| 645 | } |
| 646 | |
| 647 | int |
| 648 | amd64_set_ldt(struct thread *td, struct i386_ldt_args *uap, |
| 649 | struct user_segment_descriptor *descs) |
| 650 | { |
| 651 | struct mdproc *mdp; |
| 652 | struct proc_ldt *pldt; |
| 653 | struct user_segment_descriptor *dp; |
| 654 | struct proc *p; |
| 655 | u_int largest_ld, i; |
| 656 | int error; |
| 657 | |
| 658 | #ifdef DEBUG |
| 659 | printf("amd64_set_ldt: start=%u num=%u descs=%p\n", |
| 660 | uap->start, uap->num, (void *)uap->descs); |
| 661 | #endif |
| 662 | mdp = &td->td_proc->p_md; |
| 663 | error = 0; |
| 664 | |
| 665 | set_pcb_flags(td->td_pcb, PCB_FULL_IRET); |
| 666 | p = td->td_proc; |
| 667 | if (descs == NULL) { |
| 668 | /* Free descriptors */ |
| 669 | if (uap->start == 0 && uap->num == 0) |
| 670 | uap->num = max_ldt_segment; |
| 671 | if (uap->num == 0) |
| 672 | return (EINVAL); |
| 673 | if ((pldt = mdp->md_ldt) == NULL || |
| 674 | uap->start >= max_ldt_segment) |
| 675 | return (0); |
| 676 | largest_ld = uap->start + uap->num; |
| 677 | if (largest_ld > max_ldt_segment) |
| 678 | largest_ld = max_ldt_segment; |
| 679 | if (largest_ld < uap->start) |
| 680 | return (EINVAL); |
| 681 | mtx_lock(&dt_lock); |
| 682 | for (i = uap->start; i < largest_ld; i++) |
| 683 | ((volatile uint64_t *)(pldt->ldt_base))[i] = 0; |
| 684 | mtx_unlock(&dt_lock); |
| 685 | return (0); |
| 686 | } |
| 687 | |
| 688 | if (!(uap->start == LDT_AUTO_ALLOC && uap->num == 1)) { |
| 689 | /* verify range of descriptors to modify */ |
| 690 | largest_ld = uap->start + uap->num; |
| 691 | if (uap->start >= max_ldt_segment || |
| 692 | largest_ld > max_ldt_segment || |
| 693 | largest_ld < uap->start) |
| 694 | return (EINVAL); |
| 695 | } |
| 696 | |
| 697 | /* Check descriptors for access violations */ |
| 698 | for (i = 0; i < uap->num; i++) { |
| 699 | dp = &descs[i]; |
| 700 | |
| 701 | switch (dp->sd_type) { |
| 702 | case SDT_SYSNULL: /* system null */ |
| 703 | dp->sd_p = 0; |
| 704 | break; |
no test coverage detected