Index: include/gdt.h =================================================================== --- include/gdt.h (revision 374) +++ include/gdt.h (working copy) @@ -45,7 +45,7 @@ void gdt_init(void); void gdt_init_cpu(struct cpu_info *); void gdt_reload_cpu(struct cpu_info *); void gdt_alloc_cpu(struct cpu_info *); -int tss_alloc(struct pcb *); +int tss_alloc(const struct i386tss *); void tss_free(int); void ldt_alloc(struct pmap *, union descriptor *, size_t); void ldt_free(struct pmap *); Index: include/pcb.h =================================================================== --- include/pcb.h (revision 413) +++ include/pcb.h (working copy) @@ -88,17 +88,16 @@ #include #include -#define NIOPORTS 1024 /* # of ports we allow to be mapped */ - struct pcb { - struct i386tss pcb_tss; -#define pcb_cr3 pcb_tss.tss_cr3 -#define pcb_esp pcb_tss.tss_esp -#define pcb_ebp pcb_tss.tss_ebp -#define pcb_cs pcb_tss.__tss_cs -#define pcb_ldt_sel pcb_tss.tss_ldt + int pcb_esp0; /* ring0 esp */ + int pcb_esp; /* kernel esp */ + int pcb_ebp; /* kernel ebp */ + int pcb_ldt_sel; int pcb_cr0; /* saved image of CR0 */ int pcb_cr2; /* page fault address (CR2) */ + int pcb_cr3; /* page directory pointer */ + int __dummy; /* pcb_savefpu need to be + 16-bytes aligned */ union savefpu pcb_savefpu; /* floating point state for FPU */ struct emcsts pcb_saveemc; /* Cyrix EMC state */ /* @@ -110,7 +109,7 @@ struct pcb { void *vm86_userp; /* XXX performance hack */ struct pmap *pcb_pmap; /* back pointer to our pmap */ struct cpu_info *pcb_fpcpu; /* cpu holding our fp state. */ - u_long pcb_iomap[NIOPORTS/32]; /* I/O bitmap */ + char *pcb_iomap; /* I/O permission bitmap */ }; /* Index: include/types.h =================================================================== --- include/types.h (revision 343) +++ include/types.h (working copy) @@ -72,6 +72,5 @@ typedef __volatile int __cpu_simple_loc #define __HAVE_OLD_DISKLABEL #define __HAVE_GENERIC_SOFT_INTERRUPTS #define __HAVE_RAS -#define __HAVE_CPU_MAXPROC #endif /* _MACHTYPES_H_ */ Index: include/segments.h =================================================================== --- include/segments.h (revision 374) +++ include/segments.h (working copy) @@ -169,9 +169,9 @@ extern struct gate_descriptor *idt; void setgate(struct gate_descriptor *, void *, int, int, int, int); void setregion(struct region_descriptor *, void *, size_t); -void setsegment(struct segment_descriptor *, void *, size_t, int, int, +void setsegment(struct segment_descriptor *, const void *, size_t, int, int, int, int); -void setgdt(int, void *, size_t, int, int, int, int); +void setgdt(int, const void *, size_t, int, int, int, int); void unsetgate(struct gate_descriptor *); void cpu_init_idt(void); Index: include/cpu.h =================================================================== --- include/cpu.h (revision 374) +++ include/cpu.h (working copy) @@ -62,6 +62,15 @@ struct intrsource; +#define NIOPORTS 1024 /* # of ports we allow to be mapped */ +#define IOMAPSIZE (NIOPORTS / 8) /* I/O bitmap size in bytes */ + +/* + * I/O bitmap offset beyond TSS's segment limit means no bitmaps. + * (i.e. any I/O attempt generates an exception.) + */ +#define IOMAP_INVALOFF 0xffff + /* * a bunch of this belongs in cpuvar.h; move it later.. */ @@ -94,7 +103,6 @@ struct cpu_info { struct pcb *ci_curpcb; /* VA of current HW PCB */ struct pcb *ci_idle_pcb; /* VA of current PCB */ - int ci_idle_tss_sel; /* TSS selector of idle PCB */ struct intrsource *ci_isources[MAX_INTR_SOURCES]; u_int32_t ci_ipending; @@ -129,6 +137,13 @@ struct cpu_info { u_int ci_cflush_lsize; /* CFLUSH insn line size */ struct x86_cache_info ci_cinfo[CAI_COUNT]; + struct i386tss ci_tss; /* Per-cpu TSS; shared among processes*/ + char ci_iomap[IOMAPSIZE]; /* I/O Bitmap */ + int ci_tss_sel; /* TSS selector of this cpu */ +#define ci_esp0 ci_tss.tss_esp0 +#define ci_ss0 ci_tss.tss_ss0 +#define ci_ioopt ci_tss.tss_ioopt + /* * Variables used by cc_microtime(). */ @@ -347,9 +362,9 @@ extern int i386_has_sse2; /* machdep.c */ void dumpconf(void); -int cpu_maxproc(void); void cpu_reset(void); -void i386_init_pcb_tss_ldt(struct cpu_info *); +void i386_init_idle_pcb(struct cpu_info *); +void i386_init_tss(struct cpu_info *); void i386_proc0_tss_ldt_init(void); void i386_bufinit(void); Index: include/proc.h =================================================================== --- include/proc.h (revision 374) +++ include/proc.h (working copy) @@ -46,7 +46,6 @@ struct mdlwp { struct trapframe *md_regs; /* registers on current frame */ int md_flags; /* machine-dependent flags */ - int md_tss_sel; /* TSS selector */ }; /* md_flags */ Index: i386/vm_machdep.c =================================================================== --- i386/vm_machdep.c (revision 374) +++ i386/vm_machdep.c (working copy) @@ -172,24 +172,14 @@ cpu_lwp_fork(l1, l2, stack, stacksize, f *pcb = l1->l_addr->u_pcb; /* - * Preset these so that gdt_compact() doesn't get confused if called - * during the allocations below. - * - * Note: pcb_ldt_sel is handled in the pmap_activate() call when - * we run the new process. + * Fix up the ring0 esp. */ - l2->l_md.md_tss_sel = GSEL(GNULL_SEL, SEL_KPL); - - /* Fix up the TSS. */ - pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); - pcb->pcb_tss.tss_esp0 = (int)l2->l_addr + USPACE - 16; - - l2->l_md.md_tss_sel = tss_alloc(pcb); + pcb->pcb_esp0 = (int)l2->l_addr + USPACE - 16; /* * Copy the trapframe. */ - l2->l_md.md_regs = tf = (struct trapframe *)pcb->pcb_tss.tss_esp0 - 1; + l2->l_md.md_regs = tf = (struct trapframe *)pcb->pcb_esp0 - 1; *tf = *l1->l_md.md_regs; #ifndef NOREDZONE @@ -207,6 +197,7 @@ cpu_lwp_fork(l1, l2, stack, stacksize, f sf->sf_eip = (int)proc_trampoline; pcb->pcb_esp = (int)sf; pcb->pcb_ebp = 0; + pcb->pcb_iomap = NULL; } void @@ -300,9 +291,10 @@ void cpu_wait(l) struct lwp *l; { + struct pcb *pcb = &l->l_addr->u_pcb; - /* Nuke the TSS. */ - tss_free(l->l_md.md_tss_sel); + if (pcb->pcb_iomap) + free(pcb->pcb_iomap, M_DEVBUF); } /* Index: i386/gdt.c =================================================================== --- i386/gdt.c (revision 182) +++ i386/gdt.c (working copy) @@ -89,7 +89,7 @@ gdt_unlock() } void -setgdt(int sel, void *base, size_t limit, +setgdt(int sel, const void *base, size_t limit, int type, int dpl, int def32, int gran) { struct segment_descriptor *sd = &gdt[sel].sd; @@ -274,12 +274,12 @@ gdt_put_slot(int slot) } int -tss_alloc(struct pcb *pcb) +tss_alloc(const struct i386tss *tss) { int slot; slot = gdt_get_slot(); - setgdt(slot, &pcb->pcb_tss, sizeof(struct pcb) - 1, + setgdt(slot, tss, sizeof(struct i386tss) + IOMAPSIZE - 1, SDT_SYS386TSS, SEL_KPL, 0, 0); return GSEL(slot, SEL_KPL); } Index: i386/cpu.c =================================================================== --- i386/cpu.c (revision 374) +++ i386/cpu.c (working copy) @@ -309,16 +309,9 @@ cpu_attach(parent, self, aux) pcb = ci->ci_idle_pcb = (struct pcb *) kstack; memset(pcb, 0, USPACE); - pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); - pcb->pcb_tss.tss_esp0 = - kstack + USPACE - 16 - sizeof (struct trapframe); - pcb->pcb_tss.tss_esp = - kstack + USPACE - 16 - sizeof (struct trapframe); pcb->pcb_pmap = pmap_kernel(); - pcb->pcb_cr0 = rcr0(); - pcb->pcb_cr3 = pcb->pcb_pmap->pm_pdirpa; + i386_init_idle_pcb(ci); #endif - /* further PCB init done later. */ printf(": "); @@ -495,6 +488,9 @@ cpu_boot_secondary_processors() } } +/* + * called by BP. + */ void cpu_init_idle_pcbs() { @@ -509,7 +505,8 @@ cpu_init_idle_pcbs() continue; if ((ci->ci_flags & CPUF_PRESENT) == 0) continue; - i386_init_pcb_tss_ldt(ci); + i386_init_idle_pcb(ci); + i386_init_tss(ci); } } @@ -608,8 +605,7 @@ cpu_hatch(void *v) lapic_set_lvt(); gdt_init_cpu(ci); npxinit(ci); - - lldt(GSEL(GLDT_SEL, SEL_KPL)); + ltr(ci->ci_tss_sel); cpu_init(ci); Index: i386/pmap.c =================================================================== --- i386/pmap.c (revision 413) +++ i386/pmap.c (working copy) @@ -738,9 +738,8 @@ pmap_exec_account(struct pmap *pm, vaddr if ((opte & PG_X) && (npte & PG_X) == 0 && va == pm->pm_hiexec) { struct trapframe *tf = curlwp->l_md.md_regs; - struct pcb *pcb = &curlwp->l_addr->u_pcb; - pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); + tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); pm->pm_hiexec = I386_MAX_EXE_ADDR; } } @@ -774,9 +773,9 @@ pmap_exec_fixup(struct vm_map *map, stru pm->pm_hiexec = va; if (pm->pm_hiexec > I386_MAX_EXE_ADDR) { - pcb->pcb_cs = tf->tf_cs = GSEL(GUCODEBIG_SEL, SEL_UPL); + tf->tf_cs = GSEL(GUCODEBIG_SEL, SEL_UPL); } else { - pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); + tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); } return (1); } Index: i386/sys_machdep.c =================================================================== --- i386/sys_machdep.c (revision 374) +++ i386/sys_machdep.c (working copy) @@ -378,11 +378,16 @@ i386_get_ioperm(l, args, retval) int error; struct pcb *pcb = &l->l_addr->u_pcb; struct i386_get_ioperm_args ua; + char dummymap[IOMAPSIZE]; if ((error = copyin(args, &ua, sizeof(ua))) != 0) return (error); - return copyout(pcb->pcb_iomap, ua.iomap, sizeof(pcb->pcb_iomap)); + if (pcb->pcb_iomap) + return copyout(pcb->pcb_iomap, ua.iomap, IOMAPSIZE); + + memset(dummymap, 0xff, sizeof(dummymap)); + return copyout(dummymap, ua.iomap, sizeof(dummymap)); } int @@ -395,6 +400,7 @@ i386_set_ioperm(l, args, retval) struct proc *p = l->l_proc; struct pcb *pcb = &l->l_addr->u_pcb; struct i386_set_ioperm_args ua; + struct cpu_info *ci; if (securelevel > 1) return EPERM; @@ -403,9 +409,26 @@ i386_set_ioperm(l, args, retval) return error; if ((error = copyin(args, &ua, sizeof(ua))) != 0) - return (error); + return error; - return copyin(ua.iomap, pcb->pcb_iomap, sizeof(pcb->pcb_iomap)); + if (pcb->pcb_iomap == NULL) + pcb->pcb_iomap = malloc(IOMAPSIZE, M_DEVBUF, M_WAITOK); + + if ((error = copyin(ua.iomap, pcb->pcb_iomap, IOMAPSIZE)) != 0) + goto fail; + + /* + * make it effective immediately. + */ + ci = curcpu(); + memcpy(ci->ci_iomap, pcb->pcb_iomap, sizeof(ci->ci_iomap)); + ci->ci_ioopt = ((caddr_t)ci->ci_iomap - (caddr_t)&ci->ci_tss) << 16; + + return 0; +fail: + free(pcb->pcb_iomap, M_DEVBUF); + pcb->pcb_iomap = NULL; + return error; } #ifdef MTRR Index: i386/machdep.c =================================================================== --- i386/machdep.c (revision 390) +++ i386/machdep.c (working copy) @@ -396,49 +396,60 @@ void i386_proc0_tss_ldt_init() { struct pcb *pcb; - int x; gdt_init(); cpu_info_primary.ci_curpcb = pcb = &lwp0.l_addr->u_pcb; - pcb->pcb_tss.tss_ioopt = - ((caddr_t)pcb->pcb_iomap - (caddr_t)&pcb->pcb_tss) << 16; - - for (x = 0; x < sizeof(pcb->pcb_iomap) / 4; x++) - pcb->pcb_iomap[x] = 0xffffffff; - pcb->pcb_ldt_sel = pmap_kernel()->pm_ldt_sel = GSEL(GLDT_SEL, SEL_KPL); pcb->pcb_cr0 = rcr0(); - pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); - pcb->pcb_tss.tss_esp0 = (int)lwp0.l_addr + USPACE - 16; - lwp0.l_md.md_regs = (struct trapframe *)pcb->pcb_tss.tss_esp0 - 1; - lwp0.l_md.md_tss_sel = tss_alloc(pcb); + pcb->pcb_esp0 = (int)lwp0.l_addr + USPACE - 16; + pcb->pcb_iomap = NULL; + lwp0.l_md.md_regs = (struct trapframe *)pcb->pcb_esp0 - 1; - ltr(lwp0.l_md.md_tss_sel); lldt(pcb->pcb_ldt_sel); } +#ifdef MULTIPROCESSOR /* - * Set up TSS and LDT for a new PCB. + * Set up cpu's idle pcb. + * + * XXX this is called twice, + * once from cpu_attach and once from cpu_init_idle_pcbs. */ void -i386_init_pcb_tss_ldt(ci) +i386_init_idle_pcb(ci) struct cpu_info *ci; { - int x; struct pcb *pcb = ci->ci_idle_pcb; - pcb->pcb_tss.tss_ioopt = - ((caddr_t)pcb->pcb_iomap - (caddr_t)&pcb->pcb_tss) << 16; - for (x = 0; x < sizeof(pcb->pcb_iomap) / 4; x++) - pcb->pcb_iomap[x] = 0xffffffff; - - pcb->pcb_ldt_sel = pmap_kernel()->pm_ldt_sel = GSEL(GLDT_SEL, SEL_KPL); + /* Set up idle PCB */ + pcb->pcb_ldt_sel = -1; + pcb->pcb_iomap = NULL; pcb->pcb_cr0 = rcr0(); + pcb->pcb_cr3 = pcb->pcb_pmap->pm_pdirpa; + /* mptramp needs esp */ + pcb->pcb_esp = (int)pcb + USPACE - 16 - sizeof(struct trapframe); +} +#endif /* MULTIPROCESSOR */ + +/* + * Set up cpu's TSS. + */ + +void +i386_init_tss(ci) + struct cpu_info *ci; +{ + struct i386tss *tss = &ci->ci_tss; - ci->ci_idle_tss_sel = tss_alloc(pcb); + /* + * Set up shared TSS and I/O bitmap + */ + tss->tss_ioopt = IOMAP_INVALOFF << 16; + tss->tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); + ci->ci_tss_sel = tss_alloc(tss); } /* @@ -1213,7 +1224,7 @@ setregion(rd, base, limit) void setsegment(sd, base, limit, type, dpl, def32, gran) struct segment_descriptor *sd; - void *base; + const void *base; size_t limit; int type, dpl, def32, gran; { @@ -2365,16 +2376,3 @@ idt_vec_free(vec) idt_allocmap[vec] = 0; simple_unlock(&idt_lock); } - -/* - * Number of processes is limited by number of available GDT slots. - */ -int -cpu_maxproc(void) -{ -#ifdef USER_LDT - return ((MAXGDTSIZ - NGDT) / 2); -#else - return (MAXGDTSIZ - NGDT); -#endif -} Index: i386/locore.S =================================================================== --- i386/locore.S (revision 413) +++ i386/locore.S (working copy) @@ -1736,10 +1736,8 @@ ENTRY(cpu_switch) #ifndef MULTIPROCESSOR movl $_C_LABEL(lwp0),%ebx movl L_ADDR(%ebx),%edi - movl L_MD_TSS_SEL(%ebx),%edx #else movl CPUVAR(IDLE_PCB),%edi - movl CPUVAR(IDLE_TSS_SEL),%edx #endif movl $0,CPUVAR(CURLWP) /* In case we fault... */ @@ -1750,21 +1748,15 @@ ENTRY(cpu_switch) movl PCB_ESP(%edi),%esp movl PCB_EBP(%edi),%ebp - /* Switch address space. */ movl PCB_CR3(%edi),%ecx movl %ecx,%cr3 - /* Switch TSS. Reset "task busy" flag before loading. */ -#ifdef MULTIPROCESSOR - movl CPUVAR(GDT),%eax -#else - movl _C_LABEL(gdt),%eax -#endif - andl $~0x0200,4-SEL_KPL(%eax,%edx,1) - ltr %dx - - /* We're always in the kernel, so we don't need the LDT. */ + /* + * We're always in the kernel, so + * - we don't need the LDT. + * - we don't need to update TSS. + */ /* Restore cr0 (including FPU state). */ movl PCB_CR0(%edi),%ecx @@ -1892,9 +1884,42 @@ switch_exited: * %edi - new lwp */ + movl L_ADDR(%edi),%esi + + /* + * Switch I/O bitmap. + * + */ + movl PCB_IOMAP(%esi),%eax + orl %eax,%eax + jnz switch_hasiomap + + /* + * no I/O bitmap. + * just use invalid offset. + */ + movl $(IOMAP_INVALOFF << 16),CPUVAR(IOOPT) + jmp switch_iomap_restored + +switch_hasiomap: + /* + * XXX copying bitmap here might be slow. + */ + movl $(IOMAPSIZE/4),%ecx + pushl %esi + pushl %edi + movl %eax,%esi /* pcb_iomap */ + movl CPUVAR(SELF),%edi + leal CPU_INFO_IOMAP(%edi),%edi + rep + movsl + popl %edi + popl %esi + movl $((CPU_INFO_IOMAP - CPU_INFO_TSS) << 16),CPUVAR(IOOPT) + +switch_iomap_restored: /* No interrupts while loading new state. */ cli - movl L_ADDR(%edi),%esi /* Restore stack pointers. */ movl PCB_ESP(%esi),%esp @@ -1906,17 +1931,9 @@ switch_exited: jnz switch_restored #endif -#ifdef MULTIPROCESSOR - movl CPUVAR(GDT),%eax -#else - /* Load TSS info. */ - movl _C_LABEL(gdt),%eax -#endif - movl L_MD_TSS_SEL(%edi),%edx - - /* Switch TSS. Reset "task busy" flag before loading. */ - andl $~0x0200,4(%eax,%edx, 1) - ltr %dx + /* Switch ring0 esp in shared TSS */ + movl PCB_ESP0(%esi),%eax + movl %eax,CPUVAR(ESP0) pushl %edi call _C_LABEL(pmap_activate) # pmap_activate(p) @@ -2045,10 +2062,8 @@ ENTRY(switch_exit) #ifndef MULTIPROCESSOR movl $_C_LABEL(lwp0),%ebx movl L_ADDR(%ebx),%esi - movl L_MD_TSS_SEL(%ebx),%edx #else movl CPUVAR(IDLE_PCB),%esi - movl CPUVAR(IDLE_TSS_SEL),%edx #endif /* In case we fault... */ movl $0,CPUVAR(CURLWP) @@ -2063,23 +2078,15 @@ ENTRY(switch_exit) /* Save exit func. */ pushl %eax - /* Load TSS info. */ -#ifdef MULTIPROCESSOR - movl CPUVAR(GDT),%eax -#else - /* Load TSS info. */ - movl _C_LABEL(gdt),%eax -#endif - /* Switch address space. */ movl PCB_CR3(%esi),%ecx movl %ecx,%cr3 - /* Switch TSS. */ - andl $~0x0200,4-SEL_KPL(%eax,%edx,1) - ltr %dx - - /* We're always in the kernel, so we don't need the LDT. */ + /* + * We're always in the kernel, so + * - we don't need the LDT. + * - we don't need to update TSS. + */ /* Restore cr0 (including FPU state). */ movl PCB_CR0(%esi),%ecx Index: i386/autoconf.c =================================================================== --- i386/autoconf.c (revision 374) +++ i386/autoconf.c (working copy) @@ -145,12 +145,17 @@ cpu_configure(void) #endif /* resync cr0 after FPU configuration */ lwp0.l_addr->u_pcb.pcb_cr0 = rcr0(); + #ifdef MULTIPROCESSOR /* propagate this to the idle pcb's. */ cpu_init_idle_pcbs(); -#endif +#else /* MULTIPROCESSOR */ + i386_init_tss(&cpu_info_primary); +#endif /* MULTIPROCESSOR */ spl0(); + + ltr(cpu_info_primary.ci_tss_sel); #if NLAPIC > 0 lapic_tpr = 0; #endif Index: i386/genassym.cf =================================================================== --- i386/genassym.cf (revision 413) +++ i386/genassym.cf (working copy) @@ -152,6 +152,8 @@ define PDSLOT_KERN PDSLOT_KERN define NKPTP_MIN NKPTP_MIN define NKPTP_MAX NKPTP_MAX +define IOMAPSIZE IOMAPSIZE + define VM_MAXUSER_ADDRESS (int)VM_MAXUSER_ADDRESS define UVM_PAGE_IDLE_ZERO offsetof(struct uvm, page_idle_zero) @@ -163,7 +165,6 @@ define L_PRIORITY offsetof(struct lwp, define L_STAT offsetof(struct lwp, l_stat) define L_WCHAN offsetof(struct lwp, l_wchan) define L_PROC offsetof(struct lwp, l_proc) -define L_MD_TSS_SEL offsetof(struct lwp, l_md.md_tss_sel) define L_MD_REGS offsetof(struct lwp, l_md.md_regs) define L_CPU offsetof(struct lwp, l_cpu) define P_FLAG offsetof(struct proc, p_flag) @@ -189,10 +190,12 @@ define V_INTR offsetof(struct uvmexp, define PCB_CR3 offsetof(struct pcb, pcb_cr3) define PCB_EBP offsetof(struct pcb, pcb_ebp) define PCB_ESP offsetof(struct pcb, pcb_esp) +define PCB_ESP0 offsetof(struct pcb, pcb_esp0) define PCB_CR0 offsetof(struct pcb, pcb_cr0) define PCB_LDT_SEL offsetof(struct pcb, pcb_ldt_sel) define PCB_ONFAULT offsetof(struct pcb, pcb_onfault) define PCB_FPCPU offsetof(struct pcb, pcb_fpcpu) +define PCB_IOMAP offsetof(struct pcb, pcb_iomap) define TF_CS offsetof(struct trapframe, tf_cs) define TF_EIP offsetof(struct trapframe, tf_eip) @@ -261,8 +264,12 @@ define CPU_INFO_RESCHED offsetof(struct define CPU_INFO_CURLWP offsetof(struct cpu_info, ci_curlwp) define CPU_INFO_CURPCB offsetof(struct cpu_info, ci_curpcb) define CPU_INFO_IDLE_PCB offsetof(struct cpu_info, ci_idle_pcb) -define CPU_INFO_IDLE_TSS_SEL offsetof(struct cpu_info, ci_idle_tss_sel) define CPU_INFO_ASTPENDING offsetof(struct cpu_info, ci_astpending) +define CPU_INFO_ESP0 offsetof(struct cpu_info, ci_esp0) +define CPU_INFO_TSS offsetof(struct cpu_info, ci_tss) +define CPU_INFO_IOMAP offsetof(struct cpu_info, ci_iomap) +define CPU_INFO_IOOPT offsetof(struct cpu_info, ci_ioopt) +define IOMAP_INVALOFF IOMAP_INVALOFF define CPU_INFO_LEVEL offsetof(struct cpu_info, ci_cpuid_level) define CPU_INFO_VENDOR offsetof(struct cpu_info, ci_vendor[0])