From ef75a7aa2c77cdd2981e76dbb59ff01667a6048c Mon Sep 17 00:00:00 2001 From: Tobias Weingartner Date: Thu, 12 Jan 2006 22:39:22 +0000 Subject: Move to using gdt only (no more ldt in general case) but with a variable limit selector, so that the w^x line can float much more dynamically. Much work done by tom. Tested by various people. Addresses concerns of (Julien Tinnes) --- sys/arch/i386/i386/cpu.c | 6 ++- sys/arch/i386/i386/freebsd_machdep.c | 6 +-- sys/arch/i386/i386/genassym.cf | 3 +- sys/arch/i386/i386/linux_machdep.c | 6 +-- sys/arch/i386/i386/machdep.c | 64 +++++++++++++++++++++++---- sys/arch/i386/i386/pmap.c | 85 +++++++++++++++++++++++++++++++----- sys/arch/i386/i386/svr4_machdep.c | 6 +-- sys/arch/i386/include/cpu.h | 4 +- sys/arch/i386/include/pmap.h | 3 +- sys/arch/i386/include/segments.h | 5 ++- 10 files changed, 152 insertions(+), 36 deletions(-) diff --git a/sys/arch/i386/i386/cpu.c b/sys/arch/i386/i386/cpu.c index d3fef0caff6..95d82a9d06b 100644 --- a/sys/arch/i386/i386/cpu.c +++ b/sys/arch/i386/i386/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.16 2005/11/23 11:30:14 mickey Exp $ */ +/* $OpenBSD: cpu.c,v 1.17 2006/01/12 22:39:20 weingart Exp $ */ /* $NetBSD: cpu.c,v 1.1.2.7 2000/06/26 02:04:05 sommerfeld Exp $ */ /*- @@ -255,6 +255,8 @@ cpu_attach(parent, self, aux) pcb->pcb_pmap = pmap_kernel(); pcb->pcb_cr3 = vtophys((vaddr_t)pcb->pcb_pmap->pm_pdir); /* pcb->pcb_cr3 = pcb->pcb_pmap->pm_pdir - KERNBASE; XXX ??? */ + + cpu_default_ldt(ci); /* Use the `global' ldt until one alloc'd */ #endif /* further PCB init done later. */ @@ -295,6 +297,7 @@ cpu_attach(parent, self, aux) */ printf("apid %d (application processor)\n", caa->cpu_number); gdt_alloc_cpu(ci); + cpu_alloc_ldt(ci); ci->ci_flags |= CPUF_PRESENT | CPUF_AP; identifycpu(ci); ci->ci_next = cpu_info_list->ci_next; @@ -455,6 +458,7 @@ cpu_hatch(void *v) lapic_initclocks(); lapic_set_lvt(); gdt_init_cpu(ci); + cpu_init_ldt(ci); npxinit(ci); lldt(GSEL(GLDT_SEL, SEL_KPL)); diff --git a/sys/arch/i386/i386/freebsd_machdep.c b/sys/arch/i386/i386/freebsd_machdep.c index ef9930565a6..9e213ce906a 100644 --- a/sys/arch/i386/i386/freebsd_machdep.c +++ b/sys/arch/i386/i386/freebsd_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: freebsd_machdep.c,v 1.17 2003/06/02 23:27:47 millert Exp $ */ +/* $OpenBSD: freebsd_machdep.c,v 1.18 2006/01/12 22:39:20 weingart Exp $ */ /* $NetBSD: freebsd_machdep.c,v 1.10 1996/05/03 19:42:05 christos Exp $ */ /*- @@ -81,7 +81,6 @@ freebsd_sendsig(catcher, sig, mask, code, type, val) union sigval val; { register struct proc *p = curproc; - struct pmap *pmap = vm_map_pmap(&p->p_vmspace->vm_map); register struct trapframe *tf; struct freebsd_sigframe *fp, frame; struct sigacts *psp = p->p_sigacts; @@ -157,8 +156,7 @@ freebsd_sendsig(catcher, sig, mask, code, type, val) tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_eip = p->p_sigcode; - tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ? - GSEL(GUCODE1_SEL, SEL_UPL) : GSEL(GUCODE_SEL, SEL_UPL); + tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC); tf->tf_esp = (int)fp; tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); diff --git a/sys/arch/i386/i386/genassym.cf b/sys/arch/i386/i386/genassym.cf index 98f8a05b02c..17ea5424f2d 100644 --- a/sys/arch/i386/i386/genassym.cf +++ b/sys/arch/i386/i386/genassym.cf @@ -1,4 +1,4 @@ -# $OpenBSD: genassym.cf,v 1.22 2005/11/23 16:51:28 mickey Exp $ +# $OpenBSD: genassym.cf,v 1.23 2006/01/12 22:39:20 weingart Exp $ # # Copyright (c) 1982, 1990 The Regents of the University of California. # All rights reserved. @@ -110,6 +110,7 @@ member pcb_cr3 member pcb_ebp member pcb_esp member pcb_cr0 +member pcb_ldt member pcb_ldt_sel member pcb_onfault member pcb_fpcpu diff --git a/sys/arch/i386/i386/linux_machdep.c b/sys/arch/i386/i386/linux_machdep.c index 46cd7f6ffe9..c994c11455a 100644 --- a/sys/arch/i386/i386/linux_machdep.c +++ b/sys/arch/i386/i386/linux_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: linux_machdep.c,v 1.30 2004/07/02 16:29:55 niklas Exp $ */ +/* $OpenBSD: linux_machdep.c,v 1.31 2006/01/12 22:39:20 weingart Exp $ */ /* $NetBSD: linux_machdep.c,v 1.29 1996/05/03 19:42:11 christos Exp $ */ /* @@ -112,7 +112,6 @@ linux_sendsig(catcher, sig, mask, code, type, val) union sigval val; { struct proc *p = curproc; - struct pmap *pmap = vm_map_pmap(&p->p_vmspace->vm_map); struct trapframe *tf; struct linux_sigframe *fp, frame; struct sigacts *psp = p->p_sigacts; @@ -185,8 +184,7 @@ linux_sendsig(catcher, sig, mask, code, type, val) tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_eip = p->p_sigcode; - tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ? - GSEL(GUCODE1_SEL, SEL_UPL) : GSEL(GUCODE_SEL, SEL_UPL); + tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC); tf->tf_esp = (int)fp; tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index caa1ffd3b84..0058051f201 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.338 2006/01/06 10:53:16 grange Exp $ */ +/* $OpenBSD: machdep.c,v 1.339 2006/01/12 22:39:20 weingart Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -488,6 +488,7 @@ i386_proc0_tss_ldt_init() pcb->pcb_iomap_pad = 0xff; pcb->pcb_ldt_sel = pmap_kernel()->pm_ldt_sel = GSEL(GLDT_SEL, SEL_KPL); + pcb->pcb_ldt = ldt; pcb->pcb_cr0 = rcr0(); pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); pcb->pcb_tss.tss_esp0 = (int)proc0.p_addr + USPACE - 16; @@ -512,6 +513,7 @@ i386_init_pcb_tss_ldt(struct cpu_info *ci) pcb->pcb_iomap_pad = 0xff; pcb->pcb_ldt_sel = pmap_kernel()->pm_ldt_sel = GSEL(GLDT_SEL, SEL_KPL); + pcb->pcb_ldt = ci->ci_ldt; pcb->pcb_cr0 = rcr0(); ci->ci_idle_tss_sel = tss_alloc(pcb); } @@ -2084,7 +2086,6 @@ sendsig(catcher, sig, mask, code, type, val) extern char sigcode, sigcode_xmm; #endif struct proc *p = curproc; - struct pmap *pmap = vm_map_pmap(&p->p_vmspace->vm_map); struct trapframe *tf = p->p_md.md_regs; struct sigframe *fp, frame; struct sigacts *psp = p->p_sigacts; @@ -2180,8 +2181,7 @@ sendsig(catcher, sig, mask, code, type, val) tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_eip = p->p_sigcode; - tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ? - GSEL(GUCODE1_SEL, SEL_UPL) : GSEL(GUCODE_SEL, SEL_UPL); + tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); #ifdef I686_CPU if (i386_use_fxsave) tf->tf_eip += &sigcode_xmm - &sigcode; @@ -2591,6 +2591,30 @@ setregs(p, pack, stack, retval) pmap_ldt_cleanup(p); #endif + /* + * Reset the code segment limit to I386_MAX_EXE_ADDR in the pmap; + * this gets copied into the GDT and LDT for {G,L}UCODE_SEL by + * pmap_activate(). + */ + setsegment(&pmap->pm_codeseg, 0, atop(I386_MAX_EXE_ADDR) - 1, + SDT_MEMERA, SEL_UPL, 1, 1); + + /* + * And update the GDT and LDT since we return to the user process + * by leaving the syscall (we don't do another pmap_activate()). + */ +#ifdef MULTIPROCESSOR + curcpu()->ci_gdt[GUCODE_SEL].sd = pcb->pcb_ldt[LUCODE_SEL].sd = + pmap->pm_codeseg; +#else + gdt[GUCODE_SEL].sd = pcb->pcb_ldt[LUCODE_SEL].sd = pmap->pm_codeseg; +#endif + + /* + * And reset the hiexec marker in the pmap. + */ + pmap->pm_hiexec = 0; + p->p_md.md_flags &= ~MDP_USEDFPU; if (i386_use_fxsave) { pcb->pcb_savefpu.sv_xmm.sv_env.en_cw = __OpenBSD_NPXCW__; @@ -2605,8 +2629,7 @@ setregs(p, pack, stack, retval) tf->tf_ebp = 0; tf->tf_ebx = (int)PS_STRINGS; tf->tf_eip = pack->ep_entry; - tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ? - LSEL(LUCODE1_SEL, SEL_UPL) : LSEL(LUCODE_SEL, SEL_UPL); + tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL); tf->tf_eflags = PSL_USERSET; tf->tf_esp = stack; tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL); @@ -2739,6 +2762,32 @@ cpu_init_idt() setregion(®ion, idt, NIDT * sizeof(idt[0]) - 1); lidt(®ion); } + +void +cpu_default_ldt(struct cpu_info *ci) +{ + ci->ci_ldt = ldt; + ci->ci_ldt_len = sizeof(ldt); +} + +void +cpu_alloc_ldt(struct cpu_info *ci) +{ + union descriptor *cpu_ldt; + size_t len = sizeof(ldt); + + cpu_ldt = (union descriptor *)uvm_km_alloc(kernel_map, len); + bcopy(ldt, cpu_ldt, len); + ci->ci_ldt = cpu_ldt; + ci->ci_ldt_len = len; +} + +void +cpu_init_ldt(struct cpu_info *ci) +{ + setsegment(&ci->ci_gdt[GLDT_SEL].sd, ci->ci_ldt, ci->ci_ldt_len - 1, + SDT_SYSLDT, SEL_KPL, 0, 0); +} #endif /* MULTIPROCESSOR */ void @@ -2775,8 +2824,6 @@ init386(paddr_t first_avail) setsegment(&gdt[GDATA_SEL].sd, 0, 0xfffff, SDT_MEMRWA, SEL_KPL, 1, 1); setsegment(&gdt[GLDT_SEL].sd, ldt, sizeof(ldt) - 1, SDT_SYSLDT, SEL_KPL, 0, 0); - setsegment(&gdt[GUCODE1_SEL].sd, 0, atop(VM_MAXUSER_ADDRESS) - 1, - SDT_MEMERA, SEL_UPL, 1, 1); setsegment(&gdt[GUCODE_SEL].sd, 0, atop(I386_MAX_EXE_ADDR) - 1, SDT_MEMERA, SEL_UPL, 1, 1); setsegment(&gdt[GUDATA_SEL].sd, 0, atop(VM_MAXUSER_ADDRESS) - 1, @@ -2787,7 +2834,6 @@ init386(paddr_t first_avail) /* make ldt gates and memory segments */ setgate(&ldt[LSYS5CALLS_SEL].gd, &IDTVEC(osyscall), 1, SDT_SYS386CGT, SEL_UPL, GCODE_SEL); - ldt[LUCODE1_SEL] = gdt[GUCODE1_SEL]; ldt[LUCODE_SEL] = gdt[GUCODE_SEL]; ldt[LUDATA_SEL] = gdt[GUDATA_SEL]; ldt[LBSDICALLS_SEL] = ldt[LSYS5CALLS_SEL]; diff --git a/sys/arch/i386/i386/pmap.c b/sys/arch/i386/i386/pmap.c index be3a1640013..7906bb69757 100644 --- a/sys/arch/i386/i386/pmap.c +++ b/sys/arch/i386/i386/pmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.c,v 1.87 2005/12/25 21:39:06 miod Exp $ */ +/* $OpenBSD: pmap.c,v 1.88 2006/01/12 22:39:20 weingart Exp $ */ /* $NetBSD: pmap.c,v 1.91 2000/06/02 17:46:37 thorpej Exp $ */ /* @@ -465,6 +465,8 @@ void pmap_release(pmap_t); void pmap_zero_phys(paddr_t); +void setcslimit(struct pmap *, struct trapframe *, struct pcb *, vaddr_t); + /* * p m a p i n l i n e h e l p e r f u n c t i o n s */ @@ -710,13 +712,14 @@ pmap_exec_account(struct pmap *pm, vaddr_t va, struct trapframe *tf = curproc->p_md.md_regs; struct pcb *pcb = &curproc->p_addr->u_pcb; - pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); pm->pm_hiexec = I386_MAX_EXE_ADDR; + setcslimit(pm, tf, pcb, I386_MAX_EXE_ADDR); } } /* * Fixup the code segment to cover all potential executable mappings. + * Called by kernel SEGV trap handler. * returns 0 if no changes to the code segment were made. */ int @@ -733,24 +736,62 @@ pmap_exec_fixup(struct vm_map *map, struct trapframe *tf, struct pcb *pcb) * We need to make it point to the last page, not past it. */ if (ent->protection & VM_PROT_EXECUTE) - va = trunc_page(ent->end) - PAGE_SIZE; + va = trunc_page(ent->end - 1); } vm_map_unlock(map); - if (va == pm->pm_hiexec) + if (va <= pm->pm_hiexec) { return (0); + } pm->pm_hiexec = va; - if (pm->pm_hiexec > (vaddr_t)I386_MAX_EXE_ADDR) { - pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE1_SEL, SEL_UPL); - } else { - pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); - } - + /* + * We have a new 'highest executable' va, so we need to update + * the value for the code segment limit, which is stored in the + * PCB. + */ + setcslimit(pm, tf, pcb, va); + return (1); } +void +setcslimit(struct pmap *pm, struct trapframe *tf, struct pcb *pcb, + vaddr_t limit) +{ + /* + * Called when we have a new 'highest executable' va, so we need + * to update the value for the code segment limit, which is stored + * in the PCB. + * + * There are no caching issues to be concerned with: the + * processor reads the whole descriptor from the GDT when the + * appropriate selector is loaded into a segment register, and + * this only happens on the return to userland. + * + * This also works in the MP case, since whichever CPU gets to + * run the process will pick up the right descriptor value from + * the PCB. + */ + limit = min(limit, VM_MAXUSER_ADDRESS - 1); + + setsegment(&pm->pm_codeseg, 0, atop(limit), + SDT_MEMERA, SEL_UPL, 1, 1); + + /* And update the GDT and LDT since we may be called by the + * trap handler (cpu_switch won't get a chance). + */ +#ifdef MULTIPROCESSOR + curcpu()->ci_gdt[GUCODE_SEL].sd = pcb->pcb_ldt[LUCODE_SEL].sd = + pm->pm_codeseg; +#else + gdt[GUCODE_SEL].sd = pcb->pcb_ldt[LUCODE_SEL].sd = pm->pm_codeseg; +#endif + + pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); +} + /* * p m a p k e n t e r f u n c t i o n s * @@ -1946,6 +1987,9 @@ pmap_pinit(pmap) pmap->pm_hiexec = 0; pmap->pm_flags = 0; + setsegment(&pmap->pm_codeseg, 0, atop(I386_MAX_EXE_ADDR) - 1, + SDT_MEMERA, SEL_UPL, 1, 1); + /* allocate PDP */ pmap->pm_pdir = (pd_entry_t *) uvm_km_alloc(kernel_map, NBPG); if (pmap->pm_pdir == NULL) @@ -2171,11 +2215,32 @@ pmap_activate(p) { struct pcb *pcb = &p->p_addr->u_pcb; struct pmap *pmap = p->p_vmspace->vm_map.pmap; +#ifdef MULTIPROCESSOR + struct cpu_info *self = curcpu(); +#endif pcb->pcb_pmap = pmap; + /* Get the LDT that this process will actually use */ +#ifdef MULTIPROCESSOR + pcb->pcb_ldt = pmap->pm_ldt == NULL ? self->ci_ldt : pmap->pm_ldt; +#else + pcb->pcb_ldt = pmap->pm_ldt == NULL ? ldt : pmap->pm_ldt; +#endif pcb->pcb_ldt_sel = pmap->pm_ldt_sel; pcb->pcb_cr3 = pmap->pm_pdirpa; if (p == curproc) { + /* + * Set the correct descriptor value (i.e. with the + * correct code segment X limit) in the GDT and the LDT. + */ +#ifdef MULTIPROCESSOR + self->ci_gdt[GUCODE_SEL].sd = pcb->pcb_ldt[LUCODE_SEL].sd = + pmap->pm_codeseg; +#else + gdt[GUCODE_SEL].sd = pcb->pcb_ldt[LUCODE_SEL].sd = + pmap->pm_codeseg; +#endif + lcr3(pcb->pcb_cr3); lldt(pcb->pcb_ldt_sel); diff --git a/sys/arch/i386/i386/svr4_machdep.c b/sys/arch/i386/i386/svr4_machdep.c index 9fe0fe5ba19..e92e1a7017a 100644 --- a/sys/arch/i386/i386/svr4_machdep.c +++ b/sys/arch/i386/i386/svr4_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: svr4_machdep.c,v 1.21 2004/07/02 16:29:55 niklas Exp $ */ +/* $OpenBSD: svr4_machdep.c,v 1.22 2006/01/12 22:39:21 weingart Exp $ */ /* $NetBSD: svr4_machdep.c,v 1.24 1996/05/03 19:42:26 christos Exp $ */ /* @@ -322,7 +322,6 @@ svr4_sendsig(catcher, sig, mask, code, type, val) union sigval val; { register struct proc *p = curproc; - struct pmap *pmap = vm_map_pmap(&p->p_vmspace->vm_map); register struct trapframe *tf; struct svr4_sigframe *fp, frame; struct sigacts *psp = p->p_sigacts; @@ -380,8 +379,7 @@ svr4_sendsig(catcher, sig, mask, code, type, val) tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_eip = p->p_sigcode; - tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ? - GSEL(GUCODE1_SEL, SEL_UPL) : GSEL(GUCODE_SEL, SEL_UPL); + tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC); tf->tf_esp = (int)fp; tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h index 70a827b0846..bf7327f06a4 100644 --- a/sys/arch/i386/include/cpu.h +++ b/sys/arch/i386/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.73 2005/11/04 06:55:36 tedu Exp $ */ +/* $OpenBSD: cpu.h,v 1.74 2006/01/12 22:39:21 weingart Exp $ */ /* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */ /*- @@ -132,6 +132,8 @@ struct cpu_info { int ci_astpending; union descriptor *ci_gdt; + union descriptor *ci_ldt; /* per-cpu default LDT */ + int ci_ldt_len; /* in bytes */ volatile int ci_ddb_paused; /* paused due to other proc in ddb */ #define CI_DDB_RUNNING 0 diff --git a/sys/arch/i386/include/pmap.h b/sys/arch/i386/include/pmap.h index e0314a635d8..4a350f4201f 100644 --- a/sys/arch/i386/include/pmap.h +++ b/sys/arch/i386/include/pmap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.h,v 1.40 2005/11/23 16:51:28 mickey Exp $ */ +/* $OpenBSD: pmap.h,v 1.41 2006/01/12 22:39:21 weingart Exp $ */ /* $NetBSD: pmap.h,v 1.44 2000/04/24 17:18:18 thorpej Exp $ */ /* @@ -268,6 +268,7 @@ struct pmap { vaddr_t pm_hiexec; /* highest executable mapping */ int pm_flags; /* see below */ + struct segment_descriptor pm_codeseg; /* cs descriptor for process */ union descriptor *pm_ldt; /* user-set LDT */ int pm_ldt_len; /* number of LDT entries */ int pm_ldt_sel; /* LDT selector */ diff --git a/sys/arch/i386/include/segments.h b/sys/arch/i386/include/segments.h index 3519f0a42ed..da6f9abf187 100644 --- a/sys/arch/i386/include/segments.h +++ b/sys/arch/i386/include/segments.h @@ -1,4 +1,4 @@ -/* $OpenBSD: segments.h,v 1.13 2004/06/13 21:49:16 niklas Exp $ */ +/* $OpenBSD: segments.h,v 1.14 2006/01/12 22:39:21 weingart Exp $ */ /* $NetBSD: segments.h,v 1.23 1996/02/01 22:31:03 mycroft Exp $ */ /*- @@ -134,6 +134,9 @@ void setsegment(struct segment_descriptor *, void *, size_t, int, int, int, int); void unsetgate(struct gate_descriptor *); void cpu_init_idt(void); +void cpu_default_ldt(struct cpu_info *); +void cpu_alloc_ldt(struct cpu_info *); +void cpu_init_ldt(struct cpu_info *); int idt_vec_alloc(int, int); void idt_vec_set(int, void (*)(void)); -- cgit v1.2.3