diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index 99d6716..27439d3 100644 --- a/sys/amd64/amd64/cpu_switch.S +++ b/sys/amd64/amd64/cpu_switch.S @@ -75,8 +75,6 @@ ENTRY(cpu_throw) 1: movq TD_PCB(%rdi),%r8 /* Old pcb */ movl PCPU(CPUID), %eax - movq PCB_FSBASE(%r8),%r9 - movq PCB_GSBASE(%r8),%r10 /* release bit from old pm_active */ movq TD_PROC(%rdi), %rdx /* oldtd->td_proc */ movq P_VMSPACE(%rdx), %rdx /* proc->p_vmspace */ @@ -110,28 +108,6 @@ ENTRY(cpu_switch) movq %rbx,PCB_RBX(%r8) movq %rax,PCB_RIP(%r8) - /* - * Reread fs and gs bases. Explicit fs segment register load - * by the usermode code may change actual fs base without - * updating pcb_{fs,gs}base. - * - * %rdx still contains the mtx, save %rdx around rdmsr. - */ - movq %rdx,%r11 - movl $MSR_FSBASE,%ecx - rdmsr - shlq $32,%rdx - leaq (%rax,%rdx),%r9 - movl $MSR_KGSBASE,%ecx - rdmsr - shlq $32,%rdx - leaq (%rax,%rdx),%r10 - movq %r11,%rdx - - testl $PCB_32BIT,PCB_FLAGS(%r8) - jnz store_seg -done_store_seg: - testl $PCB_DBREGS,PCB_FLAGS(%r8) jnz store_dr /* static predict not taken */ done_store_dr: @@ -192,35 +168,66 @@ sw1: testl $TDP_KTHREAD,TD_PFLAGS(%rsi) jnz do_kthread - testl $PCB_32BIT,PCB_FLAGS(%r8) - jnz load_seg -done_load_seg: - - cmpq PCB_FSBASE(%r8),%r9 - jz 1f - /* Restore userland %fs */ - movl $MSR_FSBASE,%ecx + /* + * Load ldt register + */ + movq TD_PROC(%rsi),%rcx + cmpq $0, P_MD+MD_LDT(%rcx) + je 1f + movq PCPU(LDT),%rax + movq P_MD+MD_LDT_SD(%rcx),%rdx + movq %rdx,(%rax) + movq P_MD+MD_LDT_SD+8(%rcx),%rdx + movq %rdx,8(%rax) + movl $LDTSEL,%eax + jmp 2f +1: xorl %eax,%eax +2: lldt %ax + + /* Restore fs base in GDT */ movl PCB_FSBASE(%r8),%eax - movl PCB_FSBASE+4(%r8),%edx - wrmsr -1: - cmpq PCB_GSBASE(%r8),%r10 - jz 2f - /* Restore userland %gs */ - movl $MSR_KGSBASE,%ecx + movq PCPU(FS32P),%rdx + movw %ax,2(%rdx) + shrl $16,%eax + movb %al,4(%rdx) + shrl $8,%eax + movb %al,7(%rdx) + + /* Restore gs base in GDT */ movl PCB_GSBASE(%r8),%eax - movl PCB_GSBASE+4(%r8),%edx - wrmsr -2: + movq PCPU(GS32P),%rdx + movw %ax,2(%rdx) + shrl $16,%eax + movb %al,4(%rdx) + shrl $8,%eax + movb %al,7(%rdx) -do_tss: +do_kthread: +do_tss: movq PCPU(TSSP),%rax + movq PCB_TSSP(%r8),%rdx + testq %rdx,%rdx + jnz 1f + movq PCPU(COMMONTSSP),%rdx +1: cmpq %rax,%rdx + jz 2f + movq %rdx,PCPU(TSSP) + movq %rdx,%rcx + movq PCPU(TSS),%rax + movw %rcx,2(%rax) + shrq $16,%rcx + movb %cl,4(%rax) + shrq $8,%rcx + movb %cl,7(%rax) + shrq $8,%rcx + movl %ecx,8(%rax) + movb $0x89,5(%rax) /* unset busy */ + movl $TSSSEL,%eax + ltr %ax /* Update the TSS_RSP0 pointer for the next interrupt */ - movq PCPU(TSSP), %rax - movq %r8, PCPU(RSP0) +2: movq %r8, PCPU(RSP0) movq %r8, PCPU(CURPCB) - addq $COMMON_TSS_RSP0, %rax movq %rsi, PCPU(CURTHREAD) /* into next thread */ - movq %r8, (%rax) + movq %r8, COMMON_TSS_RSP0(%rdx) /* Test if debug registers should be restored. */ testl $PCB_DBREGS,PCB_FLAGS(%r8) @@ -249,45 +256,6 @@ done_load_dr: * We use jumps rather than call in order to avoid the stack. */ -do_kthread: - /* - * Copy old fs/gsbase to new kthread pcb for future switches - * This maintains curpcb->pcb_[fg]sbase as caches of the MSR - */ - movq %r9,PCB_FSBASE(%r8) - movq %r10,PCB_GSBASE(%r8) - jmp do_tss - -store_seg: - movl %gs,PCB_GS(%r8) - testl $PCB_GS32BIT,PCB_FLAGS(%r8) - jnz 2f -1: movl %ds,PCB_DS(%r8) - movl %es,PCB_ES(%r8) - movl %fs,PCB_FS(%r8) - jmp done_store_seg -2: movq PCPU(GS32P),%rax - movq (%rax),%rax - movq %rax,PCB_GS32SD(%r8) - jmp 1b - -load_seg: - testl $PCB_GS32BIT,PCB_FLAGS(%r8) - jnz 2f -1: movl $MSR_GSBASE,%ecx - rdmsr - movl PCB_GS(%r8),%gs - wrmsr - movl PCB_DS(%r8),%ds - movl PCB_ES(%r8),%es - movl PCB_FS(%r8),%fs - jmp done_load_seg - /* Restore userland %gs while preserving kernel gsbase */ -2: movq PCPU(GS32P),%rax - movq PCB_GS32SD(%r8),%rcx - movq %rcx,(%rax) - jmp 1b - store_dr: movq %dr7,%rax /* yes, do the save */ movq %dr0,%r15 diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c index b297616..287c236 100644 --- a/sys/amd64/amd64/db_interface.c +++ b/sys/amd64/amd64/db_interface.c @@ -139,7 +139,11 @@ void db_show_mdpcpu(struct pcpu *pc) { -#if 0 - db_printf("currentldt = 0x%x\n", pc->pc_currentldt); -#endif + db_printf("curpmap = %p\n", pc->pc_curpmap); + db_printf("tssp = %p\n", pc->pc_tssp); + db_printf("commontssp = %p\n", pc->pc_commontssp); + db_printf("rsp0 = 0x%lx\n", pc->pc_rsp0); + db_printf("gs32p = %p\n", pc->pc_gs32p); + db_printf("ldt = %p\n", pc->pc_ldt); + db_printf("tss = %p\n", pc->pc_tss); } diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c index c4e552d..6789d04 100644 --- a/sys/amd64/amd64/db_trace.c +++ b/sys/amd64/amd64/db_trace.c @@ -67,12 +67,10 @@ static db_varfcn_t db_ss; #define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) struct db_variable db_regs[] = { { "cs", DB_OFFSET(tf_cs), db_frame }, -#if 0 { "ds", DB_OFFSET(tf_ds), db_frame }, { "es", DB_OFFSET(tf_es), db_frame }, { "fs", DB_OFFSET(tf_fs), db_frame }, { "gs", DB_OFFSET(tf_gs), db_frame }, -#endif { "ss", NULL, db_ss }, { "rax", DB_OFFSET(tf_rax), db_frame }, { "rcx", DB_OFFSET(tf_rcx), db_frame }, @@ -92,7 +90,7 @@ struct db_variable db_regs[] = { { "r15", DB_OFFSET(tf_r15), db_frame }, { "rip", DB_OFFSET(tf_rip), db_frame }, { "rflags", DB_OFFSET(tf_rflags), db_frame }, -#define DB_N_SHOW_REGS 20 /* Don't show registers after here. */ +#define DB_N_SHOW_REGS 24 /* Don't show registers after here. */ { "dr0", NULL, db_dr0 }, { "dr1", NULL, db_dr1 }, { "dr2", NULL, db_dr2 }, diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S index fd0a7ca..9ce2458 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -42,6 +42,7 @@ #include #include #include +#include #include "assym.s" @@ -185,6 +186,10 @@ alltraps_pushregs_no_rdi: movq %r13,TF_R13(%rsp) movq %r14,TF_R14(%rsp) movq %r15,TF_R15(%rsp) + movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) FAKE_MCOUNT(TF_RIP(%rsp)) #ifdef KDTRACE_HOOKS /* @@ -252,6 +257,10 @@ IDTVEC(dblfault) movq %r13,TF_R13(%rsp) movq %r14,TF_R14(%rsp) movq %r15,TF_R15(%rsp) + movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ jz 1f /* already running with kernel GS.base */ swapgs @@ -288,13 +297,23 @@ IDTVEC(prot) movq %rdi,TF_RDI(%rsp) /* free up a GP register */ leaq doreti_iret(%rip),%rdi cmpq %rdi,TF_RIP(%rsp) - je 2f /* kernel but with user gsbase!! */ + je 1f /* kernel but with user gsbase!! */ + leaq ld_gs(%rip),%rdi + cmpq %rdi,TF_RIP(%rsp) + je 1f + leaq ld_fs(%rip),%rdi + cmpq %rdi,TF_RIP(%rsp) + je 1f + leaq ld_es(%rip),%rdi + cmpq %rdi,TF_RIP(%rsp) + je 1f + leaq ld_ds(%rip),%rdi + cmpq %rdi,TF_RIP(%rsp) + je 1f testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ - jz 1f /* already running with kernel GS.base */ -2: - swapgs -1: - testl $PSL_I,TF_RFLAGS(%rsp) + jz 2f /* already running with kernel GS.base */ +1: swapgs +2: testl $PSL_I,TF_RFLAGS(%rsp) jz alltraps_pushregs_no_rdi sti jmp alltraps_pushregs_no_rdi @@ -333,40 +352,14 @@ IDTVEC(fast_syscall) movq %r13,TF_R13(%rsp) /* C preserved */ movq %r14,TF_R14(%rsp) /* C preserved */ movq %r15,TF_R15(%rsp) /* C preserved */ + movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) FAKE_MCOUNT(TF_RIP(%rsp)) movq %rsp, %rdi call syscall movq PCPU(CURPCB),%rax - testq $PCB_FULLCTX,PCB_FLAGS(%rax) - jne 3f -1: /* Check for and handle AST's on return to userland */ - cli - movq PCPU(CURTHREAD),%rax - testl $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%rax) - je 2f - sti - movq %rsp, %rdi - call ast - jmp 1b -2: /* restore preserved registers */ - MEXITCOUNT - movq TF_RDI(%rsp),%rdi /* bonus; preserve arg 1 */ - movq TF_RSI(%rsp),%rsi /* bonus: preserve arg 2 */ - movq TF_RDX(%rsp),%rdx /* return value 2 */ - movq TF_RAX(%rsp),%rax /* return value 1 */ - movq TF_RBX(%rsp),%rbx /* C preserved */ - movq TF_RBP(%rsp),%rbp /* C preserved */ - movq TF_R12(%rsp),%r12 /* C preserved */ - movq TF_R13(%rsp),%r13 /* C preserved */ - movq TF_R14(%rsp),%r14 /* C preserved */ - movq TF_R15(%rsp),%r15 /* C preserved */ - movq TF_RFLAGS(%rsp),%r11 /* original %rflags */ - movq TF_RIP(%rsp),%rcx /* original %rip */ - movq TF_RSP(%rsp),%r9 /* user stack pointer */ - movq %r9,%rsp /* original %rsp */ - swapgs - sysretq -3: /* Requested full context restore, use doreti for that */ andq $~PCB_FULLCTX,PCB_FLAGS(%rax) MEXITCOUNT jmp doreti @@ -421,6 +414,10 @@ IDTVEC(nmi) movq %r13,TF_R13(%rsp) movq %r14,TF_R14(%rsp) movq %r15,TF_R15(%rsp) + movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) xorl %ebx,%ebx testb $SEL_RPL_MASK,TF_CS(%rsp) jnz nmi_needswapgs /* we came from userland */ @@ -601,6 +598,40 @@ doreti_ast: */ doreti_exit: MEXITCOUNT + movq PCPU(CURTHREAD),%r8 + movq TD_PCB(%r8),%r8 + + /* Restore %fs and fsbase */ + movl TF_FS(%rsp),%eax + .globl ld_fs +ld_fs: movl %eax,%fs + cmpw $KUF32SEL,%ax + jne 1f + movl $MSR_FSBASE,%ecx + movl PCB_FSBASE(%r8),%eax + movl PCB_FSBASE+4(%r8),%edx + wrmsr +1: + /* Restore %gs and gsbase */ + movl TF_GS(%rsp),%esi + pushfq + cli + movl $MSR_GSBASE,%ecx + rdmsr + .globl ld_gs +ld_gs: movl %esi,%gs + wrmsr + popfq + cmpw $KUG32SEL,%si + jne 1f + movl $MSR_KGSBASE,%ecx + movl PCB_GSBASE(%r8),%eax + movl PCB_GSBASE+4(%r8),%edx + wrmsr +1: .globl ld_es +ld_es: movl TF_ES(%rsp),%es + .globl ld_ds +ld_ds: movl TF_DS(%rsp),%ds movq TF_RDI(%rsp),%rdi movq TF_RSI(%rsp),%rsi movq TF_RDX(%rsp),%rdx @@ -639,7 +670,11 @@ doreti_iret_fault: testl $PSL_I,TF_RFLAGS(%rsp) jz 1f sti -1: movq %rdi,TF_RDI(%rsp) +1: movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) + movq %rdi,TF_RDI(%rsp) movq %rsi,TF_RSI(%rsp) movq %rdx,TF_RDX(%rsp) movq %rcx,TF_RCX(%rsp) @@ -659,6 +694,40 @@ doreti_iret_fault: movq $0,TF_ADDR(%rsp) FAKE_MCOUNT(TF_RIP(%rsp)) jmp calltrap + + ALIGN_TEXT + .globl ds_load_fault +ds_load_fault: + movq $T_PROTFLT,TF_TRAPNO(%rsp) + movl TF_DS(%rsp),%edx + movl %edx,TF_ERR(%rsp) + movl $KUDSEL,TF_FS(%rsp) + jmp calltrap + + ALIGN_TEXT + .globl es_load_fault +es_load_fault: + movl TF_ES(%rsp),%edx + movl %edx,TF_ERR(%rsp) + movl $KUDSEL,TF_FS(%rsp) + jmp calltrap + + ALIGN_TEXT + .globl fs_load_fault +fs_load_fault: + movl TF_FS(%rsp),%edx + movl %edx,TF_ERR(%rsp) + movl $KUF32SEL,TF_FS(%rsp) + jmp calltrap + + ALIGN_TEXT + .globl gs_load_fault +gs_load_fault: + popfq + movl TF_GS(%rsp),%edx + movl %edx,TF_ERR(%rsp) + movl $KUG32SEL,TF_FS(%rsp) + jmp calltrap #ifdef HWPMC_HOOKS ENTRY(end_exceptions) #endif diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index f749dd6..1c4415e 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -75,6 +75,10 @@ ASSYM(P_VMSPACE, offsetof(struct proc, p_vmspace)); ASSYM(VM_PMAP, offsetof(struct vmspace, vm_pmap)); ASSYM(PM_ACTIVE, offsetof(struct pmap, pm_active)); +ASSYM(P_MD, offsetof(struct proc, p_md)); +ASSYM(MD_LDT, offsetof(struct mdproc, md_ldt)); +ASSYM(MD_LDT_SD, offsetof(struct mdproc, md_ldt_sd)); + ASSYM(TD_LOCK, offsetof(struct thread, td_lock)); ASSYM(TD_FLAGS, offsetof(struct thread, td_flags)); ASSYM(TD_PCB, offsetof(struct thread, td_pcb)); @@ -128,16 +132,13 @@ ASSYM(PCB_RBX, offsetof(struct pcb, pcb_rbx)); ASSYM(PCB_RIP, offsetof(struct pcb, pcb_rip)); ASSYM(PCB_FSBASE, offsetof(struct pcb, pcb_fsbase)); ASSYM(PCB_GSBASE, offsetof(struct pcb, pcb_gsbase)); -ASSYM(PCB_DS, offsetof(struct pcb, pcb_ds)); -ASSYM(PCB_ES, offsetof(struct pcb, pcb_es)); -ASSYM(PCB_FS, offsetof(struct pcb, pcb_fs)); -ASSYM(PCB_GS, offsetof(struct pcb, pcb_gs)); ASSYM(PCB_DR0, offsetof(struct pcb, pcb_dr0)); ASSYM(PCB_DR1, offsetof(struct pcb, pcb_dr1)); ASSYM(PCB_DR2, offsetof(struct pcb, pcb_dr2)); ASSYM(PCB_DR3, offsetof(struct pcb, pcb_dr3)); ASSYM(PCB_DR6, offsetof(struct pcb, pcb_dr6)); ASSYM(PCB_DR7, offsetof(struct pcb, pcb_dr7)); +ASSYM(PCB_TSSP, offsetof(struct pcb, pcb_tssp)); ASSYM(PCB_DBREGS, PCB_DBREGS); ASSYM(PCB_32BIT, PCB_32BIT); ASSYM(PCB_GS32BIT, PCB_GS32BIT); @@ -176,6 +177,10 @@ ASSYM(TF_CS, offsetof(struct trapframe, tf_cs)); ASSYM(TF_RFLAGS, offsetof(struct trapframe, tf_rflags)); ASSYM(TF_RSP, offsetof(struct trapframe, tf_rsp)); ASSYM(TF_SS, offsetof(struct trapframe, tf_ss)); +ASSYM(TF_DS, offsetof(struct trapframe, tf_ds)); +ASSYM(TF_ES, offsetof(struct trapframe, tf_es)); +ASSYM(TF_FS, offsetof(struct trapframe, tf_fs)); +ASSYM(TF_GS, offsetof(struct trapframe, tf_gs)); ASSYM(TF_SIZE, sizeof(struct trapframe)); ASSYM(SIGF_HANDLER, offsetof(struct sigframe, sf_ahu.sf_handler)); @@ -198,7 +203,11 @@ ASSYM(PC_SCRATCH_RSP, offsetof(struct pcpu, pc_scratch_rsp)); ASSYM(PC_CURPMAP, offsetof(struct pcpu, pc_curpmap)); ASSYM(PC_TSSP, offsetof(struct pcpu, pc_tssp)); ASSYM(PC_RSP0, offsetof(struct pcpu, pc_rsp0)); +ASSYM(PC_FS32P, offsetof(struct pcpu, pc_fs32p)); ASSYM(PC_GS32P, offsetof(struct pcpu, pc_gs32p)); +ASSYM(PC_LDT, offsetof(struct pcpu, pc_ldt)); +ASSYM(PC_COMMONTSSP, offsetof(struct pcpu, pc_commontssp)); +ASSYM(PC_TSS, offsetof(struct pcpu, pc_tss)); ASSYM(LA_VER, offsetof(struct LAPIC, version)); ASSYM(LA_TPR, offsetof(struct LAPIC, tpr)); @@ -213,6 +222,10 @@ ASSYM(KDSEL, GSEL(GDATA_SEL, SEL_KPL)); ASSYM(KUCSEL, GSEL(GUCODE_SEL, SEL_UPL)); ASSYM(KUDSEL, GSEL(GUDATA_SEL, SEL_UPL)); ASSYM(KUC32SEL, GSEL(GUCODE32_SEL, SEL_UPL)); +ASSYM(KUF32SEL, GSEL(GUFS32_SEL, SEL_UPL)); +ASSYM(KUG32SEL, GSEL(GUGS32_SEL, SEL_UPL)); +ASSYM(TSSSEL, GSEL(GPROC0_SEL, SEL_KPL)); +ASSYM(LDTSEL, GSEL(GUSERLDT_SEL, SEL_KPL)); ASSYM(SEL_RPL_MASK, SEL_RPL_MASK); ASSYM(MSR_GSBASE, MSR_GSBASE); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 988b039..83b9323 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -149,6 +149,7 @@ extern void panicifcpuunsupported(void); static void cpu_startup(void *); static void get_fpcontext(struct thread *td, mcontext_t *mcp); static int set_fpcontext(struct thread *td, const mcontext_t *mcp); +static int set_fpcontext7(struct thread *td, const struct __mcontext7 *mcp); SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); #ifdef DDB @@ -192,6 +193,8 @@ struct mtx icu_lock; struct mem_range_softc mem_range_softc; +struct mtx dt_lock; /* lock for GDT and LDT */ + static void cpu_startup(dummy) void *dummy; @@ -263,11 +266,150 @@ cpu_startup(dummy) cpu_setregs(); } +static void +sf2sf7(const struct sigframe *sf, struct sigframe7 *sf7) +{ + + bzero(sf7, sizeof(sf7)); + bcopy(&sf->sf_ahu, &sf7->sf_ahu, sizeof(sf->sf_ahu)); + bcopy(&sf->sf_si, &sf7->sf_si, sizeof(sf->sf_si)); + sf7->sf_uc.uc_sigmask = sf->sf_uc.uc_sigmask; + sf7->sf_uc.uc_stack = sf->sf_uc.uc_stack; + sf7->sf_uc.uc_stack.ss_flags = sf->sf_uc.uc_stack.ss_flags; + sf7->sf_uc.uc_mcontext.mc_onstack = sf->sf_uc.uc_mcontext.mc_onstack; + sf7->sf_uc.uc_mcontext.mc_rdi = sf->sf_uc.uc_mcontext.mc_rdi; + sf7->sf_uc.uc_mcontext.mc_rsi = sf->sf_uc.uc_mcontext.mc_rsi; + sf7->sf_uc.uc_mcontext.mc_rdx = sf->sf_uc.uc_mcontext.mc_rdx; + sf7->sf_uc.uc_mcontext.mc_rcx = sf->sf_uc.uc_mcontext.mc_rcx; + sf7->sf_uc.uc_mcontext.mc_r8 = sf->sf_uc.uc_mcontext.mc_r8; + sf7->sf_uc.uc_mcontext.mc_r9 = sf->sf_uc.uc_mcontext.mc_r9; + sf7->sf_uc.uc_mcontext.mc_rax = sf->sf_uc.uc_mcontext.mc_rax; + sf7->sf_uc.uc_mcontext.mc_rbx = sf->sf_uc.uc_mcontext.mc_rbx; + sf7->sf_uc.uc_mcontext.mc_rbp = sf->sf_uc.uc_mcontext.mc_rbp; + sf7->sf_uc.uc_mcontext.mc_r10 = sf->sf_uc.uc_mcontext.mc_r10; + sf7->sf_uc.uc_mcontext.mc_r11 = sf->sf_uc.uc_mcontext.mc_r11; + sf7->sf_uc.uc_mcontext.mc_r12 = sf->sf_uc.uc_mcontext.mc_r12; + sf7->sf_uc.uc_mcontext.mc_r13 = sf->sf_uc.uc_mcontext.mc_r13; + sf7->sf_uc.uc_mcontext.mc_r14 = sf->sf_uc.uc_mcontext.mc_r14; + sf7->sf_uc.uc_mcontext.mc_r15 = sf->sf_uc.uc_mcontext.mc_r15; + sf7->sf_uc.uc_mcontext.mc_trapno = sf->sf_uc.uc_mcontext.mc_trapno; + sf7->sf_uc.uc_mcontext.mc_addr = sf->sf_uc.uc_mcontext.mc_addr; + sf7->sf_uc.uc_mcontext.mc_flags = sf->sf_uc.uc_mcontext.mc_flags; + sf7->sf_uc.uc_mcontext.mc_err = sf->sf_uc.uc_mcontext.mc_err; + sf7->sf_uc.uc_mcontext.mc_rip = sf->sf_uc.uc_mcontext.mc_rip; + sf7->sf_uc.uc_mcontext.mc_cs = sf->sf_uc.uc_mcontext.mc_cs; + sf7->sf_uc.uc_mcontext.mc_rflags = sf->sf_uc.uc_mcontext.mc_rflags; + sf7->sf_uc.uc_mcontext.mc_rsp = sf->sf_uc.uc_mcontext.mc_rsp; + sf7->sf_uc.uc_mcontext.mc_ss = sf->sf_uc.uc_mcontext.mc_ss; + /* magic */ + sf7->sf_uc.uc_mcontext.mc_len = sizeof(sf7->sf_uc.uc_mcontext); + sf7->sf_uc.uc_mcontext.mc_fpformat = sf->sf_uc.uc_mcontext.mc_fpformat; + sf7->sf_uc.uc_mcontext.mc_ownedfp = sf->sf_uc.uc_mcontext.mc_ownedfp; + bcopy(&sf->sf_uc.uc_mcontext.mc_fpstate[0], + &sf7->sf_uc.uc_mcontext.mc_fpstate[0], + sizeof(&sf7->sf_uc.uc_mcontext.mc_fpstate)); +} + +static void +sendsig_freebsd7(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) +{ + struct sigframe sf; + struct sigframe7 sf7, *sfp7; + struct proc *p; + struct thread *td; + struct sigacts *psp; + char *sp; + struct trapframe *regs; + int sig, oonstack, error; + + td = curthread; + p = td->td_proc; + PROC_LOCK_ASSERT(p, MA_OWNED); + sig = ksi->ksi_signo; + psp = p->p_sigacts; + mtx_assert(&psp->ps_mtx, MA_OWNED); + regs = td->td_frame; + oonstack = sigonstack(regs->tf_rsp); + + /* Save user context. */ + bzero(&sf, sizeof(sf)); + sf.sf_uc.uc_sigmask = *mask; + sf.sf_uc.uc_stack = td->td_sigstk; + sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) + ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; + sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; + bcopy(regs, &sf.sf_uc.uc_mcontext.mc_rdi, sizeof(*regs)); + sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */ + get_fpcontext(td, &sf.sf_uc.uc_mcontext); + fpstate_drop(td); + sf2sf7(&sf, &sf7); + + /* Allocate space for the signal handler context. */ + if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sp = td->td_sigstk.ss_sp + + td->td_sigstk.ss_size - sizeof(struct sigframe7); +#if defined(COMPAT_43) + td->td_sigstk.ss_flags |= SS_ONSTACK; +#endif + } else + sp = (char *)regs->tf_rsp - sizeof(struct sigframe7) - 128; + /* Align to 16 bytes. */ + sfp7 = (struct sigframe7 *)((unsigned long)sp & ~0xFul); + + /* Translate the signal if appropriate. */ + if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; + + /* Build the argument list for the signal handler. */ + regs->tf_rdi = sig; /* arg 1 in %rdi */ + regs->tf_rdx = (register_t)&sfp7->sf_uc; /* arg 3 in %rdx */ + if (SIGISMEMBER(psp->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ + regs->tf_rsi = (register_t)&sfp7->sf_si;/* arg 2 in %rsi */ + sf7.sf_ahu.sf_action = (__siginfohandler_t *)catcher; + /* Fill in POSIX parts */ + sf7.sf_si = ksi->ksi_info; + sf7.sf_si.si_signo = sig; /* maybe a translated signal */ + regs->tf_rcx = (register_t)ksi->ksi_addr; /* arg 4 in %rcx */ + } else { + /* Old FreeBSD-style arguments. */ + regs->tf_rsi = ksi->ksi_code; /* arg 2 in %rsi */ + regs->tf_rcx = (register_t)ksi->ksi_addr; /* arg 4 in %rcx */ + sf7.sf_ahu.sf_handler = catcher; + } + mtx_unlock(&psp->ps_mtx); + PROC_UNLOCK(p); + + /* + * Copy the sigframe out to the user's stack. + */ + error = copyout(&sf7, sfp7, sizeof(struct sigframe7)); + if (error != 0) { +#ifdef DEBUG + printf("process %ld has trashed its stack\n", (long)p->p_pid); +#endif + PROC_LOCK(p); + sigexit(td, SIGILL); + } + + regs->tf_rsp = (long)sfp7; + regs->tf_rip = PS_STRINGS - szsigcode7; + regs->tf_rflags &= ~(PSL_T | PSL_D); + regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); + PROC_LOCK(p); + mtx_lock(&psp->ps_mtx); +} + /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored - * at top to call routine, followed by kcall + * at top to call routine, followed by call * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user @@ -282,8 +424,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) struct sigacts *psp; char *sp; struct trapframe *regs; - int sig; - int oonstack; + int sig, oonstack, error; td = curthread; p = td->td_proc; @@ -291,6 +432,8 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) sig = ksi->ksi_signo; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); + if (SIGISMEMBER(psp->ps_freebsd7, sig)) + sendsig_freebsd7(catcher, ksi, mask); regs = td->td_frame; oonstack = sigonstack(regs->tf_rsp); @@ -299,7 +442,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = td->td_sigstk; sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) - ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; + ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; bcopy(regs, &sf.sf_uc.uc_mcontext.mc_rdi, sizeof(*regs)); sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */ @@ -310,7 +453,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sp = td->td_sigstk.ss_sp + - td->td_sigstk.ss_size - sizeof(struct sigframe); + td->td_sigstk.ss_size - sizeof(struct sigframe); #if defined(COMPAT_43) td->td_sigstk.ss_flags |= SS_ONSTACK; #endif @@ -325,12 +468,11 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) /* Build the argument list for the signal handler. */ regs->tf_rdi = sig; /* arg 1 in %rdi */ - regs->tf_rdx = (register_t)&sfp->sf_uc; /* arg 3 in %rdx */ + regs->tf_rdx = (register_t)&sfp->sf_uc; if (SIGISMEMBER(psp->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ regs->tf_rsi = (register_t)&sfp->sf_si; /* arg 2 in %rsi */ sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; - /* Fill in POSIX parts */ sf.sf_si = ksi->ksi_info; sf.sf_si.si_signo = sig; /* maybe a translated signal */ @@ -347,7 +489,8 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) /* * Copy the sigframe out to the user's stack. */ - if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { + error = copyout(&sf, sfp, sizeof(struct sigframe)); + if (error != 0) { #ifdef DEBUG printf("process %ld has trashed its stack\n", (long)p->p_pid); #endif @@ -359,6 +502,10 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) regs->tf_rip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); } @@ -434,7 +581,7 @@ sigreturn(td, uap) if (ret != 0) return (ret); bcopy(&ucp->uc_mcontext.mc_rdi, regs, sizeof(*regs)); - + PROC_LOCK(p); #if defined(COMPAT_43) if (ucp->uc_mcontext.mc_onstack & 1) @@ -451,6 +598,113 @@ sigreturn(td, uap) return (EJUSTRETURN); } +#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD6) || \ + defined(COMPAT_FREEBSD7) +int +osigreturn_freebsd7(td, uap) + struct thread *td; + struct osigreturn_freebsd7_args /* { + const struct ucontext7 *sigcntxp; + } */ *uap; +{ + struct ucontext7 uc7; + struct proc *p = td->td_proc; + struct trapframe *regs; + const struct ucontext7 *ucp7; + long rflags; + int cs, error, ret; + ksiginfo_t ksi; + + error = copyin(uap->sigcntxp, &uc7, sizeof(uc7)); + if (error != 0) + return (error); + ucp7 = &uc7; + regs = td->td_frame; + rflags = ucp7->uc_mcontext.mc_rflags; + /* + * Don't allow users to change privileged or reserved flags. + */ + /* + * XXX do allow users to change the privileged flag PSL_RF. + * The cpu sets PSL_RF in tf_rflags for faults. Debuggers + * should sometimes set it there too. tf_rflags is kept in + * the signal context during signal handling and there is no + * other place to remember it, so the PSL_RF bit may be + * corrupted by the signal handler without us knowing. + * Corruption of the PSL_RF bit at worst causes one more or + * one less debugger trap, so allowing it is fairly harmless. + */ + if (!EFL_SECURE(rflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) { + printf("sigreturn: rflags = 0x%lx\n", rflags); + return (EINVAL); + } + + /* + * Don't allow users to load a valid privileged %cs. Let the + * hardware check for invalid selectors, excess privilege in + * other selectors, invalid %eip's and invalid %esp's. + */ + cs = ucp7->uc_mcontext.mc_cs; + if (!CS_SECURE(cs)) { + printf("sigreturn: cs = 0x%x\n", cs); + ksiginfo_init_trap(&ksi); + ksi.ksi_signo = SIGBUS; + ksi.ksi_code = BUS_OBJERR; + ksi.ksi_trapno = T_PROTFLT; + ksi.ksi_addr = (void *)regs->tf_rip; + trapsignal(td, &ksi); + return (EINVAL); + } + + ret = set_fpcontext7(td, &ucp7->uc_mcontext); + if (ret != 0) + return (ret); + regs->tf_rdi = ucp7->uc_mcontext.mc_rdi; + regs->tf_rsi = ucp7->uc_mcontext.mc_rsi; + regs->tf_rdx = ucp7->uc_mcontext.mc_rdx; + regs->tf_rcx = ucp7->uc_mcontext.mc_rcx; + regs->tf_r8 = ucp7->uc_mcontext.mc_r8; + regs->tf_r9 = ucp7->uc_mcontext.mc_r9; + regs->tf_rax = ucp7->uc_mcontext.mc_rax; + regs->tf_rbx = ucp7->uc_mcontext.mc_rbx; + regs->tf_rbp = ucp7->uc_mcontext.mc_rbp; + regs->tf_r10 = ucp7->uc_mcontext.mc_r10; + regs->tf_r11 = ucp7->uc_mcontext.mc_r11; + regs->tf_r12 = ucp7->uc_mcontext.mc_r12; + regs->tf_r13 = ucp7->uc_mcontext.mc_r13; + regs->tf_r14 = ucp7->uc_mcontext.mc_r14; + regs->tf_r15 = ucp7->uc_mcontext.mc_r15; + regs->tf_trapno = ucp7->uc_mcontext.mc_trapno; + regs->tf_addr = ucp7->uc_mcontext.mc_addr; + regs->tf_flags = ucp7->uc_mcontext.mc_flags; + regs->tf_err = ucp7->uc_mcontext.mc_err; + regs->tf_rip = ucp7->uc_mcontext.mc_rip; + regs->tf_cs = ucp7->uc_mcontext.mc_cs; + regs->tf_rflags = ucp7->uc_mcontext.mc_rflags; + regs->tf_rsp = ucp7->uc_mcontext.mc_rsp; + regs->tf_ss = ucp7->uc_mcontext.mc_ss; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); + + PROC_LOCK(p); +#if defined(COMPAT_43) + if (ucp7->uc_mcontext.mc_onstack & 1) + td->td_sigstk.ss_flags |= SS_ONSTACK; + else + td->td_sigstk.ss_flags &= ~SS_ONSTACK; +#endif + + td->td_sigmask = ucp7->uc_sigmask; + SIG_CANTMASK(td->td_sigmask); + signotify(td); + PROC_UNLOCK(p); + td->td_pcb->pcb_flags |= PCB_FULLCTX; + return (EJUSTRETURN); +} +#endif + #ifdef COMPAT_FREEBSD4 int freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap) @@ -727,22 +981,18 @@ exec_setregs(td, entry, stack, ps_strings) { struct trapframe *regs = td->td_frame; struct pcb *pcb = td->td_pcb; + + mtx_lock(&dt_lock); + if (td->td_proc->p_md.md_ldt != NULL) { + user_ldt_free(td); + bzero(&td->td_proc->p_md.md_ldt_sd, sizeof(struct + system_segment_descriptor)); + } else + mtx_unlock(&dt_lock); - critical_enter(); - wrmsr(MSR_FSBASE, 0); - wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ pcb->pcb_fsbase = 0; pcb->pcb_gsbase = 0; - critical_exit(); pcb->pcb_flags &= ~(PCB_32BIT | PCB_GS32BIT); - load_ds(_udatasel); - load_es(_udatasel); - load_fs(_udatasel); - load_gs(_udatasel); - pcb->pcb_ds = _udatasel; - pcb->pcb_es = _udatasel; - pcb->pcb_fs = _udatasel; - pcb->pcb_gs = _udatasel; bzero((char *)regs, sizeof(struct trapframe)); regs->tf_rip = entry; @@ -751,6 +1001,10 @@ exec_setregs(td, entry, stack, ps_strings) regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); regs->tf_ss = _udatasel; regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); /* * Reset the hardware debug registers if they were in use. @@ -814,87 +1068,114 @@ struct amd64tss common_tss[MAXCPU]; /* software prototypes -- in more palatable form */ struct soft_segment_descriptor gdt_segs[] = { /* GNULL_SEL 0 Null Descriptor */ -{ 0x0, /* segment base address */ - 0x0, /* length */ - 0, /* segment type */ - 0, /* segment descriptor priority level */ - 0, /* segment descriptor present */ - 0, /* long */ - 0, /* default 32 vs 16 bit size */ - 0 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0x0, + .ssd_type = 0, + .ssd_dpl = 0, + .ssd_p = 0, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, /* GCODE_SEL 1 Code Descriptor for kernel */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMERA, /* segment type */ - SEL_KPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 1, /* long */ - 0, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMERA, + .ssd_dpl = SEL_KPL, + .ssd_p = 1, + .ssd_long = 1, + .ssd_def32 = 0, + .ssd_gran = 1 }, /* GDATA_SEL 2 Data Descriptor for kernel */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMRWA, /* segment type */ - SEL_KPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 1, /* long */ - 0, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMRWA, + .ssd_dpl = SEL_KPL, + .ssd_p = 1, + .ssd_long = 1, + .ssd_def32 = 0, + .ssd_gran = 1 }, /* GUCODE32_SEL 3 32 bit Code Descriptor for user */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMERA, /* segment type */ - SEL_UPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 0, /* long */ - 1, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMERA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 1, + .ssd_gran = 1 }, /* GUDATA_SEL 4 32/64 bit Data Descriptor for user */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMRWA, /* segment type */ - SEL_UPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 0, /* long */ - 1, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMRWA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 1, + .ssd_gran = 1 }, /* GUCODE_SEL 5 64 bit Code Descriptor for user */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMERA, /* segment type */ - SEL_UPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 1, /* long */ - 0, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMERA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 1, + .ssd_def32 = 0, + .ssd_gran = 1 }, /* GPROC0_SEL 6 Proc 0 Tss Descriptor */ { - 0x0, /* segment base address */ - sizeof(struct amd64tss)-1,/* length */ - SDT_SYSTSS, /* segment type */ - SEL_KPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 0, /* long */ - 0, /* unused - default 32 vs 16 bit size */ - 0 /* limit granularity (byte/page units)*/ }, + .ssd_base = 0x0, + .ssd_limit = sizeof(struct amd64tss) + IOPAGES * PAGE_SIZE - 1, + .ssd_type = SDT_SYSTSS, + .ssd_dpl = SEL_KPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, /* Actually, the TSS is a system descriptor which is double size */ -{ 0x0, /* segment base address */ - 0x0, /* length */ - 0, /* segment type */ - 0, /* segment descriptor priority level */ - 0, /* segment descriptor present */ - 0, /* long */ - 0, /* default 32 vs 16 bit size */ - 0 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0x0, + .ssd_type = 0, + .ssd_dpl = 0, + .ssd_p = 0, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, /* GUGS32_SEL 8 32 bit GS Descriptor for user */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMRWA, /* segment type */ - SEL_UPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 0, /* long */ - 1, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMRWA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 1, + .ssd_gran = 1 }, +/* GUFS32_SEL 9 32 bit FS Descriptor for user */ +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMRWA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 1, + .ssd_gran = 1 }, +/* GUSERLDT_SEL 10 LDT Descriptor */ +{ .ssd_base = 0x0, + .ssd_limit = 0x0, + .ssd_type = 0, + .ssd_dpl = 0, + .ssd_p = 0, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, +/* GUSERLDT_SEL 11 LDT Descriptor, double size */ +{ .ssd_base = 0x0, + .ssd_limit = 0x0, + .ssd_type = 0, + .ssd_dpl = 0, + .ssd_p = 0, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, }; void @@ -1324,12 +1605,12 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) /* * make gdt memory segments */ - gdt_segs[GPROC0_SEL].ssd_base = (uintptr_t)&common_tss[0]; - for (x = 0; x < NGDT; x++) { - if (x != GPROC0_SEL && x != (GPROC0_SEL + 1)) + if (x != GPROC0_SEL && x != (GPROC0_SEL + 1) && + x != GUSERLDT_SEL && x != (GUSERLDT_SEL) + 1) ssdtosd(&gdt_segs[x], &gdt[x]); } + gdt_segs[GPROC0_SEL].ssd_base = (uintptr_t)&common_tss[0]; ssdtosyssd(&gdt_segs[GPROC0_SEL], (struct system_segment_descriptor *)&gdt[GPROC0_SEL]); @@ -1347,6 +1628,10 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) PCPU_SET(curthread, &thread0); PCPU_SET(curpcb, thread0.td_pcb); PCPU_SET(tssp, &common_tss[0]); + PCPU_SET(commontssp, &common_tss[0]); + PCPU_SET(tss, (struct system_segment_descriptor *)&gdt[GPROC0_SEL]); + PCPU_SET(ldt, (struct system_segment_descriptor *)&gdt[GUSERLDT_SEL]); + PCPU_SET(fs32p, &gdt[GUFS32_SEL]); PCPU_SET(gs32p, &gdt[GUGS32_SEL]); /* @@ -1359,6 +1644,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) */ mutex_init(); mtx_init(&icu_lock, "icu", NULL, MTX_SPIN | MTX_NOWITNESS); + mtx_init(&dt_lock, "descriptor tables", NULL, MTX_DEF); /* exceptions */ for (x = 0; x < NIDT; x++) @@ -1439,7 +1725,8 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) common_tss[0].tss_ist1 = (long)&dblfault_stack[sizeof(dblfault_stack)]; /* Set the IO permission bitmap (empty due to tss seg limit) */ - common_tss[0].tss_iobase = sizeof(struct amd64tss); + common_tss[0].tss_iobase = sizeof(struct amd64tss) + + IOPAGES * PAGE_SIZE; gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); ltr(gsel_tss); @@ -1470,7 +1757,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) load_ds(_udatasel); load_es(_udatasel); - load_fs(_udatasel); + load_fs(GSEL(GUFS32_SEL, SEL_UPL)); /* setup proc 0's pcb */ thread0.td_pcb->pcb_flags = 0; @@ -1820,6 +2107,33 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp) return (0); } +static int +set_fpcontext7(struct thread *td, const struct __mcontext7 *mcp) +{ + struct savefpu *fpstate; + + if (mcp->mc_fpformat == _MC_FPFMT_NODEV) + return (0); + else if (mcp->mc_fpformat != _MC_FPFMT_XMM) + return (EINVAL); + else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) + /* We don't care what state is left in the FPU or PCB. */ + fpstate_drop(td); + else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU || + mcp->mc_ownedfp == _MC_FPOWNED_PCB) { + /* + * XXX we violate the dubious requirement that fpusetregs() + * be called with interrupts disabled. + * XXX obsolete on trap-16 systems? + */ + fpstate = (struct savefpu *)&mcp->mc_fpstate; + fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; + fpusetregs(td, fpstate); + } else + return (EINVAL); + return (0); +} + void fpstate_drop(struct thread *td) { diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 2de63e3..28b73b7 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -445,17 +445,19 @@ init_secondary(void) /* Init tss */ common_tss[cpu] = common_tss[0]; common_tss[cpu].tss_rsp0 = 0; /* not used until after switch */ - common_tss[cpu].tss_iobase = sizeof(struct amd64tss); + common_tss[cpu].tss_iobase = sizeof(struct amd64tss) + + IOPAGES * PAGE_SIZE; common_tss[cpu].tss_ist1 = (long)&doublefault_stack[PAGE_SIZE]; /* Prepare private GDT */ gdt_segs[GPROC0_SEL].ssd_base = (long) &common_tss[cpu]; - ssdtosyssd(&gdt_segs[GPROC0_SEL], - (struct system_segment_descriptor *)&gdt[NGDT * cpu + GPROC0_SEL]); for (x = 0; x < NGDT; x++) { - if (x != GPROC0_SEL && x != (GPROC0_SEL + 1)) + if (x != GPROC0_SEL && x != (GPROC0_SEL + 1) && + x != GUSERLDT_SEL && x != (GUSERLDT_SEL + 1)) ssdtosd(&gdt_segs[x], &gdt[NGDT * cpu + x]); } + ssdtosyssd(&gdt_segs[GPROC0_SEL], + (struct system_segment_descriptor *)&gdt[NGDT * cpu + GPROC0_SEL]); ap_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; ap_gdt.rd_base = (long) &gdt[NGDT * cpu]; lgdt(&ap_gdt); /* does magic intra-segment return */ @@ -469,8 +471,14 @@ init_secondary(void) pc->pc_prvspace = pc; pc->pc_curthread = 0; pc->pc_tssp = &common_tss[cpu]; + pc->pc_commontssp = &common_tss[cpu]; pc->pc_rsp0 = 0; + pc->pc_tss = (struct system_segment_descriptor *)&gdt[NGDT * cpu + + GPROC0_SEL]; + pc->pc_fs32p = &gdt[NGDT * cpu + GUFS32_SEL]; pc->pc_gs32p = &gdt[NGDT * cpu + GUGS32_SEL]; + pc->pc_ldt = (struct system_segment_descriptor *)&gdt[NGDT * cpu + + GUSERLDT_SEL]; wrmsr(MSR_FSBASE, 0); /* User value */ wrmsr(MSR_GSBASE, (u_int64_t)pc); @@ -576,7 +584,7 @@ init_secondary(void) load_cr4(rcr4() | CR4_PGE); load_ds(_udatasel); load_es(_udatasel); - load_fs(_udatasel); + load_fs(GSEL(GUFS32_SEL, SEL_UPL)); mtx_unlock_spin(&ap_boot_mtx); /* wait until all the AP's are up */ diff --git a/sys/amd64/amd64/sigtramp.S b/sys/amd64/amd64/sigtramp.S index a05ea85..874ee19 100644 --- a/sys/amd64/amd64/sigtramp.S +++ b/sys/amd64/amd64/sigtramp.S @@ -47,6 +47,15 @@ NON_GPROF_ENTRY(sigcode) 0: hlt /* trap priviliged instruction */ jmp 0b +NON_GPROF_ENTRY(sigcode7) + call *SIGF_HANDLER(%rsp) /* call signal handler */ + lea SIGF_UC(%rsp),%rdi /* get ucontext_t */ + pushq $0 /* junk to fake return addr. */ + movq $SYS_sigreturn_freebsd7,%rax + syscall /* enter kernel with args */ +0: hlt /* trap priviliged instruction */ + jmp 0b + ALIGN_TEXT esigcode: @@ -54,3 +63,6 @@ esigcode: .globl szsigcode szsigcode: .long esigcode-sigcode + .globl szsigcode7 +szsigcode7: + .long esigcode-sigcode7 diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c index 7f022d0..a96b1ca 100644 --- a/sys/amd64/amd64/sys_machdep.c +++ b/sys/amd64/amd64/sys_machdep.c @@ -36,15 +36,36 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include +#include #include #include -#include -#include -#include +#include #include #include +#include /* for kernel_map */ +#include + +#include +#include +#include #include +#include + +#include + +int max_ldt_segment = 1024; +#define LD_PER_PAGE 512 +#define NULL_LDT_BASE ((caddr_t)NULL) + +#ifdef notyet +#ifdef SMP +static void set_user_ldt_rv(struct vmspace *vmsp); +#endif +#endif +static void user_ldt_derefl(struct proc_ldt *pldt); #ifndef _SYS_SYSPROTO_H_ struct sysarch_args { @@ -54,6 +75,55 @@ struct sysarch_args { #endif int +sysarch_ldt(struct thread *td, struct sysarch_args *uap, int uap_space) +{ + struct i386_ldt_args *largs, la; + struct user_segment_descriptor *lp; + int error = 0; + + /* + * XXXKIB check that the BSM generation code knows to encode + * the op argument. + */ + AUDIT_ARG(cmd, uap->op); + if (uap_space == UIO_USERSPACE) { + error = copyin(uap->parms, &la, sizeof(struct i386_ldt_args)); + if (error != 0) + return (error); + largs = &la; + } else + largs = (struct i386_ldt_args *)uap->parms; + if (largs->num > max_ldt_segment || largs->num <= 0) + return (EINVAL); + + switch(uap->op) { + case I386_GET_LDT: + error = amd64_get_ldt(td, largs); + break; + case I386_SET_LDT: + if (largs->descs != NULL) { + lp = (struct user_segment_descriptor *) + kmem_alloc(kernel_map, largs->num * + sizeof(struct user_segment_descriptor)); + if (lp == NULL) { + error = ENOMEM; + break; + } + error = copyin(largs->descs, lp, largs->num * + sizeof(struct user_segment_descriptor)); + if (error == 0) + error = amd64_set_ldt(td, largs, lp); + kmem_free(kernel_map, (vm_offset_t)lp, largs->num * + sizeof(struct user_segment_descriptor)); + } else { + error = amd64_set_ldt(td, largs, NULL); + } + break; + } + return (error); +} + +int sysarch(td, uap) struct thread *td; register struct sysarch_args *uap; @@ -62,20 +132,44 @@ sysarch(td, uap) struct pcb *pcb = curthread->td_pcb; uint32_t i386base; uint64_t a64base; + struct i386_ioperm_args iargs; + + if (uap->op == I386_GET_LDT || uap->op == I386_SET_LDT) + return (sysarch_ldt(td, uap, UIO_USERSPACE)); + /* + * XXXKIB check that the BSM generation code knows to encode + * the op argument. + */ + AUDIT_ARG(cmd, uap->op); + switch (uap->op) { + case I386_GET_IOPERM: + case I386_SET_IOPERM: + if ((error = copyin(uap->parms, &iargs, + sizeof(struct i386_ioperm_args))) != 0) + return (error); + break; + default: + break; + } switch(uap->op) { + case I386_GET_IOPERM: + error = amd64_get_ioperm(td, &iargs); + if (error == 0) + error = copyout(&iargs, uap->parms, + sizeof(struct i386_ioperm_args)); + break; + case I386_SET_IOPERM: + error = amd64_set_ioperm(td, &iargs); + break; case I386_GET_FSBASE: i386base = pcb->pcb_fsbase; error = copyout(&i386base, uap->parms, sizeof(i386base)); break; case I386_SET_FSBASE: error = copyin(uap->parms, &i386base, sizeof(i386base)); - if (!error) { - critical_enter(); - wrmsr(MSR_FSBASE, i386base); + if (!error) pcb->pcb_fsbase = i386base; - critical_exit(); - } break; case I386_GET_GSBASE: i386base = pcb->pcb_gsbase; @@ -83,12 +177,8 @@ sysarch(td, uap) break; case I386_SET_GSBASE: error = copyin(uap->parms, &i386base, sizeof(i386base)); - if (!error) { - critical_enter(); - wrmsr(MSR_KGSBASE, i386base); + if (!error) pcb->pcb_gsbase = i386base; - critical_exit(); - } break; case AMD64_GET_FSBASE: error = copyout(&pcb->pcb_fsbase, uap->parms, sizeof(pcb->pcb_fsbase)); @@ -97,14 +187,10 @@ sysarch(td, uap) case AMD64_SET_FSBASE: error = copyin(uap->parms, &a64base, sizeof(a64base)); if (!error) { - if (a64base < VM_MAXUSER_ADDRESS) { - critical_enter(); - wrmsr(MSR_FSBASE, a64base); + if (a64base < VM_MAXUSER_ADDRESS) pcb->pcb_fsbase = a64base; - critical_exit(); - } else { + else error = EINVAL; - } } break; @@ -115,14 +201,10 @@ sysarch(td, uap) case AMD64_SET_GSBASE: error = copyin(uap->parms, &a64base, sizeof(a64base)); if (!error) { - if (a64base < VM_MAXUSER_ADDRESS) { - critical_enter(); - wrmsr(MSR_KGSBASE, a64base); + if (a64base < VM_MAXUSER_ADDRESS) pcb->pcb_gsbase = a64base; - critical_exit(); - } else { + else error = EINVAL; - } } break; @@ -132,3 +214,423 @@ sysarch(td, uap) } return (error); } + +int +amd64_set_ioperm(td, uap) + struct thread *td; + struct i386_ioperm_args *uap; +{ + int i, error; + char *iomap; + struct amd64tss *tssp; + struct system_segment_descriptor *tss_sd; + u_long *addr; + struct pcb *pcb; + + if ((error = priv_check(td, PRIV_IO)) != 0) + return (error); + if ((error = securelevel_gt(td->td_ucred, 0)) != 0) + return (error); + /* + * XXX + * While this is restricted to root, we should probably figure out + * whether any other driver is using this i/o address, as so not to + * cause confusion. This probably requires a global 'usage registry'. + */ + pcb = td->td_pcb; + if ((iomap = pcb->pcb_iomap) == 0) { + pcb->pcb_tss = kmem_alloc(kernel_map, ctob(IOPAGES+1)); + if (pcb->pcb_tss == 0) + return (ENOMEM); + tssp = (struct amd64tss *)pcb->pcb_tss; + iomap = (char *)pcb->pcb_tss + sizeof(tssp); + addr = (u_long *)iomap; + for (i = 0; i < (ctob(IOPAGES) + 1) / sizeof(u_long); i++) + *addr++ = ~0; + critical_enter(); + td->td_pcb->pcb_iomap = iomap; + td->td_pcb->pcb_tssp = tssp; + tss_sd = PCPU_GET(tss); + memcpy(tssp, &common_tss[PCPU_GET(cpuid)], + sizeof(struct amd64tss)); + tssp->tss_iobase = sizeof(tssp); + tss_sd->sd_lobase = (u_long)tssp & 0xffffff; + tss_sd->sd_hibase = ((u_long)tssp >> 24) & 0xfffffffffful; + tss_sd->sd_type = SDT_SYSTSS; + ltr(GSEL(GPROC0_SEL, SEL_KPL)); + critical_exit(); + } + if (uap->start + uap->length > IOPAGES * PAGE_SIZE * NBBY) + return (EINVAL); + + for (i = uap->start; i < uap->start + uap->length; i++) { + if (uap->enable) + iomap[i >> 3] &= ~(1 << (i & 7)); + else + iomap[i >> 3] |= (1 << (i & 7)); + } + return (error); +} + +int +amd64_get_ioperm(td, uap) + struct thread *td; + struct i386_ioperm_args *uap; +{ + int i, state; + char *iomap; + + if (uap->start >= IOPAGES * PAGE_SIZE * NBBY) + return (EINVAL); + + if (td->td_pcb->pcb_iomap == 0) { + uap->length = 0; + goto done; + } + + iomap = (char *)td->td_pcb->pcb_iomap; + + i = uap->start; + state = (iomap[i >> 3] >> (i & 7)) & 1; + uap->enable = !state; + uap->length = 1; + + for (i = uap->start + 1; i < IOPAGES * PAGE_SIZE * NBBY; i++) { + if (state != ((iomap[i >> 3] >> (i & 7)) & 1)) + break; + uap->length++; + } + +done: + return (0); +} + +/* + * Update the GDT entry pointing to the LDT to point to the LDT of the + * current process. + */ +void +set_user_ldt(struct mdproc *mdp) +{ + + *PCPU_GET(ldt) = mdp->md_ldt_sd; + lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); +} + +#ifdef notyet +#ifdef SMP +static void +set_user_ldt_rv(struct vmspace *vmsp) +{ + struct thread *td; + + td = curthread; + if (vmsp != td->td_proc->p_vmspace) + return; + + set_user_ldt(&td->td_proc->p_md); +} +#endif +#endif + +struct proc_ldt * +user_ldt_alloc(struct proc *p, int force) +{ + struct proc_ldt *pldt, *new_ldt; + struct mdproc *mdp; + struct soft_segment_descriptor sldt; + + mtx_assert(&dt_lock, MA_OWNED); + mdp = &p->p_md; + if (!force && mdp->md_ldt != NULL) + return (mdp->md_ldt); + mtx_unlock(&dt_lock); + MALLOC(new_ldt, struct proc_ldt *, sizeof(struct proc_ldt), + M_SUBPROC, M_WAITOK); + + new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map, + max_ldt_segment * sizeof(struct user_segment_descriptor)); + if (new_ldt->ldt_base == NULL) { + FREE(new_ldt, M_SUBPROC); + mtx_lock(&dt_lock); + return (NULL); + } + new_ldt->ldt_refcnt = 1; + sldt.ssd_base = (uint64_t)new_ldt->ldt_base; + sldt.ssd_limit = max_ldt_segment * + sizeof(struct user_segment_descriptor) - 1; + sldt.ssd_type = SDT_SYSLDT; + sldt.ssd_dpl = SEL_KPL; + sldt.ssd_p = 1; + sldt.ssd_long = 0; + sldt.ssd_def32 = 0; + sldt.ssd_gran = 0; + mtx_lock(&dt_lock); + pldt = mdp->md_ldt; + if (pldt != NULL && !force) { + kmem_free(kernel_map, (vm_offset_t)pldt->ldt_base, + max_ldt_segment * sizeof(struct user_segment_descriptor)); + FREE(new_ldt, M_SUBPROC); + return (pldt); + } + + mdp->md_ldt = new_ldt; + if (pldt != NULL) { + bcopy(pldt->ldt_base, new_ldt->ldt_base, max_ldt_segment * + sizeof(struct user_segment_descriptor)); + user_ldt_derefl(pldt); + } + ssdtosyssd(&sldt, &p->p_md.md_ldt_sd); + if (p == curproc) + set_user_ldt(mdp); + + return (mdp->md_ldt); +} + +void +user_ldt_free(struct thread *td) +{ + struct proc *p = td->td_proc; + struct mdproc *mdp = &p->p_md; + struct proc_ldt *pldt; + + mtx_assert(&dt_lock, MA_OWNED); + if ((pldt = mdp->md_ldt) == NULL) { + mtx_unlock(&dt_lock); + return; + } + + mdp->md_ldt = NULL; + bzero(&mdp->md_ldt_sd, sizeof(mdp->md_ldt_sd)); + if (td == curthread) + lldt(GSEL(GNULL_SEL, SEL_KPL)); + user_ldt_deref(pldt); +} + +static void +user_ldt_derefl(struct proc_ldt *pldt) +{ + + if (--pldt->ldt_refcnt == 0) { + kmem_free(kernel_map, (vm_offset_t)pldt->ldt_base, + max_ldt_segment * sizeof(struct user_segment_descriptor)); + FREE(pldt, M_SUBPROC); + } +} + +void +user_ldt_deref(struct proc_ldt *pldt) +{ + + mtx_assert(&dt_lock, MA_OWNED); + user_ldt_derefl(pldt); + mtx_unlock(&dt_lock); +} + +/* + * Note for the authors of compat layers (linux, etc): copyout() in + * the function below is not a problem since it presents data in + * arch-specific format (i.e. i386-specific in this case), not in + * the OS-specific one. + */ +int +amd64_get_ldt(td, uap) + struct thread *td; + struct i386_ldt_args *uap; +{ + int error = 0; + struct proc_ldt *pldt; + int num; + struct user_segment_descriptor *lp; + +#ifdef DEBUG + printf("amd64_get_ldt: start=%d num=%d descs=%p\n", + uap->start, uap->num, (void *)uap->descs); +#endif + + if ((pldt = td->td_proc->p_md.md_ldt) != NULL) { + lp = &((struct user_segment_descriptor *)(pldt->ldt_base)) + [uap->start]; + num = min(uap->num, max_ldt_segment); + } else + return (EINVAL); + + if ((uap->start > (unsigned int)max_ldt_segment) || + ((unsigned int)num > (unsigned int)max_ldt_segment) || + ((unsigned int)(uap->start + num) > (unsigned int)max_ldt_segment)) + return(EINVAL); + + error = copyout(lp, uap->descs, num * + sizeof(struct user_segment_descriptor)); + if (!error) + td->td_retval[0] = num; + + return(error); +} + +int +amd64_set_ldt(td, uap, descs) + struct thread *td; + struct i386_ldt_args *uap; + struct user_segment_descriptor *descs; +{ + int error = 0, i; + int largest_ld; + struct mdproc *mdp = &td->td_proc->p_md; + struct proc_ldt *pldt; + struct user_segment_descriptor *dp; + struct proc *p; + +#ifdef DEBUG + printf("amd64_set_ldt: start=%d num=%d descs=%p\n", + uap->start, uap->num, (void *)uap->descs); +#endif + + p = td->td_proc; + if (descs == NULL) { + /* Free descriptors */ + if (uap->start == 0 && uap->num == 0) + uap->num = max_ldt_segment; + if (uap->num <= 0) + return (EINVAL); + if ((pldt = mdp->md_ldt) == NULL || + uap->start >= max_ldt_segment) + return (0); + largest_ld = uap->start + uap->num; + if (largest_ld > max_ldt_segment) + largest_ld = max_ldt_segment; + i = largest_ld - uap->start; + mtx_lock(&dt_lock); + bzero(&((struct user_segment_descriptor *)(pldt->ldt_base)) + [uap->start], sizeof(struct user_segment_descriptor) * i); + mtx_unlock(&dt_lock); + return (0); + } + + if (!(uap->start == LDT_AUTO_ALLOC && uap->num == 1)) { + /* verify range of descriptors to modify */ + largest_ld = uap->start + uap->num; + if (uap->start >= max_ldt_segment || + uap->num < 0 || largest_ld > max_ldt_segment) + return (EINVAL); + } + + /* Check descriptors for access violations */ + for (i = 0; i < uap->num; i++) { + dp = &descs[i]; + + switch (dp->sd_type) { + case SDT_SYSNULL: /* system null */ + dp->sd_p = 0; + break; + case SDT_SYS286TSS: + case SDT_SYSLDT: + case SDT_SYS286BSY: + case SDT_SYS286CGT: + case SDT_SYSTASKGT: + case SDT_SYS286IGT: + case SDT_SYS286TGT: + case SDT_SYSNULL2: + case SDT_SYSTSS: + case SDT_SYSNULL3: + case SDT_SYSBSY: + case SDT_SYSCGT: + case SDT_SYSNULL4: + case SDT_SYSIGT: + case SDT_SYSTGT: + /* I can't think of any reason to allow a user proc + * to create a segment of these types. They are + * for OS use only. + */ + return (EACCES); + /*NOTREACHED*/ + + /* memory segment types */ + case SDT_MEMEC: /* memory execute only conforming */ + case SDT_MEMEAC: /* memory execute only accessed conforming */ + case SDT_MEMERC: /* memory execute read conforming */ + case SDT_MEMERAC: /* memory execute read accessed conforming */ + /* Must be "present" if executable and conforming. */ + if (dp->sd_p == 0) + return (EACCES); + break; + case SDT_MEMRO: /* memory read only */ + case SDT_MEMROA: /* memory read only accessed */ + case SDT_MEMRW: /* memory read write */ + case SDT_MEMRWA: /* memory read write accessed */ + case SDT_MEMROD: /* memory read only expand dwn limit */ + case SDT_MEMRODA: /* memory read only expand dwn lim accessed */ + case SDT_MEMRWD: /* memory read write expand dwn limit */ + case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */ + case SDT_MEME: /* memory execute only */ + case SDT_MEMEA: /* memory execute only accessed */ + case SDT_MEMER: /* memory execute read */ + case SDT_MEMERA: /* memory execute read accessed */ + break; + default: + return(EINVAL); + /*NOTREACHED*/ + } + + /* Only user (ring-3) descriptors may be present. */ + if ((dp->sd_p != 0) && (dp->sd_dpl != SEL_UPL)) + return (EACCES); + } + + if (uap->start == LDT_AUTO_ALLOC && uap->num == 1) { + /* Allocate a free slot */ + mtx_lock(&dt_lock); + pldt = user_ldt_alloc(p, 0); + if (pldt == NULL) { + mtx_unlock(&dt_lock); + return (ENOMEM); + } + + /* + * start scanning a bit up to leave room for NVidia and + * Wine, which still user the "Blat" method of allocation. + */ + i = 16; + dp = &((struct user_segment_descriptor *)(pldt->ldt_base))[i]; + for (; i < max_ldt_segment; ++i, ++dp) { + if (dp->sd_type == SDT_SYSNULL) + break; + } + if (i >= max_ldt_segment) { + mtx_unlock(&dt_lock); + return (ENOSPC); + } + uap->start = i; + error = amd64_set_ldt_data(td, i, 1, descs); + mtx_unlock(&dt_lock); + } else { + largest_ld = uap->start + uap->num; + if (largest_ld > max_ldt_segment) + return (EINVAL); + mtx_lock(&dt_lock); + if (user_ldt_alloc(p, 0) != NULL) { + error = amd64_set_ldt_data(td, uap->start, uap->num, + descs); + } + mtx_unlock(&dt_lock); + } + if (error == 0) + td->td_retval[0] = uap->start; + return (error); +} + +int +amd64_set_ldt_data(struct thread *td, int start, int num, + struct user_segment_descriptor *descs) +{ + struct mdproc *mdp = &td->td_proc->p_md; + struct proc_ldt *pldt = mdp->md_ldt; + + mtx_assert(&dt_lock, MA_OWNED); + + /* Fill in range */ + bcopy(descs, + &((struct user_segment_descriptor *)(pldt->ldt_base))[start], + num * sizeof(struct user_segment_descriptor)); + return (0); +} diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 8d710cd..8c6d29f 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -478,6 +478,22 @@ trap(struct trapframe *frame) frame->tf_rip = (long)doreti_iret_fault; goto out; } + if (frame->tf_rip == (long)ld_ds) { + frame->tf_rip = (long)ds_load_fault; + goto out; + } + if (frame->tf_rip == (long)ld_es) { + frame->tf_rip = (long)es_load_fault; + goto out; + } + if (frame->tf_rip == (long)ld_fs) { + frame->tf_rip = (long)fs_load_fault; + goto out; + } + if (frame->tf_rip == (long)ld_gs) { + frame->tf_rip = (long)gs_load_fault; + goto out; + } if (PCPU_GET(curpcb)->pcb_onfault != NULL) { frame->tf_rip = (long)PCPU_GET(curpcb)->pcb_onfault; @@ -579,6 +595,18 @@ trap(struct trapframe *frame) if ((type == T_PAGEFLT) || (type == T_PROTFLT)) uprintf(", fault VA = 0x%lx", frame->tf_addr); uprintf("\n"); +{ + register_t rg,rgk, rf; + rf = rdmsr(0xc0000100); + rg = rdmsr(0xc0000101); + rgk = rdmsr(0xc0000102); + uprintf("TRAP type %d rip %lx err %lx cs %lx ss %lx ds %lx " + "es %lx fs %lx fsbase %lx %lx gs %lx gsbase %lx %lx %lx\n", + type, frame->tf_rip, frame->tf_err, + frame->tf_cs, frame->tf_ss, frame->tf_ds, frame->tf_es, + frame->tf_fs, td->td_pcb->pcb_fsbase, rf, + frame->tf_gs, td->td_pcb->pcb_gsbase, rg, rgk); + } } #endif diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index adddc1c..e7f8f9e 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -93,6 +93,8 @@ static u_int cpu_reset_proxyid; static volatile u_int cpu_reset_proxy_active; #endif +extern int _udatasel; + /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child @@ -107,11 +109,23 @@ cpu_fork(td1, p2, td2, flags) { register struct proc *p1; struct pcb *pcb2; - struct mdproc *mdp2; + struct mdproc *mdp1, *mdp2; + struct proc_ldt *pldt; p1 = td1->td_proc; - if ((flags & RFPROC) == 0) + if ((flags & RFPROC) == 0) { + if ((flags & RFMEM) == 0) { + /* unshare user LDT */ + mdp1 = &p1->p_md; + mtx_lock(&dt_lock); + if ((pldt = mdp1->md_ldt) != NULL && + pldt->ldt_refcnt > 1 && + user_ldt_alloc(p1, 1) == NULL) + panic("could not copy LDT"); + mtx_unlock(&dt_lock); + } return; + } /* Ensure that p1's pcb is up to date. */ fpuexit(td1); @@ -173,6 +187,32 @@ cpu_fork(td1, p2, td2, flags) td2->td_md.md_spinlock_count = 1; td2->td_md.md_saved_flags = PSL_KERNEL | PSL_I; + /* As an i386, do not copy io permission bitmap. */ + pcb2->pcb_iomap = NULL; + pcb2->pcb_tssp = NULL; + + /* Copy the LDT, if necessary. */ + mdp1 = &td1->td_proc->p_md; + mdp2 = &p2->p_md; + mtx_lock(&dt_lock); + if (mdp1->md_ldt != NULL) { + if (flags & RFMEM) { + mdp1->md_ldt->ldt_refcnt++; + mdp2->md_ldt = mdp1->md_ldt; + bcopy(&mdp1->md_ldt_sd, &mdp2->md_ldt_sd, sizeof(struct + system_segment_descriptor)); + } else { + mdp2->md_ldt = user_ldt_alloc(p2, 0); + if (mdp2->md_ldt == NULL) + panic("could not copy LDT"); + amd64_set_ldt_data(td2, 0, max_ldt_segment, + (struct user_segment_descriptor *) + mdp1->md_ldt->ldt_base); + } + } else + mdp2->md_ldt = NULL; + mtx_unlock(&dt_lock); + /* * Now, cpu_switch() can schedule the new process. * pcb_rsp is loaded pointing to the cpu_switch() stack frame @@ -207,25 +247,68 @@ cpu_set_fork_handler(td, func, arg) void cpu_exit(struct thread *td) { + + /* + * If this process has a custom LDT, release it. + */ + mtx_lock(&dt_lock); + if (td->td_proc->p_md.md_ldt != 0) { + user_ldt_free(td); + } else + mtx_unlock(&dt_lock); } void cpu_thread_exit(struct thread *td) { + struct system_segment_descriptor *tss_sd; + struct amd64tss *tssp; + struct pcb *pcb; if (td == PCPU_GET(fpcurthread)) fpudrop(); + pcb = td->td_pcb; + /* Disable any hardware breakpoints. */ - if (td->td_pcb->pcb_flags & PCB_DBREGS) { + if (pcb->pcb_flags & PCB_DBREGS) { reset_dbregs(); - td->td_pcb->pcb_flags &= ~PCB_DBREGS; + pcb->pcb_flags &= ~PCB_DBREGS; + } + + /* + * Clean TSS/iomap + */ + if (pcb->pcb_tssp != NULL) { + tssp = PCPU_GET(commontssp); + + /* + * Proc spinlock is owned, and spinlock implies + * critical section. + */ + PCPU_SET(tssp, tssp); + tss_sd = PCPU_GET(tss); + tss_sd->sd_lobase = (u_long)tssp & 0xffffff; + tss_sd->sd_hibase = ((u_long)tssp >> 24) & 0xfffffffffful; + tss_sd->sd_type = SDT_SYSTSS; + ltr(GSEL(GPROC0_SEL, SEL_KPL)); + pcb->pcb_iomap = NULL; + pcb->pcb_tssp = NULL; } } void cpu_thread_clean(struct thread *td) { + struct pcb *pcb; + vm_offset_t tss; + + pcb = td->td_pcb; + if (pcb->pcb_tss != 0) { + tss = pcb->pcb_tss; + pcb->pcb_tss = 0; + kmem_free(kernel_map, tss, ctob(IOPAGES + 1)); + } } void @@ -250,6 +333,8 @@ cpu_thread_alloc(struct thread *td) void cpu_thread_free(struct thread *td) { + + cpu_thread_clean(td); } /* @@ -353,6 +438,10 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg, ((register_t)stack->ss_sp + stack->ss_size) & ~0x0f; td->td_frame->tf_rsp -= 8; td->td_frame->tf_rip = (register_t)entry; + td->td_frame->tf_ds = _udatasel; + td->td_frame->tf_es = _udatasel; + td->td_frame->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + td->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); /* * Pass the address of the mailbox for this kse to the uts @@ -370,25 +459,11 @@ cpu_set_user_tls(struct thread *td, void *tls_base) #ifdef COMPAT_IA32 if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) { - if (td == curthread) { - critical_enter(); - td->td_pcb->pcb_gsbase = (register_t)tls_base; - wrmsr(MSR_KGSBASE, td->td_pcb->pcb_gsbase); - critical_exit(); - } else { - td->td_pcb->pcb_gsbase = (register_t)tls_base; - } + td->td_pcb->pcb_gsbase = (register_t)tls_base; return (0); } #endif - if (td == curthread) { - critical_enter(); - td->td_pcb->pcb_fsbase = (register_t)tls_base; - wrmsr(MSR_FSBASE, td->td_pcb->pcb_fsbase); - critical_exit(); - } else { - td->td_pcb->pcb_fsbase = (register_t)tls_base; - } + td->td_pcb->pcb_fsbase = (register_t)tls_base; return (0); } diff --git a/sys/amd64/ia32/ia32_reg.c b/sys/amd64/ia32/ia32_reg.c index 8abc6fc..fef43d1 100644 --- a/sys/amd64/ia32/ia32_reg.c +++ b/sys/amd64/ia32/ia32_reg.c @@ -85,9 +85,10 @@ fill_regs32(struct thread *td, struct reg32 *regs) tp = td->td_frame; pcb = td->td_pcb; - regs->r_fs = pcb->pcb_fs; - regs->r_es = pcb->pcb_es; - regs->r_ds = pcb->pcb_ds; + regs->r_gs = tp->tf_gs; + regs->r_fs = tp->tf_fs; + regs->r_es = tp->tf_es; + regs->r_ds = tp->tf_ds; regs->r_edi = tp->tf_rdi; regs->r_esi = tp->tf_rsi; regs->r_ebp = tp->tf_rbp; @@ -100,7 +101,6 @@ fill_regs32(struct thread *td, struct reg32 *regs) regs->r_eflags = tp->tf_rflags; regs->r_esp = tp->tf_rsp; regs->r_ss = tp->tf_ss; - regs->r_gs = pcb->pcb_gs; return (0); } @@ -114,14 +114,10 @@ set_regs32(struct thread *td, struct reg32 *regs) if (!EFL_SECURE(regs->r_eflags, tp->tf_rflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); pcb = td->td_pcb; -#if 0 - load_fs(regs->r_fs); - pcb->pcb_fs = regs->r_fs; - load_es(regs->r_es); - pcb->pcb_es = regs->r_es; - load_ds(regs->r_ds); - pcb->pcb_ds = regs->r_ds; -#endif + tp->tf_gs = regs->r_gs; + tp->tf_fs = regs->r_fs; + tp->tf_es = regs->r_es; + tp->tf_ds = regs->r_ds; tp->tf_rdi = regs->r_edi; tp->tf_rsi = regs->r_esi; tp->tf_rbp = regs->r_ebp; @@ -134,10 +130,6 @@ set_regs32(struct thread *td, struct reg32 *regs) tp->tf_rflags = regs->r_eflags; tp->tf_rsp = regs->r_esp; tp->tf_ss = regs->r_ss; -#if 0 - load_gs(regs->r_gs); - pcb->pcb_gs = regs->r_gs; -#endif return (0); } @@ -166,7 +158,7 @@ fill_fpregs32(struct thread *td, struct fpreg32 *regs) penv_87->en_fcs = td->td_frame->tf_cs; penv_87->en_opcode = penv_xmm->en_opcode; penv_87->en_foo = penv_xmm->en_rdp; - penv_87->en_fos = td->td_pcb->pcb_ds; + penv_87->en_fos = td->td_frame->tf_ds; /* FPU registers */ for (i = 0; i < 8; ++i) diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c index 162dcf9..63e8b79 100644 --- a/sys/amd64/ia32/ia32_signal.c +++ b/sys/amd64/ia32/ia32_signal.c @@ -134,10 +134,10 @@ ia32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags) PROC_LOCK(curthread->td_proc); mcp->mc_onstack = sigonstack(tp->tf_rsp); PROC_UNLOCK(curthread->td_proc); - mcp->mc_gs = td->td_pcb->pcb_gs; - mcp->mc_fs = td->td_pcb->pcb_fs; - mcp->mc_es = td->td_pcb->pcb_es; - mcp->mc_ds = td->td_pcb->pcb_ds; + mcp->mc_gs = tp->tf_gs; + mcp->mc_fs = tp->tf_fs; + mcp->mc_es = tp->tf_es; + mcp->mc_ds = tp->tf_ds; mcp->mc_edi = tp->tf_rdi; mcp->mc_esi = tp->tf_rsi; mcp->mc_ebp = tp->tf_rbp; @@ -394,10 +394,8 @@ freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; - load_ds(_udatasel); - td->td_pcb->pcb_ds = _udatasel; - load_es(_udatasel); - td->td_pcb->pcb_es = _udatasel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; /* leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); @@ -514,10 +512,8 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; - load_ds(_udatasel); - td->td_pcb->pcb_ds = _udatasel; - load_es(_udatasel); - td->td_pcb->pcb_es = _udatasel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; /* leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); @@ -715,20 +711,8 @@ ia32_setregs(td, entry, stack, ps_strings) struct trapframe *regs = td->td_frame; struct pcb *pcb = td->td_pcb; - critical_enter(); - wrmsr(MSR_FSBASE, 0); - wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ pcb->pcb_fsbase = 0; pcb->pcb_gsbase = 0; - critical_exit(); - load_ds(_udatasel); - load_es(_udatasel); - load_fs(_udatasel); - load_gs(_udatasel); - pcb->pcb_ds = _udatasel; - pcb->pcb_es = _udatasel; - pcb->pcb_fs = _udatasel; - pcb->pcb_gs = _udatasel; bzero((char *)regs, sizeof(struct trapframe)); regs->tf_rip = entry; @@ -737,6 +721,10 @@ ia32_setregs(td, entry, stack, ps_strings) regs->tf_ss = _udatasel; regs->tf_cs = _ucode32sel; regs->tf_rbx = ps_strings; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); load_cr0(rcr0() | CR0_MP | CR0_TS); fpstate_drop(td); diff --git a/sys/amd64/include/asmacros.h b/sys/amd64/include/asmacros.h index 788f39f..421e871 100644 --- a/sys/amd64/include/asmacros.h +++ b/sys/amd64/include/asmacros.h @@ -161,7 +161,11 @@ movq %r12,TF_R12(%rsp) ; \ movq %r13,TF_R13(%rsp) ; \ movq %r14,TF_R14(%rsp) ; \ - movq %r15,TF_R15(%rsp) + movq %r15,TF_R15(%rsp) ; \ + movl %fs,TF_FS(%rsp) ; \ + movl %gs,TF_GS(%rsp) ; \ + movl %es,TF_ES(%rsp) ; \ + movl %ds,TF_DS(%rsp) #define POP_FRAME \ movq TF_RDI(%rsp),%rdi ; \ diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h index 26c9dd0..f9026aa 100644 --- a/sys/amd64/include/frame.h +++ b/sys/amd64/include/frame.h @@ -64,6 +64,38 @@ struct trapframe { register_t tf_r13; register_t tf_r14; register_t tf_r15; + register_t tf_fs; + register_t tf_gs; + register_t tf_es; + register_t tf_ds; + register_t tf_trapno; + register_t tf_addr; + register_t tf_flags; + /* below portion defined in hardware */ + register_t tf_err; + register_t tf_rip; + register_t tf_cs; + register_t tf_rflags; + register_t tf_rsp; + register_t tf_ss; +}; + +struct otrapframe { + register_t tf_rdi; + register_t tf_rsi; + register_t tf_rdx; + register_t tf_rcx; + register_t tf_r8; + register_t tf_r9; + register_t tf_rax; + register_t tf_rbx; + register_t tf_rbp; + register_t tf_r10; + register_t tf_r11; + register_t tf_r12; + register_t tf_r13; + register_t tf_r14; + register_t tf_r15; register_t tf_trapno; register_t tf_addr; register_t tf_flags; diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h index 348cb31..fa5b57f 100644 --- a/sys/amd64/include/md_var.h +++ b/sys/amd64/include/md_var.h @@ -54,6 +54,7 @@ extern char cpu_vendor[]; extern char kstack[]; extern char sigcode[]; extern int szsigcode; +extern int szsigcode7; extern uint64_t *vm_page_dump; extern int vm_page_dump_size; @@ -68,6 +69,14 @@ void busdma_swi(void); void cpu_setregs(void); void doreti_iret(void) __asm(__STRING(doreti_iret)); void doreti_iret_fault(void) __asm(__STRING(doreti_iret_fault)); +void ld_ds(void) __asm(__STRING(ld_ds)); +void ld_es(void) __asm(__STRING(ld_es)); +void ld_fs(void) __asm(__STRING(ld_fs)); +void ld_gs(void) __asm(__STRING(ld_gs)); +void ds_load_fault(void) __asm(__STRING(ds_load_fault)); +void es_load_fault(void) __asm(__STRING(es_load_fault)); +void fs_load_fault(void) __asm(__STRING(fs_load_fault)); +void gs_load_fault(void) __asm(__STRING(gs_load_fault)); void dump_add_page(vm_paddr_t); void dump_drop_page(vm_paddr_t); void initializecpu(void); diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h index 43b59e5..c7544ab 100644 --- a/sys/amd64/include/pcb.h +++ b/sys/amd64/include/pcb.h @@ -56,10 +56,6 @@ struct pcb { register_t pcb_fsbase; register_t pcb_gsbase; u_long pcb_flags; - u_int32_t pcb_ds; - u_int32_t pcb_es; - u_int32_t pcb_fs; - u_int32_t pcb_gs; u_int64_t pcb_dr0; u_int64_t pcb_dr1; u_int64_t pcb_dr2; @@ -78,6 +74,10 @@ struct pcb { /* 32-bit segment descriptor */ struct user_segment_descriptor pcb_gs32sd; + caddr_t pcb_iomap; /* i/o permission bitmap */ + /* local tss, with i/o bitmap; NULL for common */ + struct amd64tss *pcb_tssp; + vm_offset_t pcb_tss; }; #ifdef _KERNEL diff --git a/sys/amd64/include/pcpu.h b/sys/amd64/include/pcpu.h index e9faf28..84b4ebb 100644 --- a/sys/amd64/include/pcpu.h +++ b/sys/amd64/include/pcpu.h @@ -45,11 +45,15 @@ struct pcpu *pc_prvspace; /* Self-reference */ \ struct pmap *pc_curpmap; \ struct amd64tss *pc_tssp; \ + struct amd64tss *pc_commontssp; \ register_t pc_rsp0; \ register_t pc_scratch_rsp; /* User %rsp in syscall */ \ u_int pc_apic_id; \ u_int pc_acpi_id; /* ACPI CPU id */ \ - struct user_segment_descriptor *pc_gs32p + struct user_segment_descriptor *pc_fs32p; \ + struct user_segment_descriptor *pc_gs32p; \ + struct system_segment_descriptor *pc_ldt; \ + struct system_segment_descriptor *pc_tss #ifdef _KERNEL diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h index a3ebd79..273ba5e 100644 --- a/sys/amd64/include/proc.h +++ b/sys/amd64/include/proc.h @@ -33,6 +33,13 @@ #ifndef _MACHINE_PROC_H_ #define _MACHINE_PROC_H_ +#include + +struct proc_ldt { + caddr_t ldt_base; + int ldt_refcnt; +}; + /* * Machine-dependent part of the proc structure for AMD64. */ @@ -42,6 +49,8 @@ struct mdthread { }; struct mdproc { + struct proc_ldt *md_ldt; /* (t) per-process ldt */ + struct system_segment_descriptor md_ldt_sd; }; #ifdef _KERNEL @@ -55,6 +64,18 @@ struct mdproc { (char *)&td; \ } while (0) +void set_user_ldt(struct mdproc *); +struct proc_ldt *user_ldt_alloc(struct proc *, int); +void user_ldt_free(struct thread *); +void user_ldt_deref(struct proc_ldt *); +struct sysarch_args; +int sysarch_ldt(struct thread *td, struct sysarch_args *uap, int uap_space); +int amd64_set_ldt_data(struct thread *td, int start, int num, + struct user_segment_descriptor *descs); + +extern struct mtx dt_lock; +extern int max_ldt_segment; + #endif /* _KERNEL */ #endif /* !_MACHINE_PROC_H_ */ diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h index 1c83d1c..6c6cb40 100644 --- a/sys/amd64/include/segments.h +++ b/sys/amd64/include/segments.h @@ -108,12 +108,29 @@ struct gate_descriptor { u_int64_t sd_xx1:32; } __packed; +/* + * Generic descriptor + */ +union descriptor { + struct user_segment_descriptor sd; + struct gate_descriptor gd; +}; + /* system segments and gate types */ #define SDT_SYSNULL 0 /* system null */ +#define SDT_SYS286TSS 1 /* system 286 TSS available */ #define SDT_SYSLDT 2 /* system 64 bit local descriptor table */ +#define SDT_SYS286BSY 3 /* system 286 TSS busy */ +#define SDT_SYS286CGT 4 /* system 286 call gate */ +#define SDT_SYSTASKGT 5 /* system task gate */ +#define SDT_SYS286IGT 6 /* system 286 interrupt gate */ +#define SDT_SYS286TGT 7 /* system 286 trap gate */ +#define SDT_SYSNULL2 8 /* system null again */ #define SDT_SYSTSS 9 /* system available 64 bit TSS */ +#define SDT_SYSNULL3 10 /* system null again */ #define SDT_SYSBSY 11 /* system busy 64 bit TSS */ #define SDT_SYSCGT 12 /* system 64 bit call gate */ +#define SDT_SYSNULL4 13 /* system null again */ #define SDT_SYSIGT 14 /* system 64 bit interrupt gate */ #define SDT_SYSTGT 15 /* system 64 bit trap gate */ @@ -203,7 +220,10 @@ struct region_descriptor { #define GPROC0_SEL 6 /* TSS for entering kernel etc */ /* slot 7 is second half of GPROC0_SEL */ #define GUGS32_SEL 8 /* User 32 bit GS Descriptor */ -#define NGDT 9 +#define GUFS32_SEL 9 /* User 32 bit FS Descriptor */ +#define GUSERLDT_SEL 10 /* LDT */ +/* slot 11 is second half of GUSERLDT_SEL */ +#define NGDT 12 #ifdef _KERNEL extern struct user_segment_descriptor gdt[]; diff --git a/sys/amd64/include/sigframe.h b/sys/amd64/include/sigframe.h index d104507..0671104 100644 --- a/sys/amd64/include/sigframe.h +++ b/sys/amd64/include/sigframe.h @@ -43,4 +43,13 @@ struct sigframe { siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ }; +struct sigframe7 { + union { + __siginfohandler_t *sf_action; + __sighandler_t *sf_handler; + } sf_ahu; + struct ucontext7 sf_uc; /* = *sf_ucontext */ + siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ +}; + #endif /* !_MACHINE_SIGFRAME_H_ */ diff --git a/sys/amd64/include/sysarch.h b/sys/amd64/include/sysarch.h index 67c8a4a..6c3e6c9 100644 --- a/sys/amd64/include/sysarch.h +++ b/sys/amd64/include/sysarch.h @@ -35,6 +35,15 @@ #ifndef _MACHINE_SYSARCH_H_ #define _MACHINE_SYSARCH_H_ +#define I386_GET_LDT 0 +#define I386_SET_LDT 1 +#define LDT_AUTO_ALLOC 0xffffffff + /* I386_IOPL */ +#define I386_GET_IOPERM 3 +#define I386_SET_IOPERM 4 + +/* XXX Not implementable #define I386_VM86 6 */ + #define I386_GET_FSBASE 7 #define I386_SET_FSBASE 8 #define I386_GET_GSBASE 9 @@ -46,6 +55,18 @@ #define AMD64_GET_GSBASE 130 #define AMD64_SET_GSBASE 131 +struct i386_ldt_args { + unsigned int start; + struct user_segment_descriptor *descs __packed; + unsigned int num; +}; + +struct i386_ioperm_args { + unsigned int start; + unsigned int length; + int enable; +}; + #ifndef _KERNEL #include @@ -56,6 +77,15 @@ int amd64_set_fsbase(void *); int amd64_set_gsbase(void *); int sysarch(int, void *); __END_DECLS +#else +struct thread; +union descriptor; + +int amd64_get_ldt(struct thread *, struct i386_ldt_args *); +int amd64_set_ldt(struct thread *, struct i386_ldt_args *, + struct user_segment_descriptor *); +int amd64_get_ioperm(struct thread *, struct i386_ioperm_args *); +int amd64_set_ioperm(struct thread *, struct i386_ioperm_args *); #endif #endif /* !_MACHINE_SYSARCH_H_ */ diff --git a/sys/amd64/include/ucontext.h b/sys/amd64/include/ucontext.h index 5c13803..6414668 100644 --- a/sys/amd64/include/ucontext.h +++ b/sys/amd64/include/ucontext.h @@ -34,7 +34,7 @@ typedef struct __mcontext { /* - * The first 20 fields must match the definition of + * The first 24 fields must match the definition of * sigcontext. So that we can support sigcontext * and ucontext_t at the same time. */ @@ -54,6 +54,10 @@ typedef struct __mcontext { __register_t mc_r13; __register_t mc_r14; __register_t mc_r15; + __register_t tf_fs; + __register_t tf_gs; + __register_t tf_es; + __register_t tf_ds; __register_t mc_trapno; __register_t mc_addr; __register_t mc_flags; @@ -79,4 +83,51 @@ typedef struct __mcontext { long mc_spare[8]; } mcontext_t; +struct __mcontext7 { + /* + * The first 20 fields must match the definition of + * sigcontext. So that we can support sigcontext + * and ucontext_t at the same time. + */ + __register_t mc_onstack; /* XXX - sigcontext compat. */ + __register_t mc_rdi; /* machine state (struct trapframe) */ + __register_t mc_rsi; + __register_t mc_rdx; + __register_t mc_rcx; + __register_t mc_r8; + __register_t mc_r9; + __register_t mc_rax; + __register_t mc_rbx; + __register_t mc_rbp; + __register_t mc_r10; + __register_t mc_r11; + __register_t mc_r12; + __register_t mc_r13; + __register_t mc_r14; + __register_t mc_r15; + __register_t mc_trapno; + __register_t mc_addr; + __register_t mc_flags; + __register_t mc_err; + __register_t mc_rip; + __register_t mc_cs; + __register_t mc_rflags; + __register_t mc_rsp; + __register_t mc_ss; + + long mc_len; /* sizeof(mcontext_t) */ +#define _MC_FPFMT_NODEV 0x10000 /* device not present or configured */ +#define _MC_FPFMT_XMM 0x10002 + long mc_fpformat; +#define _MC_FPOWNED_NONE 0x20000 /* FP state not used */ +#define _MC_FPOWNED_FPU 0x20001 /* FP state came from FPU */ +#define _MC_FPOWNED_PCB 0x20002 /* FP state came from PCB */ + long mc_ownedfp; + /* + * See for the internals of mc_fpstate[]. + */ + long mc_fpstate[64] __aligned(16); + long mc_spare[8]; +}; + #endif /* !_MACHINE_UCONTEXT_H_ */ diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c index aecf869..e54f7b2 100644 --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -693,8 +693,8 @@ linux_clone(struct thread *td, struct linux_clone_args *args) sd.sd_long, sd.sd_def32, sd.sd_gran); #endif td2->td_pcb->pcb_gsbase = (register_t)info.base_addr; - td2->td_pcb->pcb_gs32sd = sd; - td2->td_pcb->pcb_gs = GSEL(GUGS32_SEL, SEL_UPL); +/* XXXKIB td2->td_pcb->pcb_gs32sd = sd; */ + td2->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); td2->td_pcb->pcb_flags |= PCB_GS32BIT | PCB_32BIT; } } @@ -1351,7 +1351,7 @@ linux_set_thread_area(struct thread *td, critical_enter(); td->td_pcb->pcb_gsbase = (register_t)info.base_addr; - td->td_pcb->pcb_gs32sd = *PCPU_GET(gs32p) = sd; +/* XXXKIB td->td_pcb->pcb_gs32sd = *PCPU_GET(gs32p) = sd; */ td->td_pcb->pcb_flags |= PCB_32BIT | PCB_GS32BIT; wrmsr(MSR_KGSBASE, td->td_pcb->pcb_gsbase); critical_exit(); diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index 5676ddd..865482f 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -405,10 +405,10 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; - load_ds(_udatasel); - td->td_pcb->pcb_ds = _udatasel; - load_es(_udatasel); - td->td_pcb->pcb_es = _udatasel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); /* leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); @@ -487,10 +487,10 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) * Build the signal context to be used by sigreturn. */ frame.sf_sc.sc_mask = lmask.__bits[0]; - frame.sf_sc.sc_gs = rgs(); - frame.sf_sc.sc_fs = rfs(); - __asm __volatile("movl %%es,%0" : "=rm" (frame.sf_sc.sc_es)); - __asm __volatile("movl %%ds,%0" : "=rm" (frame.sf_sc.sc_ds)); + frame.sf_sc.sc_gs = regs->tf_gs; + frame.sf_sc.sc_fs = regs->tf_fs; + frame.sf_sc.sc_es = regs->tf_es; + frame.sf_sc.sc_ds = regs->tf_ds; frame.sf_sc.sc_edi = regs->tf_rdi; frame.sf_sc.sc_esi = regs->tf_rsi; frame.sf_sc.sc_ebp = regs->tf_rbp; @@ -527,10 +527,10 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; - load_ds(_udatasel); - td->td_pcb->pcb_ds = _udatasel; - load_es(_udatasel); - td->td_pcb->pcb_es = _udatasel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); /* leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); @@ -714,7 +714,10 @@ linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) /* * Restore signal context */ - /* Selectors were restored by the trampoline. */ + regs->tf_gs = context->sc_gs; + regs->tf_fs = context->sc_fs; + regs->tf_es = context->sc_es; + regs->tf_ds = context->sc_ds; regs->tf_rdi = context->sc_edi; regs->tf_rsi = context->sc_esi; regs->tf_rbp = context->sc_ebp; @@ -823,19 +826,15 @@ exec_linux_setregs(td, entry, stack, ps_strings) pcb->pcb_fsbase = 0; pcb->pcb_gsbase = 0; critical_exit(); - load_ds(_udatasel); - load_es(_udatasel); - load_fs(_udatasel); - load_gs(_udatasel); - pcb->pcb_ds = _udatasel; - pcb->pcb_es = _udatasel; - pcb->pcb_fs = _udatasel; - pcb->pcb_gs = _udatasel; bzero((char *)regs, sizeof(struct trapframe)); regs->tf_rip = entry; regs->tf_rsp = stack; regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); + regs->tf_gs = _udatasel; + regs->tf_fs = _udatasel; + regs->tf_es = _udatasel; + regs->tf_ds = _udatasel; regs->tf_ss = _udatasel; regs->tf_cs = _ucode32sel; regs->tf_rbx = ps_strings; diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h index 0c77bab..5957a92 100644 --- a/sys/compat/freebsd32/freebsd32.h +++ b/sys/compat/freebsd32/freebsd32.h @@ -173,4 +173,10 @@ struct thr_param32 { uint32_t spare[3]; }; +struct i386_ldt_args32 { + uint32_t start; + uint32_t descs; + uint32_t num; +}; + #endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */ diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 917a672..49b3973 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include @@ -2555,6 +2556,31 @@ freebsd32_cpuset_setaffinity(struct thread *td, } int +freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap) +{ + struct sysarch_args uap1; + struct i386_ldt_args uapl; + struct i386_ldt_args32 uapl32; + int error; + + if (uap->op == I386_SET_LDT || uap->op == I386_GET_LDT) { + if ((error = copyin(uap->parms, &uapl32, sizeof(uapl32))) != 0) + return (error); + uap1.op = uap->op; + uap1.parms = (char *)&uapl; + uapl.start = uapl32.start; + uapl.descs = (struct user_segment_descriptor *)(uintptr_t) + uapl32.descs; + uapl.num = uapl32.num; + return (sysarch_ldt(td, &uap1, UIO_SYSSPACE)); + } else { + uap1.op = uap->op; + uap1.parms = uap->parms; + return (sysarch(td, &uap1)); + } +} + +int freebsd32_nmount(struct thread *td, struct freebsd32_nmount_args /* { struct iovec *iovp; diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h index d8944ad..a1e7f08 100644 --- a/sys/compat/freebsd32/freebsd32_proto.h +++ b/sys/compat/freebsd32/freebsd32_proto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 183188 2008-09-19 15:17:32Z obrien + * created from FreeBSD */ #ifndef _FREEBSD32_SYSPROTO_H_ @@ -114,6 +114,10 @@ struct freebsd32_adjtime_args { char delta_l_[PADL_(struct timeval32 *)]; struct timeval32 * delta; char delta_r_[PADR_(struct timeval32 *)]; char olddelta_l_[PADL_(struct timeval32 *)]; struct timeval32 * olddelta; char olddelta_r_[PADR_(struct timeval32 *)]; }; +struct freebsd32_sysarch_args { + char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)]; + char parms_l_[PADL_(char *)]; char * parms; char parms_r_[PADR_(char *)]; +}; struct freebsd32_semsys_args { char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)]; char a2_l_[PADL_(int)]; int a2; char a2_r_[PADR_(int)]; @@ -394,6 +398,7 @@ int freebsd32_writev(struct thread *, struct freebsd32_writev_args *); int freebsd32_settimeofday(struct thread *, struct freebsd32_settimeofday_args *); int freebsd32_utimes(struct thread *, struct freebsd32_utimes_args *); int freebsd32_adjtime(struct thread *, struct freebsd32_adjtime_args *); +int freebsd32_sysarch(struct thread *, struct freebsd32_sysarch_args *); int freebsd32_semsys(struct thread *, struct freebsd32_semsys_args *); int freebsd32_msgsys(struct thread *, struct freebsd32_msgsys_args *); int freebsd32_shmsys(struct thread *, struct freebsd32_shmsys_args *); @@ -605,6 +610,7 @@ int freebsd6_freebsd32_ftruncate(struct thread *, struct freebsd6_freebsd32_ftru #define FREEBSD32_SYS_AUE_freebsd32_settimeofday AUE_SETTIMEOFDAY #define FREEBSD32_SYS_AUE_freebsd32_utimes AUE_UTIMES #define FREEBSD32_SYS_AUE_freebsd32_adjtime AUE_ADJTIME +#define FREEBSD32_SYS_AUE_freebsd32_sysarch AUE_SYSARCH #define FREEBSD32_SYS_AUE_freebsd32_semsys AUE_SEMSYS #define FREEBSD32_SYS_AUE_freebsd32_msgsys AUE_MSGSYS #define FREEBSD32_SYS_AUE_freebsd32_shmsys AUE_SHMSYS diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h index 0848a25..03fc7c4 100644 --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 183188 2008-09-19 15:17:32Z obrien + * created from FreeBSD */ #define FREEBSD32_SYS_syscall 0 @@ -159,7 +159,7 @@ #define FREEBSD32_SYS_getdomainname 162 #define FREEBSD32_SYS_setdomainname 163 #define FREEBSD32_SYS_uname 164 -#define FREEBSD32_SYS_sysarch 165 +#define FREEBSD32_SYS_freebsd32_sysarch 165 #define FREEBSD32_SYS_rtprio 166 #define FREEBSD32_SYS_freebsd32_semsys 169 #define FREEBSD32_SYS_freebsd32_msgsys 170 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c index c80f776..907f7d8 100644 --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 183188 2008-09-19 15:17:32Z obrien + * created from FreeBSD */ const char *freebsd32_syscallnames[] = { @@ -172,7 +172,7 @@ const char *freebsd32_syscallnames[] = { "getdomainname", /* 162 = getdomainname */ "setdomainname", /* 163 = setdomainname */ "uname", /* 164 = uname */ - "sysarch", /* 165 = sysarch */ + "freebsd32_sysarch", /* 165 = freebsd32_sysarch */ "rtprio", /* 166 = rtprio */ "#167", /* 167 = nosys */ "#168", /* 168 = nosys */ diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c index a03e2ef..55fb035 100644 --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 183188 2008-09-19 15:17:32Z obrien + * created from FreeBSD */ #include "opt_compat.h" @@ -203,7 +203,7 @@ struct sysent freebsd32_sysent[] = { { AS(getdomainname_args), (sy_call_t *)getdomainname, AUE_SYSCTL, NULL, 0, 0 }, /* 162 = getdomainname */ { AS(setdomainname_args), (sy_call_t *)setdomainname, AUE_SYSCTL, NULL, 0, 0 }, /* 163 = setdomainname */ { AS(uname_args), (sy_call_t *)uname, AUE_NULL, NULL, 0, 0 }, /* 164 = uname */ - { AS(sysarch_args), (sy_call_t *)sysarch, AUE_SYSARCH, NULL, 0, 0 }, /* 165 = sysarch */ + { AS(freebsd32_sysarch_args), (sy_call_t *)freebsd32_sysarch, AUE_SYSARCH, NULL, 0, 0 }, /* 165 = freebsd32_sysarch */ { AS(rtprio_args), (sy_call_t *)rtprio, AUE_RTPRIO, NULL, 0, 0 }, /* 166 = rtprio */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 }, /* 167 = nosys */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 }, /* 168 = nosys */ diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 3fedb3e..0d8eda5 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -300,7 +300,7 @@ 163 AUE_SYSCTL NOPROTO { int setdomainname(char *domainname, \ int len); } 164 AUE_NULL NOPROTO { int uname(struct utsname *name); } -165 AUE_SYSARCH NOPROTO { int sysarch(int op, char *parms); } +165 AUE_SYSARCH STD { int freebsd32_sysarch(int op, char *parms); } 166 AUE_RTPRIO NOPROTO { int rtprio(int function, pid_t pid, \ struct rtprio *rtp); } 167 AUE_NULL UNIMPL nosys diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index fc6c6f4..45cec6c 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson + * created from FreeBSD */ #include "opt_compat.h" @@ -444,8 +444,8 @@ struct sysent sysent[] = { { AS(extattr_get_link_args), (sy_call_t *)extattr_get_link, AUE_EXTATTR_GET_LINK, NULL, 0, 0 }, /* 413 = extattr_get_link */ { AS(extattr_delete_link_args), (sy_call_t *)extattr_delete_link, AUE_EXTATTR_DELETE_LINK, NULL, 0, 0 }, /* 414 = extattr_delete_link */ { AS(__mac_execve_args), (sy_call_t *)__mac_execve, AUE_NULL, NULL, 0, 0 }, /* 415 = __mac_execve */ - { AS(sigaction_args), (sy_call_t *)sigaction, AUE_SIGACTION, NULL, 0, 0 }, /* 416 = sigaction */ - { AS(sigreturn_args), (sy_call_t *)sigreturn, AUE_SIGRETURN, NULL, 0, 0 }, /* 417 = sigreturn */ + { compat(AS(osigaction_freebsd7_args),sigaction_freebsd7), AUE_SIGACTION, NULL, 0, 0 }, /* 416 = old sigaction_freebsd7 */ + { compat(AS(osigreturn_freebsd7_args),sigreturn_freebsd7), AUE_SIGRETURN, NULL, 0, 0 }, /* 417 = old sigreturn_freebsd7 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 }, /* 418 = __xstat */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 }, /* 419 = __xfstat */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 }, /* 420 = __xlstat */ @@ -533,4 +533,6 @@ struct sysent sysent[] = { { AS(symlinkat_args), (sy_call_t *)symlinkat, AUE_SYMLINKAT, NULL, 0, 0 }, /* 502 = symlinkat */ { AS(unlinkat_args), (sy_call_t *)unlinkat, AUE_UNLINKAT, NULL, 0, 0 }, /* 503 = unlinkat */ { AS(posix_openpt_args), (sy_call_t *)posix_openpt, AUE_POSIX_OPENPT, NULL, 0, 0 }, /* 504 = posix_openpt */ + { AS(sigaction_args), (sy_call_t *)sigaction, AUE_SIGACTION, NULL, 0, 0 }, /* 505 = sigaction */ + { AS(sigreturn_args), (sy_call_t *)sigreturn, AUE_SIGRETURN, NULL, 0, 0 }, /* 506 = sigreturn */ }; diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index d5d1813..c3af8fa 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -767,6 +767,15 @@ kern_sigaction(td, sig, act, oact, flags) else SIGADDSET(ps->ps_freebsd4, sig); #endif +#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD6) || \ + defined(COMPAT_FREEBSD7) + if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || + ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL || + (flags & KSA_FREEBSD7) == 0) + SIGDELSET(ps->ps_freebsd7, sig); + else + SIGADDSET(ps->ps_freebsd7, sig); +#endif #ifdef COMPAT_43 if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL || @@ -840,7 +849,51 @@ freebsd4_sigaction(td, uap) error = copyout(oactp, uap->oact, sizeof(oact)); return (error); } -#endif /* COMAPT_FREEBSD4 */ +#endif /* COMPAT_FREEBSD4 */ + +#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD6) || \ + defined(COMPAT_FREEBSD7) +#ifndef _SYS_SYSPROTO_H_ +struct freebsd7_sigaction_args { + int sig; + struct sigaction *act; + struct sigaction *oact; +}; +#endif +int +osigaction_freebsd7(td, uap) + struct thread *td; + register struct osigaction_freebsd7_args *uap; +{ + struct sigaction act, oact; + register struct sigaction *actp, *oactp; + int error; + + + actp = (uap->act != NULL) ? &act : NULL; + oactp = (uap->oact != NULL) ? &oact : NULL; + if (actp) { + error = copyin(uap->act, actp, sizeof(act)); + if (error) + return (error); + } + error = kern_sigaction(td, uap->sig, actp, oactp, KSA_FREEBSD7); + if (oactp && !error) + error = copyout(oactp, uap->oact, sizeof(oact)); + return (error); +} +#if !defined(__amd64__) +/* Avoid replicating the same stub everywhere */ +int +osigreturn_freebsd7(td, uap) + struct thread *td; + struct osigreturn_freebsd7_args *uap; +{ + + return (sigreturn(td, (struct sigreturn_args *)uap)); +} +#endif +#endif /* COMPAT_FREEBSD7 */ #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ #ifndef _SYS_SYSPROTO_H_ diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh index 74737f2..36cdcca 100644 --- a/sys/kern/makesyscalls.sh +++ b/sys/kern/makesyscalls.sh @@ -267,7 +267,7 @@ s/\$//g funcalias = funcname if (argalias == "") { argalias = funcname "_args" - if ($3 == "COMPAT") + if ($3 == "COMPAT" || $3 == "LIBCOMPAT") argalias = "o" argalias if ($3 == "COMPAT4") argalias = "freebsd4_" argalias @@ -457,7 +457,18 @@ s/\$//g $3 == "LIBCOMPAT" { ncompat++ parseline() - printf("%s\to%s();\n", rettype, funcname) > syscompatdcl + if (argc != 0) { + printf("struct %s {\n", argalias) > out + for (i = 1; i <= argc; i++) + printf("\tchar %s_l_[PADL_(%s)]; %s %s; " \ + "char %s_r_[PADR_(%s)];\n", + argname[i], argtype[i], + argtype[i], argname[i], + argname[i], argtype[i]) > out + printf("};\n") > out + } + printf("%s\to%s(struct thread *, struct %s *);\n", rettype, + funcname, argalias) > syscompatdcl printf("\t{ compat(%s,%s), %s, NULL, 0, 0 },", argssize, funcname, auditev) > sysent align_sysent_comment(8 + 9 + \ diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 80149fc..6447210 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson + * created from FreeBSD */ const char *syscallnames[] = { @@ -423,8 +423,8 @@ const char *syscallnames[] = { "extattr_get_link", /* 413 = extattr_get_link */ "extattr_delete_link", /* 414 = extattr_delete_link */ "__mac_execve", /* 415 = __mac_execve */ - "sigaction", /* 416 = sigaction */ - "sigreturn", /* 417 = sigreturn */ + "compat.sigaction_freebsd7", /* 416 = old sigaction_freebsd7 */ + "old.sigreturn_freebsd7", /* 417 = old sigreturn_freebsd7 */ "#418", /* 418 = __xstat */ "#419", /* 419 = __xfstat */ "#420", /* 420 = __xlstat */ @@ -512,4 +512,6 @@ const char *syscallnames[] = { "symlinkat", /* 502 = symlinkat */ "unlinkat", /* 503 = unlinkat */ "posix_openpt", /* 504 = posix_openpt */ + "sigaction", /* 505 = sigaction */ + "sigreturn", /* 506 = sigreturn */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 3bbe2e6..79c0a3e 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -737,10 +737,10 @@ const char *attrname); } 415 AUE_NULL STD { int __mac_execve(char *fname, char **argv, \ char **envv, struct mac *mac_p); } -416 AUE_SIGACTION STD { int sigaction(int sig, \ +416 AUE_SIGACTION COMPAT { int sigaction_freebsd7(int sig, \ const struct sigaction *act, \ struct sigaction *oact); } -417 AUE_SIGRETURN STD { int sigreturn( \ +417 AUE_SIGRETURN LIBCOMPAT { int sigreturn_freebsd7( \ const struct __ucontext *sigcntxp); } 418 AUE_NULL UNIMPL __xstat 419 AUE_NULL UNIMPL __xfstat @@ -895,5 +895,10 @@ char *path2); } 503 AUE_UNLINKAT STD { int unlinkat(int fd, char *path, int flag); } 504 AUE_POSIX_OPENPT STD { int posix_openpt(int flags); } +505 AUE_SIGACTION STD { int sigaction(int sig, \ + const struct sigaction *act, \ + struct sigaction *oact); } +506 AUE_SIGRETURN STD { int sigreturn( \ + const struct __ucontext *sigcntxp); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c index 097bf21..3155286 100644 --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -2345,22 +2345,6 @@ systrace_args(int sysnum, void *params, u_int64_t *uarg, int *n_args) *n_args = 4; break; } - /* sigaction */ - case 416: { - struct sigaction_args *p = params; - iarg[0] = p->sig; /* int */ - uarg[1] = (intptr_t) p->act; /* const struct sigaction * */ - uarg[2] = (intptr_t) p->oact; /* struct sigaction * */ - *n_args = 3; - break; - } - /* sigreturn */ - case 417: { - struct sigreturn_args *p = params; - uarg[0] = (intptr_t) p->sigcntxp; /* const struct __ucontext * */ - *n_args = 1; - break; - } /* getcontext */ case 421: { struct getcontext_args *p = params; @@ -3061,6 +3045,22 @@ systrace_args(int sysnum, void *params, u_int64_t *uarg, int *n_args) *n_args = 1; break; } + /* sigaction */ + case 505: { + struct sigaction_args *p = params; + iarg[0] = p->sig; /* int */ + uarg[1] = (intptr_t) p->act; /* const struct sigaction * */ + uarg[2] = (intptr_t) p->oact; /* struct sigaction * */ + *n_args = 3; + break; + } + /* sigreturn */ + case 506: { + struct sigreturn_args *p = params; + uarg[0] = (intptr_t) p->sigcntxp; /* const struct __ucontext * */ + *n_args = 1; + break; + } default: *n_args = 0; break; @@ -6863,32 +6863,6 @@ systrace_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* sigaction */ - case 416: - switch(ndx) { - case 0: - p = "int"; - break; - case 1: - p = "const struct sigaction *"; - break; - case 2: - p = "struct sigaction *"; - break; - default: - break; - }; - break; - /* sigreturn */ - case 417: - switch(ndx) { - case 0: - p = "const struct __ucontext *"; - break; - default: - break; - }; - break; /* getcontext */ case 421: switch(ndx) { @@ -8120,6 +8094,32 @@ systrace_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* sigaction */ + case 505: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const struct sigaction *"; + break; + case 2: + p = "struct sigaction *"; + break; + default: + break; + }; + break; + /* sigreturn */ + case 506: + switch(ndx) { + case 0: + p = "const struct __ucontext *"; + break; + default: + break; + }; + break; default: break; }; diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index dc09226..98fdf86 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -61,6 +61,7 @@ struct sigacts { sigset_t ps_sigignore; /* Signals being ignored. */ sigset_t ps_sigcatch; /* Signals being caught by user. */ sigset_t ps_freebsd4; /* signals using freebsd4 ucontext. */ + sigset_t ps_freebsd7; /* signals using freebsd4 ucontext. */ sigset_t ps_osigset; /* Signals using <= 3.x osigset_t. */ sigset_t ps_usertramp; /* SunOS compat; libc sigtramp. XXX */ int ps_flag; diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index ed98f15..3a6c74d 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson + * created from FreeBSD */ #define SYS_syscall 0 @@ -339,8 +339,8 @@ #define SYS_extattr_get_link 413 #define SYS_extattr_delete_link 414 #define SYS___mac_execve 415 -#define SYS_sigaction 416 -#define SYS_sigreturn 417 + /* 416 is old sigaction_freebsd7 */ +#define SYS_sigreturn_freebsd7 417 /* compatibility; still used by libc */ #define SYS_getcontext 421 #define SYS_setcontext 422 #define SYS_swapcontext 423 @@ -420,4 +420,6 @@ #define SYS_symlinkat 502 #define SYS_unlinkat 503 #define SYS_posix_openpt 504 -#define SYS_MAXSYSCALL 505 +#define SYS_sigaction 505 +#define SYS_sigreturn 506 +#define SYS_MAXSYSCALL 507 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index 37ea3d7..cb79e88 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -1,7 +1,7 @@ # FreeBSD system call names. # DO NOT EDIT-- this file is automatically generated. # $FreeBSD$ -# created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson +# created from FreeBSD MIASM = \ syscall.o \ exit.o \ @@ -288,8 +288,7 @@ MIASM = \ extattr_get_link.o \ extattr_delete_link.o \ __mac_execve.o \ - sigaction.o \ - sigreturn.o \ + sigreturn_freebsd7.o \ getcontext.o \ setcontext.o \ swapcontext.o \ @@ -368,4 +367,6 @@ MIASM = \ renameat.o \ symlinkat.o \ unlinkat.o \ - posix_openpt.o + posix_openpt.o \ + sigaction.o \ + sigreturn.o diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index ec352f8..0873efb 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -214,5 +214,6 @@ int kern_writev(struct thread *td, int fd, struct uio *auio); /* flags for kern_sigaction */ #define KSA_OSIGSET 0x0001 /* uses osigact_t */ #define KSA_FREEBSD4 0x0002 /* uses ucontext4 */ +#define KSA_FREEBSD7 0x0004 /* uses ucontext7 */ #endif /* !_SYS_SYSCALLSUBR_H_ */ diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index dcf59b1..c4b968c 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson + * created from FreeBSD */ #ifndef _SYS_SYSPROTO_H_ @@ -1241,14 +1241,6 @@ struct __mac_execve_args { char envv_l_[PADL_(char **)]; char ** envv; char envv_r_[PADR_(char **)]; char mac_p_l_[PADL_(struct mac *)]; struct mac * mac_p; char mac_p_r_[PADR_(struct mac *)]; }; -struct sigaction_args { - char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; - char act_l_[PADL_(const struct sigaction *)]; const struct sigaction * act; char act_r_[PADR_(const struct sigaction *)]; - char oact_l_[PADL_(struct sigaction *)]; struct sigaction * oact; char oact_r_[PADR_(struct sigaction *)]; -}; -struct sigreturn_args { - char sigcntxp_l_[PADL_(const struct __ucontext *)]; const struct __ucontext * sigcntxp; char sigcntxp_r_[PADR_(const struct __ucontext *)]; -}; struct getcontext_args { char ucp_l_[PADL_(struct __ucontext *)]; struct __ucontext * ucp; char ucp_r_[PADR_(struct __ucontext *)]; }; @@ -1633,6 +1625,14 @@ struct unlinkat_args { struct posix_openpt_args { char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; }; +struct sigaction_args { + char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; + char act_l_[PADL_(const struct sigaction *)]; const struct sigaction * act; char act_r_[PADR_(const struct sigaction *)]; + char oact_l_[PADL_(struct sigaction *)]; struct sigaction * oact; char oact_r_[PADR_(struct sigaction *)]; +}; +struct sigreturn_args { + char sigcntxp_l_[PADL_(const struct __ucontext *)]; const struct __ucontext * sigcntxp; char sigcntxp_r_[PADR_(const struct __ucontext *)]; +}; int nosys(struct thread *, struct nosys_args *); void sys_exit(struct thread *, struct sys_exit_args *); int fork(struct thread *, struct fork_args *); @@ -1910,8 +1910,6 @@ int extattr_set_link(struct thread *, struct extattr_set_link_args *); int extattr_get_link(struct thread *, struct extattr_get_link_args *); int extattr_delete_link(struct thread *, struct extattr_delete_link_args *); int __mac_execve(struct thread *, struct __mac_execve_args *); -int sigaction(struct thread *, struct sigaction_args *); -int sigreturn(struct thread *, struct sigreturn_args *); int getcontext(struct thread *, struct getcontext_args *); int setcontext(struct thread *, struct setcontext_args *); int swapcontext(struct thread *, struct swapcontext_args *); @@ -1991,6 +1989,8 @@ int renameat(struct thread *, struct renameat_args *); int symlinkat(struct thread *, struct symlinkat_args *); int unlinkat(struct thread *, struct unlinkat_args *); int posix_openpt(struct thread *, struct posix_openpt_args *); +int sigaction(struct thread *, struct sigaction_args *); +int sigreturn(struct thread *, struct sigreturn_args *); #ifdef COMPAT_43 @@ -2123,6 +2123,14 @@ struct ogetdirentries_args { char count_l_[PADL_(u_int)]; u_int count; char count_r_[PADR_(u_int)]; char basep_l_[PADL_(long *)]; long * basep; char basep_r_[PADR_(long *)]; }; +struct osigaction_freebsd7_args { + char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; + char act_l_[PADL_(const struct sigaction *)]; const struct sigaction * act; char act_r_[PADR_(const struct sigaction *)]; + char oact_l_[PADL_(struct sigaction *)]; struct sigaction * oact; char oact_r_[PADR_(struct sigaction *)]; +}; +struct osigreturn_freebsd7_args { + char sigcntxp_l_[PADL_(const struct __ucontext *)]; const struct __ucontext * sigcntxp; char sigcntxp_r_[PADR_(const struct __ucontext *)]; +}; int ocreat(struct thread *, struct ocreat_args *); int olseek(struct thread *, struct olseek_args *); int ostat(struct thread *, struct ostat_args *); @@ -2160,6 +2168,8 @@ int okillpg(struct thread *, struct okillpg_args *); int oquota(struct thread *, struct oquota_args *); int ogetsockname(struct thread *, struct getsockname_args *); int ogetdirentries(struct thread *, struct ogetdirentries_args *); +int osigaction_freebsd7(struct thread *, struct osigaction_freebsd7_args *); +int osigreturn_freebsd7(struct thread *, struct osigreturn_freebsd7_args *); #endif /* COMPAT_43 */ @@ -2493,8 +2503,6 @@ int freebsd4_sigreturn(struct thread *, struct freebsd4_sigreturn_args *); #define SYS_AUE_extattr_get_link AUE_EXTATTR_GET_LINK #define SYS_AUE_extattr_delete_link AUE_EXTATTR_DELETE_LINK #define SYS_AUE___mac_execve AUE_NULL -#define SYS_AUE_sigaction AUE_SIGACTION -#define SYS_AUE_sigreturn AUE_SIGRETURN #define SYS_AUE_getcontext AUE_NULL #define SYS_AUE_setcontext AUE_NULL #define SYS_AUE_swapcontext AUE_NULL @@ -2574,6 +2582,8 @@ int freebsd4_sigreturn(struct thread *, struct freebsd4_sigreturn_args *); #define SYS_AUE_symlinkat AUE_SYMLINKAT #define SYS_AUE_unlinkat AUE_UNLINKAT #define SYS_AUE_posix_openpt AUE_POSIX_OPENPT +#define SYS_AUE_sigaction AUE_SIGACTION +#define SYS_AUE_sigreturn AUE_SIGRETURN #undef PAD_ #undef PADL_ diff --git a/sys/sys/ucontext.h b/sys/sys/ucontext.h index baa179e..576fc34 100644 --- a/sys/sys/ucontext.h +++ b/sys/sys/ucontext.h @@ -67,6 +67,19 @@ struct ucontext4 { #endif /* __i386__ */ #endif /* _KERNEL */ +#if defined(_KERNEL) && (defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD6) \ + ||defined(COMPAT_FREEBSD7)) +#if defined(__amd64__) +struct ucontext7 { + sigset_t uc_sigmask; + struct __mcontext7 uc_mcontext; + struct ucontext7 *uc_link; + stack_t uc_stack; + int __spare__[8]; +}; +#endif +#endif + #ifndef _KERNEL __BEGIN_DECLS