+ return ENOMEM;
+ }
+
+ new_ldt->start = begin_sel;
+ new_ldt->count = ldt_count;
+
+ /*
+ * Have new LDT. If there was a an old ldt, copy descriptors
+ * from old to new.
+ */
+ if (old_ldt) {
+ bcopy(&old_ldt->ldt[0],
+ &new_ldt->ldt[old_ldt->start - begin_sel],
+ old_ldt->count * sizeof(struct real_descriptor));
+
+ /*
+ * If the old and new LDTs are non-overlapping, fill the
+ * center in with null selectors.
+ */
+
+ if (old_ldt->start + old_ldt->count < start_sel) {
+ bzero(&new_ldt->ldt[old_ldt->count],
+ (start_sel - (old_ldt->start + old_ldt->count)) * sizeof(struct real_descriptor));
+ } else if (old_ldt->start > start_sel + num_sels) {
+ bzero(&new_ldt->ldt[num_sels],
+ (old_ldt->start - (start_sel + num_sels)) * sizeof(struct real_descriptor));
+ }
+ }
+
+ /*
+ * Install new descriptors.
+ */
+ if (descs != 0) {
+ /* XXX copyin under task lock */
+ err = copyin(descs, (char *)&new_ldt->ldt[start_sel - begin_sel],
+ num_sels * sizeof(struct real_descriptor));
+ if (err != 0) {
+ task_unlock(task);
+ user_ldt_free(new_ldt);
+ return err;
+ }
+ } else {
+ bzero(&new_ldt->ldt[start_sel - begin_sel], num_sels * sizeof(struct real_descriptor));
+ }
+ /*
+ * Validate descriptors.
+ * Only allow descriptors with user privileges.
+ */
+ for (i = 0, dp = (struct real_descriptor *) &new_ldt->ldt[start_sel - begin_sel];
+ i < num_sels;
+ i++, dp++) {
+ switch (dp->access & ~ACC_A) {
+ case 0:
+ case ACC_P:
+ /* valid empty descriptor, clear Present preemptively */
+ dp->access &= (~ACC_P & 0xff);
+ break;
+ case ACC_P | ACC_PL_U | ACC_DATA:
+ case ACC_P | ACC_PL_U | ACC_DATA_W:
+ case ACC_P | ACC_PL_U | ACC_DATA_E:
+ case ACC_P | ACC_PL_U | ACC_DATA_EW:
+ case ACC_P | ACC_PL_U | ACC_CODE:
+ case ACC_P | ACC_PL_U | ACC_CODE_R:
+ case ACC_P | ACC_PL_U | ACC_CODE_C:
+ case ACC_P | ACC_PL_U | ACC_CODE_CR:
+ break;
+ default:
+ task_unlock(task);
+ user_ldt_free(new_ldt);
+ return EACCES;
+ }
+ /* Reject attempts to create segments with 64-bit granules */
+ /* Note this restriction is still correct, even when
+ * executing as a 64-bit process (we want to maintain a single
+ * 64-bit selector (located in the GDT)).
+ */
+ if (dp->granularity & SZ_64) {
+ task_unlock(task);
+ user_ldt_free(new_ldt);
+ return EACCES;
+ }