Changeset View
Changeset View
Standalone View
Standalone View
sys/i386/i386/machdep.c
/*- | /*- | ||||
* SPDX-License-Identifier: BSD-4-Clause | * SPDX-License-Identifier: BSD-4-Clause | ||||
* | * | ||||
* Copyright (c) 2018 The FreeBSD Foundation | |||||
emaste: For cases where there is already a 4-clause license I think we should add a new 2-clause… | |||||
* Copyright (c) 1992 Terrence R. Lambert. | * Copyright (c) 1992 Terrence R. Lambert. | ||||
* Copyright (c) 1982, 1987, 1990 The Regents of the University of California. | * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. | ||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* This code is derived from software contributed to Berkeley by | * This code is derived from software contributed to Berkeley by | ||||
* William Jolitz. | * William Jolitz. | ||||
* | * | ||||
* Portions of this software were developed by A. Joseph Koshy under | |||||
* sponsorship from the FreeBSD Foundation and Google, Inc. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
* notice, this list of conditions and the following disclaimer in the | * notice, this list of conditions and the following disclaimer in the | ||||
* documentation and/or other materials provided with the distribution. | * documentation and/or other materials provided with the distribution. | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
#include <sys/msgbuf.h> | #include <sys/msgbuf.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/pcpu.h> | #include <sys/pcpu.h> | ||||
#include <sys/ptrace.h> | #include <sys/ptrace.h> | ||||
#include <sys/reboot.h> | #include <sys/reboot.h> | ||||
#include <sys/rwlock.h> | #include <sys/rwlock.h> | ||||
#include <sys/sched.h> | #include <sys/sched.h> | ||||
#include <sys/signalvar.h> | #include <sys/signalvar.h> | ||||
#ifdef SMP | |||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#endif | |||||
#include <sys/syscallsubr.h> | #include <sys/syscallsubr.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/sysent.h> | #include <sys/sysent.h> | ||||
#include <sys/sysproto.h> | #include <sys/sysproto.h> | ||||
#include <sys/ucontext.h> | #include <sys/ucontext.h> | ||||
#include <sys/vmmeter.h> | #include <sys/vmmeter.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
Show All 28 Lines | |||||
#include <machine/mp_watchdog.h> | #include <machine/mp_watchdog.h> | ||||
#include <machine/pc/bios.h> | #include <machine/pc/bios.h> | ||||
#include <machine/pcb.h> | #include <machine/pcb.h> | ||||
#include <machine/pcb_ext.h> | #include <machine/pcb_ext.h> | ||||
#include <machine/proc.h> | #include <machine/proc.h> | ||||
#include <machine/reg.h> | #include <machine/reg.h> | ||||
#include <machine/sigframe.h> | #include <machine/sigframe.h> | ||||
#include <machine/specialreg.h> | #include <machine/specialreg.h> | ||||
#include <machine/sysarch.h> | |||||
#include <machine/vm86.h> | #include <machine/vm86.h> | ||||
#include <x86/init.h> | #include <x86/init.h> | ||||
#ifdef PERFMON | #ifdef PERFMON | ||||
#include <machine/perfmon.h> | #include <machine/perfmon.h> | ||||
#endif | #endif | ||||
#ifdef SMP | #ifdef SMP | ||||
#include <machine/smp.h> | #include <machine/smp.h> | ||||
#endif | #endif | ||||
#ifdef FDT | #ifdef FDT | ||||
#include <x86/fdt.h> | #include <x86/fdt.h> | ||||
#endif | #endif | ||||
#ifdef DEV_APIC | #ifdef DEV_APIC | ||||
#include <x86/apicvar.h> | #include <x86/apicvar.h> | ||||
#endif | #endif | ||||
#ifdef DEV_ISA | #ifdef DEV_ISA | ||||
#include <x86/isa/icu.h> | #include <x86/isa/icu.h> | ||||
#endif | #endif | ||||
/* Sanity check for __curthread() */ | /* Sanity check for __curthread() */ | ||||
CTASSERT(offsetof(struct pcpu, pc_curthread) == 0); | CTASSERT(offsetof(struct pcpu, pc_curthread) == 0); | ||||
extern register_t init386(int first); | register_t init386(int first); | ||||
extern void dblfault_handler(void); | void dblfault_handler(void); | ||||
static void cpu_startup(void *); | static void cpu_startup(void *); | ||||
static void fpstate_drop(struct thread *td); | static void fpstate_drop(struct thread *td); | ||||
static void get_fpcontext(struct thread *td, mcontext_t *mcp, | static void get_fpcontext(struct thread *td, mcontext_t *mcp, | ||||
char *xfpusave, size_t xfpusave_len); | char *xfpusave, size_t xfpusave_len); | ||||
static int set_fpcontext(struct thread *td, mcontext_t *mcp, | static int set_fpcontext(struct thread *td, mcontext_t *mcp, | ||||
char *xfpustate, size_t xfpustate_len); | char *xfpustate, size_t xfpustate_len); | ||||
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); | SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); | ||||
Show All 40 Lines | |||||
static struct trapframe proc0_tf; | static struct trapframe proc0_tf; | ||||
struct pcpu __pcpu[MAXCPU]; | struct pcpu __pcpu[MAXCPU]; | ||||
struct mtx icu_lock; | struct mtx icu_lock; | ||||
struct mem_range_softc mem_range_softc; | struct mem_range_softc mem_range_softc; | ||||
extern char start_exceptions[], end_exceptions[]; | |||||
extern struct sysentvec elf32_freebsd_sysvec; | |||||
/* Default init_ops implementation. */ | /* Default init_ops implementation. */ | ||||
struct init_ops init_ops = { | struct init_ops init_ops = { | ||||
.early_clock_source_init = i8254_init, | .early_clock_source_init = i8254_init, | ||||
.early_delay = i8254_delay, | .early_delay = i8254_delay, | ||||
#ifdef DEV_APIC | #ifdef DEV_APIC | ||||
.msi_init = msi_init, | .msi_init = msi_init, | ||||
#endif | #endif | ||||
}; | }; | ||||
static void | static void | ||||
cpu_startup(dummy) | cpu_startup(dummy) | ||||
void *dummy; | void *dummy; | ||||
{ | { | ||||
uintmax_t memsize; | uintmax_t memsize; | ||||
char *sysenv; | char *sysenv; | ||||
▲ Show 20 Lines • Show All 864 Lines • ▼ Show 20 Lines | #if defined(COMPAT_43) | ||||
else | else | ||||
td->td_sigstk.ss_flags &= ~SS_ONSTACK; | td->td_sigstk.ss_flags &= ~SS_ONSTACK; | ||||
#endif | #endif | ||||
kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0); | kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0); | ||||
return (EJUSTRETURN); | return (EJUSTRETURN); | ||||
} | } | ||||
#ifdef COMPAT_43 | |||||
static void | |||||
setup_priv_lcall_gate(struct proc *p) | |||||
{ | |||||
struct i386_ldt_args uap; | |||||
union descriptor desc; | |||||
u_int lcall_addr; | |||||
bzero(&uap, sizeof(uap)); | |||||
uap.start = 0; | |||||
uap.num = 1; | |||||
lcall_addr = p->p_sysent->sv_psstrings - sz_lcall_tramp; | |||||
bzero(&desc, sizeof(desc)); | |||||
desc.sd.sd_type = SDT_MEMERA; | |||||
desc.sd.sd_dpl = SEL_UPL; | |||||
desc.sd.sd_p = 1; | |||||
desc.sd.sd_def32 = 1; | |||||
desc.sd.sd_gran = 1; | |||||
desc.sd.sd_lolimit = 0xffff; | |||||
desc.sd.sd_hilimit = 0xf; | |||||
desc.sd.sd_lobase = lcall_addr; | |||||
desc.sd.sd_hibase = lcall_addr >> 24; | |||||
i386_set_ldt(curthread, &uap, &desc); | |||||
} | |||||
#endif | |||||
/* | /* | ||||
* Reset registers to default values on exec. | * Reset registers to default values on exec. | ||||
*/ | */ | ||||
void | void | ||||
exec_setregs(struct thread *td, struct image_params *imgp, u_long stack) | exec_setregs(struct thread *td, struct image_params *imgp, u_long stack) | ||||
{ | { | ||||
struct trapframe *regs = td->td_frame; | struct trapframe *regs; | ||||
struct pcb *pcb = td->td_pcb; | struct pcb *pcb; | ||||
regs = td->td_frame; | |||||
pcb = td->td_pcb; | |||||
/* Reset pc->pcb_gs and %gs before possibly invalidating it. */ | /* Reset pc->pcb_gs and %gs before possibly invalidating it. */ | ||||
pcb->pcb_gs = _udatasel; | pcb->pcb_gs = _udatasel; | ||||
load_gs(_udatasel); | load_gs(_udatasel); | ||||
mtx_lock_spin(&dt_lock); | mtx_lock_spin(&dt_lock); | ||||
if (td->td_proc->p_md.md_ldt) | if (td->td_proc->p_md.md_ldt != NULL) | ||||
user_ldt_free(td); | user_ldt_free(td); | ||||
else | else | ||||
mtx_unlock_spin(&dt_lock); | mtx_unlock_spin(&dt_lock); | ||||
#ifdef COMPAT_43 | |||||
if (td->td_proc->p_sysent->sv_psstrings != | |||||
elf32_freebsd_sysvec.sv_psstrings) | |||||
setup_priv_lcall_gate(td->td_proc); | |||||
#endif | |||||
/* | /* | ||||
* Reset the fs and gs bases. The values from the old address | * Reset the fs and gs bases. The values from the old address | ||||
* space do not make sense for the new program. In particular, | * space do not make sense for the new program. In particular, | ||||
* gsbase might be the TLS base for the old program but the new | * gsbase might be the TLS base for the old program but the new | ||||
* program has no TLS now. | * program has no TLS now. | ||||
*/ | */ | ||||
set_fsbase(td, 0); | set_fsbase(td, 0); | ||||
set_gsbase(td, 0); | set_gsbase(td, 0); | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
/* | /* | ||||
* Initialize segments & interrupt table | * Initialize segments & interrupt table | ||||
*/ | */ | ||||
int _default_ldt; | int _default_ldt; | ||||
union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */ | struct mtx dt_lock; /* lock for GDT and LDT */ | ||||
union descriptor ldt[NLDT]; /* local descriptor table */ | |||||
union descriptor gdt0[NGDT]; /* initial global descriptor table */ | |||||
union descriptor *gdt = gdt0; /* global descriptor table */ | |||||
union descriptor *ldt; /* local descriptor table */ | |||||
static struct gate_descriptor idt0[NIDT]; | static struct gate_descriptor idt0[NIDT]; | ||||
struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ | struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ | ||||
struct region_descriptor r_gdt, r_idt; /* table descriptors */ | |||||
struct mtx dt_lock; /* lock for GDT and LDT */ | |||||
static struct i386tss dblfault_tss; | static struct i386tss *dblfault_tss; | ||||
static char dblfault_stack[PAGE_SIZE]; | static char *dblfault_stack; | ||||
extern vm_offset_t proc0kstack; | static struct i386tss common_tss0; | ||||
vm_offset_t proc0kstack; | |||||
/* | /* | ||||
* software prototypes -- in more palatable form. | * software prototypes -- in more palatable form. | ||||
* | * | ||||
* GCODE_SEL through GUDATA_SEL must be in this order for syscall/sysret | * GCODE_SEL through GUDATA_SEL must be in this order for syscall/sysret | ||||
* GUFS_SEL and GUGS_SEL must be in this order (swtch.s knows it) | * GUFS_SEL and GUGS_SEL must be in this order (swtch.s knows it) | ||||
*/ | */ | ||||
struct soft_segment_descriptor gdt_segs[] = { | struct soft_segment_descriptor gdt_segs[] = { | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | /* GPROC0_SEL 9 Proc 0 Tss Descriptor */ | ||||
.ssd_limit = sizeof(struct i386tss)-1, | .ssd_limit = sizeof(struct i386tss)-1, | ||||
.ssd_type = SDT_SYS386TSS, | .ssd_type = SDT_SYS386TSS, | ||||
.ssd_dpl = 0, | .ssd_dpl = 0, | ||||
.ssd_p = 1, | .ssd_p = 1, | ||||
.ssd_xx = 0, .ssd_xx1 = 0, | .ssd_xx = 0, .ssd_xx1 = 0, | ||||
.ssd_def32 = 0, | .ssd_def32 = 0, | ||||
.ssd_gran = 0 }, | .ssd_gran = 0 }, | ||||
/* GLDT_SEL 10 LDT Descriptor */ | /* GLDT_SEL 10 LDT Descriptor */ | ||||
{ .ssd_base = (int) ldt, | { .ssd_base = 0, | ||||
.ssd_limit = sizeof(ldt)-1, | .ssd_limit = sizeof(union descriptor) * NLDT - 1, | ||||
.ssd_type = SDT_SYSLDT, | .ssd_type = SDT_SYSLDT, | ||||
.ssd_dpl = SEL_UPL, | .ssd_dpl = SEL_UPL, | ||||
.ssd_p = 1, | .ssd_p = 1, | ||||
.ssd_xx = 0, .ssd_xx1 = 0, | .ssd_xx = 0, .ssd_xx1 = 0, | ||||
.ssd_def32 = 0, | .ssd_def32 = 0, | ||||
.ssd_gran = 0 }, | .ssd_gran = 0 }, | ||||
/* GUSERLDT_SEL 11 User LDT Descriptor per process */ | /* GUSERLDT_SEL 11 User LDT Descriptor per process */ | ||||
{ .ssd_base = (int) ldt, | { .ssd_base = 0, | ||||
.ssd_limit = (512 * sizeof(union descriptor)-1), | .ssd_limit = (512 * sizeof(union descriptor)-1), | ||||
.ssd_type = SDT_SYSLDT, | .ssd_type = SDT_SYSLDT, | ||||
.ssd_dpl = 0, | .ssd_dpl = 0, | ||||
.ssd_p = 1, | .ssd_p = 1, | ||||
.ssd_xx = 0, .ssd_xx1 = 0, | .ssd_xx = 0, .ssd_xx1 = 0, | ||||
.ssd_def32 = 0, | .ssd_def32 = 0, | ||||
.ssd_gran = 0 }, | .ssd_gran = 0 }, | ||||
/* GPANIC_SEL 12 Panic Tss Descriptor */ | /* GPANIC_SEL 12 Panic Tss Descriptor */ | ||||
{ .ssd_base = (int) &dblfault_tss, | { .ssd_base = 0, | ||||
.ssd_limit = sizeof(struct i386tss)-1, | .ssd_limit = sizeof(struct i386tss)-1, | ||||
.ssd_type = SDT_SYS386TSS, | .ssd_type = SDT_SYS386TSS, | ||||
.ssd_dpl = 0, | .ssd_dpl = 0, | ||||
.ssd_p = 1, | .ssd_p = 1, | ||||
.ssd_xx = 0, .ssd_xx1 = 0, | .ssd_xx = 0, .ssd_xx1 = 0, | ||||
.ssd_def32 = 0, | .ssd_def32 = 0, | ||||
.ssd_gran = 0 }, | .ssd_gran = 0 }, | ||||
/* GBIOSCODE32_SEL 13 BIOS 32-bit interface (32bit Code) */ | /* GBIOSCODE32_SEL 13 BIOS 32-bit interface (32bit Code) */ | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | static struct soft_segment_descriptor ldt_segs[] = { | ||||
.ssd_type = SDT_MEMRWA, | .ssd_type = SDT_MEMRWA, | ||||
.ssd_dpl = SEL_UPL, | .ssd_dpl = SEL_UPL, | ||||
.ssd_p = 1, | .ssd_p = 1, | ||||
.ssd_xx = 0, .ssd_xx1 = 0, | .ssd_xx = 0, .ssd_xx1 = 0, | ||||
.ssd_def32 = 1, | .ssd_def32 = 1, | ||||
.ssd_gran = 1 }, | .ssd_gran = 1 }, | ||||
}; | }; | ||||
uintptr_t setidt_disp; | |||||
void | void | ||||
setidt(idx, func, typ, dpl, selec) | setidt(int idx, inthand_t *func, int typ, int dpl, int selec) | ||||
int idx; | |||||
inthand_t *func; | |||||
int typ; | |||||
int dpl; | |||||
int selec; | |||||
{ | { | ||||
uintptr_t off; | |||||
off = func != NULL ? (uintptr_t)func + setidt_disp : 0; | |||||
setidt_nodisp(idx, off, typ, dpl, selec); | |||||
} | |||||
void | |||||
setidt_nodisp(int idx, uintptr_t off, int typ, int dpl, int selec) | |||||
{ | |||||
struct gate_descriptor *ip; | struct gate_descriptor *ip; | ||||
ip = idt + idx; | ip = idt + idx; | ||||
ip->gd_looffset = (int)func; | ip->gd_looffset = off; | ||||
ip->gd_selector = selec; | ip->gd_selector = selec; | ||||
ip->gd_stkcpy = 0; | ip->gd_stkcpy = 0; | ||||
ip->gd_xx = 0; | ip->gd_xx = 0; | ||||
ip->gd_type = typ; | ip->gd_type = typ; | ||||
ip->gd_dpl = dpl; | ip->gd_dpl = dpl; | ||||
ip->gd_p = 1; | ip->gd_p = 1; | ||||
ip->gd_hioffset = ((int)func)>>16 ; | ip->gd_hioffset = ((u_int)off) >> 16 ; | ||||
} | } | ||||
extern inthand_t | extern inthand_t | ||||
IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), | IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), | ||||
IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm), | IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm), | ||||
IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), | IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), | ||||
IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), | IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), | ||||
IDTVEC(xmm), | IDTVEC(xmm), | ||||
#ifdef KDTRACE_HOOKS | #ifdef KDTRACE_HOOKS | ||||
IDTVEC(dtrace_ret), | IDTVEC(dtrace_ret), | ||||
#endif | #endif | ||||
#ifdef XENHVM | #ifdef XENHVM | ||||
IDTVEC(xen_intr_upcall), | IDTVEC(xen_intr_upcall), | ||||
#endif | #endif | ||||
IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall); | IDTVEC(int0x80_syscall); | ||||
#ifdef DDB | #ifdef DDB | ||||
/* | /* | ||||
* Display the index and function name of any IDT entries that don't use | * Display the index and function name of any IDT entries that don't use | ||||
* the default 'rsvd' entry point. | * the default 'rsvd' entry point. | ||||
*/ | */ | ||||
DB_SHOW_COMMAND(idt, db_show_idt) | DB_SHOW_COMMAND(idt, db_show_idt) | ||||
{ | { | ||||
struct gate_descriptor *ip; | struct gate_descriptor *ip; | ||||
int idx; | int idx; | ||||
uintptr_t func; | uintptr_t func, func_trm; | ||||
bool trm; | |||||
ip = idt; | ip = idt; | ||||
for (idx = 0; idx < NIDT && !db_pager_quit; idx++) { | for (idx = 0; idx < NIDT && !db_pager_quit; idx++) { | ||||
if (ip->gd_type == SDT_SYSTASKGT) { | |||||
db_printf("%3d\t<TASK>\n", idx); | |||||
} else { | |||||
func = (ip->gd_hioffset << 16 | ip->gd_looffset); | func = (ip->gd_hioffset << 16 | ip->gd_looffset); | ||||
if (func >= PMAP_TRM_MIN_ADDRESS) { | |||||
func_trm = func; | |||||
func -= setidt_disp; | |||||
trm = true; | |||||
} else | |||||
trm = false; | |||||
if (func != (uintptr_t)&IDTVEC(rsvd)) { | if (func != (uintptr_t)&IDTVEC(rsvd)) { | ||||
db_printf("%3d\t", idx); | db_printf("%3d\t", idx); | ||||
db_printsym(func, DB_STGY_PROC); | db_printsym(func, DB_STGY_PROC); | ||||
if (trm) | |||||
db_printf(" (trampoline %#x)", | |||||
func_trm); | |||||
db_printf("\n"); | db_printf("\n"); | ||||
} | } | ||||
} | |||||
ip++; | ip++; | ||||
} | } | ||||
} | } | ||||
/* Show privileged registers. */ | /* Show privileged registers. */ | ||||
DB_SHOW_COMMAND(sysregs, db_show_sysregs) | DB_SHOW_COMMAND(sysregs, db_show_sysregs) | ||||
{ | { | ||||
uint64_t idtr, gdtr; | uint64_t idtr, gdtr; | ||||
▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | add_smap_entries(struct bios_smap *smapbase, vm_paddr_t *physmap, | ||||
for (smap = smapbase; smap < smapend; smap++) | for (smap = smapbase; smap < smapend; smap++) | ||||
if (!add_smap_entry(smap, physmap, physmap_idxp)) | if (!add_smap_entry(smap, physmap, physmap_idxp)) | ||||
break; | break; | ||||
} | } | ||||
static void | static void | ||||
basemem_setup(void) | basemem_setup(void) | ||||
{ | { | ||||
vm_paddr_t pa; | |||||
pt_entry_t *pte; | pt_entry_t *pte; | ||||
int i; | int i; | ||||
if (basemem > 640) { | if (basemem > 640) { | ||||
printf("Preposterous BIOS basemem of %uK, truncating to 640K\n", | printf("Preposterous BIOS basemem of %uK, truncating to 640K\n", | ||||
basemem); | basemem); | ||||
basemem = 640; | basemem = 640; | ||||
} | } | ||||
/* | /* | ||||
* XXX if biosbasemem is now < 640, there is a `hole' | |||||
* between the end of base memory and the start of | |||||
* ISA memory. The hole may be empty or it may | |||||
* contain BIOS code or data. Map it read/write so | |||||
* that the BIOS can write to it. (Memory from 0 to | |||||
* the physical end of the kernel is mapped read-only | |||||
* to begin with and then parts of it are remapped. | |||||
* The parts that aren't remapped form holes that | |||||
* remain read-only and are unused by the kernel. | |||||
* The base memory area is below the physical end of | |||||
* the kernel and right now forms a read-only hole. | |||||
* The part of it from PAGE_SIZE to | |||||
* (trunc_page(biosbasemem * 1024) - 1) will be | |||||
* remapped and used by the kernel later.) | |||||
* | |||||
* This code is similar to the code used in | |||||
* pmap_mapdev, but since no memory needs to be | |||||
* allocated we simply change the mapping. | |||||
*/ | |||||
for (pa = trunc_page(basemem * 1024); | |||||
pa < ISA_HOLE_START; pa += PAGE_SIZE) | |||||
pmap_kenter(KERNBASE + pa, pa); | |||||
/* | |||||
* Map pages between basemem and ISA_HOLE_START, if any, r/w into | * Map pages between basemem and ISA_HOLE_START, if any, r/w into | ||||
* the vm86 page table so that vm86 can scribble on them using | * the vm86 page table so that vm86 can scribble on them using | ||||
* the vm86 map too. XXX: why 2 ways for this and only 1 way for | * the vm86 map too. XXX: why 2 ways for this and only 1 way for | ||||
* page 0, at least as initialized here? | * page 0, at least as initialized here? | ||||
*/ | */ | ||||
pte = (pt_entry_t *)vm86paddr; | pte = (pt_entry_t *)vm86paddr; | ||||
for (i = basemem / 4; i < 160; i++) | for (i = basemem / 4; i < 160; i++) | ||||
pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; | pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | if (hasbrokenint12 == 0) { | ||||
basemem_setup(); | basemem_setup(); | ||||
} | } | ||||
/* | /* | ||||
* Fetch the memory map with INT 15:E820. Map page 1 R/W into | * Fetch the memory map with INT 15:E820. Map page 1 R/W into | ||||
* the kernel page table so we can use it as a buffer. The | * the kernel page table so we can use it as a buffer. The | ||||
* kernel will unmap this page later. | * kernel will unmap this page later. | ||||
*/ | */ | ||||
pmap_kenter(KERNBASE + (1 << PAGE_SHIFT), 1 << PAGE_SHIFT); | pmap_kenter(1 << PAGE_SHIFT, 1 << PAGE_SHIFT); | ||||
vmc.npages = 0; | vmc.npages = 0; | ||||
smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT)); | smap = (void *)vm86_addpage(&vmc, 1, 1 << PAGE_SHIFT); | ||||
res = vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); | res = vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); | ||||
KASSERT(res != 0, ("vm86_getptr() failed: address not found")); | KASSERT(res != 0, ("vm86_getptr() failed: address not found")); | ||||
vmf.vmf_ebx = 0; | vmf.vmf_ebx = 0; | ||||
do { | do { | ||||
vmf.vmf_eax = 0xE820; | vmf.vmf_eax = 0xE820; | ||||
vmf.vmf_edx = SMAP_SIG; | vmf.vmf_edx = SMAP_SIG; | ||||
vmf.vmf_ecx = sizeof(struct bios_smap); | vmf.vmf_ecx = sizeof(struct bios_smap); | ||||
▲ Show 20 Lines • Show All 304 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
kdb_init(); | kdb_init(); | ||||
#ifdef KDB | #ifdef KDB | ||||
if (boothowto & RB_KDB) | if (boothowto & RB_KDB) | ||||
kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); | kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); | ||||
#endif | #endif | ||||
} | } | ||||
static void | |||||
fixup_idt(void) | |||||
{ | |||||
struct gate_descriptor *ip; | |||||
uintptr_t off; | |||||
int x; | |||||
for (x = 0; x < NIDT; x++) { | |||||
ip = &idt[x]; | |||||
if (ip->gd_type != SDT_SYS386IGT && | |||||
ip->gd_type != SDT_SYS386TGT) | |||||
continue; | |||||
off = ip->gd_looffset + (((u_int)ip->gd_hioffset) << 16); | |||||
KASSERT(off >= (uintptr_t)start_exceptions && | |||||
off < (uintptr_t)end_exceptions, | |||||
("IDT[%d] type %d off %#x", x, ip->gd_type, off)); | |||||
off += setidt_disp; | |||||
MPASS(off >= PMAP_TRM_MIN_ADDRESS && | |||||
off < PMAP_TRM_MAX_ADDRESS); | |||||
ip->gd_looffset = off; | |||||
ip->gd_hioffset = off >> 16; | |||||
} | |||||
} | |||||
static void | |||||
i386_setidt1(void) | |||||
{ | |||||
int x; | |||||
/* exceptions */ | |||||
for (x = 0; x < NIDT; x++) | |||||
setidt(x, &IDTVEC(rsvd), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_DE, &IDTVEC(div), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_DB, &IDTVEC(dbg), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_NMI, &IDTVEC(nmi), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_BP, &IDTVEC(bpt), SDT_SYS386IGT, SEL_UPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_OF, &IDTVEC(ofl), SDT_SYS386IGT, SEL_UPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_BR, &IDTVEC(bnd), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_UD, &IDTVEC(ill), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_NM, &IDTVEC(dna), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_DF, 0, SDT_SYSTASKGT, SEL_KPL, GSEL(GPANIC_SEL, | |||||
SEL_KPL)); | |||||
setidt(IDT_FPUGP, &IDTVEC(fpusegm), SDT_SYS386IGT, | |||||
SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_TS, &IDTVEC(tss), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_NP, &IDTVEC(missing), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_SS, &IDTVEC(stk), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_GP, &IDTVEC(prot), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_PF, &IDTVEC(page), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_MF, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_AC, &IDTVEC(align), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_MC, &IDTVEC(mchk), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_XF, &IDTVEC(xmm), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_SYSCALL, &IDTVEC(int0x80_syscall), | |||||
SDT_SYS386IGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); | |||||
#ifdef KDTRACE_HOOKS | |||||
setidt(IDT_DTRACE_RET, &IDTVEC(dtrace_ret), | |||||
SDT_SYS386IGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); | |||||
#endif | |||||
#ifdef XENHVM | |||||
setidt(IDT_EVTCHN, &IDTVEC(xen_intr_upcall), | |||||
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); | |||||
#endif | |||||
} | |||||
static void | |||||
i386_setidt2(void) | |||||
{ | |||||
setidt(IDT_UD, &IDTVEC(ill), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_GP, &IDTVEC(prot), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
} | |||||
#if defined(DEV_ISA) && !defined(DEV_ATPIC) | |||||
static void | |||||
i386_setidt3(void) | |||||
{ | |||||
setidt(IDT_IO_INTS + 7, IDTVEC(spuriousint), | |||||
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_IO_INTS + 15, IDTVEC(spuriousint), | |||||
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); | |||||
} | |||||
#endif | |||||
register_t | register_t | ||||
init386(int first) | init386(int first) | ||||
{ | { | ||||
struct gate_descriptor *gdp; | struct region_descriptor r_gdt, r_idt; /* table descriptors */ | ||||
int gsel_tss, metadata_missing, x, pa; | int gsel_tss, metadata_missing, x, pa; | ||||
struct pcpu *pc; | struct pcpu *pc; | ||||
struct xstate_hdr *xhdr; | struct xstate_hdr *xhdr; | ||||
vm_offset_t addend; | |||||
int late_console; | int late_console; | ||||
thread0.td_kstack = proc0kstack; | thread0.td_kstack = proc0kstack; | ||||
thread0.td_kstack_pages = TD0_KSTACK_PAGES; | thread0.td_kstack_pages = TD0_KSTACK_PAGES; | ||||
/* | /* | ||||
* This may be done better later if it gets more high level | * This may be done better later if it gets more high level | ||||
* components in it. If so just link td->td_proc here. | * components in it. If so just link td->td_proc here. | ||||
*/ | */ | ||||
proc_linkup0(&proc0, &thread0); | proc_linkup0(&proc0, &thread0); | ||||
metadata_missing = 0; | |||||
if (bootinfo.bi_modulep) { | if (bootinfo.bi_modulep) { | ||||
preload_metadata = (caddr_t)bootinfo.bi_modulep + KERNBASE; | metadata_missing = 0; | ||||
preload_bootstrap_relocate(KERNBASE); | addend = (vm_paddr_t)bootinfo.bi_modulep < KERNBASE ? | ||||
PMAP_MAP_LOW : 0; | |||||
preload_metadata = (caddr_t)bootinfo.bi_modulep + addend; | |||||
preload_bootstrap_relocate(addend); | |||||
} else { | } else { | ||||
metadata_missing = 1; | metadata_missing = 1; | ||||
} | } | ||||
if (bootinfo.bi_envp != 0) | if (bootinfo.bi_envp != 0) { | ||||
init_static_kenv((char *)bootinfo.bi_envp + KERNBASE, 0); | addend = (vm_paddr_t)bootinfo.bi_envp < KERNBASE ? | ||||
else | PMAP_MAP_LOW : 0; | ||||
init_static_kenv((char *)bootinfo.bi_envp + addend, 0); | |||||
} else { | |||||
init_static_kenv(NULL, 0); | init_static_kenv(NULL, 0); | ||||
} | |||||
identify_hypervisor(); | identify_hypervisor(); | ||||
/* Init basic tunables, hz etc */ | /* Init basic tunables, hz etc */ | ||||
init_param1(); | init_param1(); | ||||
/* | /* | ||||
* Make gdt memory segments. All segments cover the full 4GB | * Make gdt memory segments. All segments cover the full 4GB | ||||
* of address space and permissions are enforced at page level. | * of address space and permissions are enforced at page level. | ||||
*/ | */ | ||||
gdt_segs[GCODE_SEL].ssd_limit = atop(0 - 1); | gdt_segs[GCODE_SEL].ssd_limit = atop(0 - 1); | ||||
gdt_segs[GDATA_SEL].ssd_limit = atop(0 - 1); | gdt_segs[GDATA_SEL].ssd_limit = atop(0 - 1); | ||||
gdt_segs[GUCODE_SEL].ssd_limit = atop(0 - 1); | gdt_segs[GUCODE_SEL].ssd_limit = atop(0 - 1); | ||||
gdt_segs[GUDATA_SEL].ssd_limit = atop(0 - 1); | gdt_segs[GUDATA_SEL].ssd_limit = atop(0 - 1); | ||||
gdt_segs[GUFS_SEL].ssd_limit = atop(0 - 1); | gdt_segs[GUFS_SEL].ssd_limit = atop(0 - 1); | ||||
gdt_segs[GUGS_SEL].ssd_limit = atop(0 - 1); | gdt_segs[GUGS_SEL].ssd_limit = atop(0 - 1); | ||||
pc = &__pcpu[0]; | pc = &__pcpu[0]; | ||||
gdt_segs[GPRIV_SEL].ssd_limit = atop(0 - 1); | gdt_segs[GPRIV_SEL].ssd_limit = atop(0 - 1); | ||||
gdt_segs[GPRIV_SEL].ssd_base = (int) pc; | gdt_segs[GPRIV_SEL].ssd_base = (int)pc; | ||||
gdt_segs[GPROC0_SEL].ssd_base = (int) &pc->pc_common_tss; | gdt_segs[GPROC0_SEL].ssd_base = (int)&common_tss0; | ||||
for (x = 0; x < NGDT; x++) | for (x = 0; x < NGDT; x++) | ||||
ssdtosd(&gdt_segs[x], &gdt[x].sd); | ssdtosd(&gdt_segs[x], &gdt[x].sd); | ||||
r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; | r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; | ||||
r_gdt.rd_base = (int) gdt; | r_gdt.rd_base = (int) gdt; | ||||
mtx_init(&dt_lock, "descriptor tables", NULL, MTX_SPIN); | mtx_init(&dt_lock, "descriptor tables", NULL, MTX_SPIN); | ||||
lgdt(&r_gdt); | lgdt(&r_gdt); | ||||
pcpu_init(pc, 0, sizeof(struct pcpu)); | pcpu_init(pc, 0, sizeof(struct pcpu)); | ||||
for (pa = first; pa < first + DPCPU_SIZE; pa += PAGE_SIZE) | for (pa = first; pa < first + DPCPU_SIZE; pa += PAGE_SIZE) | ||||
pmap_kenter(pa + KERNBASE, pa); | pmap_kenter(pa, pa); | ||||
dpcpu_init((void *)(first + KERNBASE), 0); | dpcpu_init((void *)first, 0); | ||||
first += DPCPU_SIZE; | first += DPCPU_SIZE; | ||||
PCPU_SET(prvspace, pc); | PCPU_SET(prvspace, pc); | ||||
PCPU_SET(curthread, &thread0); | PCPU_SET(curthread, &thread0); | ||||
/* Non-late cninit() and printf() can be moved up to here. */ | /* Non-late cninit() and printf() can be moved up to here. */ | ||||
/* | /* | ||||
* Initialize mutexes. | * Initialize mutexes. | ||||
* | * | ||||
* icu_lock: in order to allow an interrupt to occur in a critical | * icu_lock: in order to allow an interrupt to occur in a critical | ||||
* section, to set pcpu->ipending (etc...) properly, we | * section, to set pcpu->ipending (etc...) properly, we | ||||
* must be able to get the icu lock, so it can't be | * must be able to get the icu lock, so it can't be | ||||
* under witness. | * under witness. | ||||
*/ | */ | ||||
mutex_init(); | mutex_init(); | ||||
mtx_init(&icu_lock, "icu", NULL, MTX_SPIN | MTX_NOWITNESS | MTX_NOPROFILE); | mtx_init(&icu_lock, "icu", NULL, MTX_SPIN | MTX_NOWITNESS | MTX_NOPROFILE); | ||||
/* make ldt memory segments */ | i386_setidt1(); | ||||
ldt_segs[LUCODE_SEL].ssd_limit = atop(0 - 1); | |||||
ldt_segs[LUDATA_SEL].ssd_limit = atop(0 - 1); | |||||
for (x = 0; x < nitems(ldt_segs); x++) | |||||
ssdtosd(&ldt_segs[x], &ldt[x].sd); | |||||
_default_ldt = GSEL(GLDT_SEL, SEL_KPL); | |||||
lldt(_default_ldt); | |||||
PCPU_SET(currentldt, _default_ldt); | |||||
/* exceptions */ | |||||
for (x = 0; x < NIDT; x++) | |||||
setidt(x, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_DE, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_DB, &IDTVEC(dbg), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_NMI, &IDTVEC(nmi), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_BP, &IDTVEC(bpt), SDT_SYS386IGT, SEL_UPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_OF, &IDTVEC(ofl), SDT_SYS386TGT, SEL_UPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_BR, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_UD, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_NM, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL | |||||
, GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_DF, 0, SDT_SYSTASKGT, SEL_KPL, GSEL(GPANIC_SEL, SEL_KPL)); | |||||
setidt(IDT_FPUGP, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_TS, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_NP, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_SS, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_GP, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_PF, &IDTVEC(page), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_MF, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_AC, &IDTVEC(align), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_MC, &IDTVEC(mchk), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_XF, &IDTVEC(xmm), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_SYSCALL, &IDTVEC(int0x80_syscall), SDT_SYS386TGT, SEL_UPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
#ifdef KDTRACE_HOOKS | |||||
setidt(IDT_DTRACE_RET, &IDTVEC(dtrace_ret), SDT_SYS386TGT, SEL_UPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
#endif | |||||
#ifdef XENHVM | |||||
setidt(IDT_EVTCHN, &IDTVEC(xen_intr_upcall), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
#endif | |||||
r_idt.rd_limit = sizeof(idt0) - 1; | r_idt.rd_limit = sizeof(idt0) - 1; | ||||
r_idt.rd_base = (int) idt; | r_idt.rd_base = (int) idt; | ||||
lidt(&r_idt); | lidt(&r_idt); | ||||
/* | /* | ||||
* Initialize the clock before the console so that console | * Initialize the clock before the console so that console | ||||
* initialization can use DELAY(). | * initialization can use DELAY(). | ||||
*/ | */ | ||||
clock_init(); | clock_init(); | ||||
finishidentcpu(); /* Final stage of CPU initialization */ | finishidentcpu(); /* Final stage of CPU initialization */ | ||||
setidt(IDT_UD, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, | i386_setidt2(); | ||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_GP, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
initializecpu(); /* Initialize CPU registers */ | initializecpu(); /* Initialize CPU registers */ | ||||
initializecpucache(); | initializecpucache(); | ||||
/* pointer to selector slot for %fs/%gs */ | /* pointer to selector slot for %fs/%gs */ | ||||
PCPU_SET(fsgs_gdt, &gdt[GUFS_SEL].sd); | PCPU_SET(fsgs_gdt, &gdt[GUFS_SEL].sd); | ||||
dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 = | |||||
dblfault_tss.tss_esp2 = (int)&dblfault_stack[sizeof(dblfault_stack)]; | |||||
dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 = | |||||
dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL); | |||||
#if defined(PAE) || defined(PAE_TABLES) | |||||
dblfault_tss.tss_cr3 = (int)IdlePDPT; | |||||
#else | |||||
dblfault_tss.tss_cr3 = (int)IdlePTD; | |||||
#endif | |||||
dblfault_tss.tss_eip = (int)dblfault_handler; | |||||
dblfault_tss.tss_eflags = PSL_KERNEL; | |||||
dblfault_tss.tss_ds = dblfault_tss.tss_es = | |||||
dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL); | |||||
dblfault_tss.tss_fs = GSEL(GPRIV_SEL, SEL_KPL); | |||||
dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL); | |||||
dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL); | |||||
/* Initialize the tss (except for the final esp0) early for vm86. */ | /* Initialize the tss (except for the final esp0) early for vm86. */ | ||||
PCPU_SET(common_tss.tss_esp0, thread0.td_kstack + | common_tss0.tss_esp0 = thread0.td_kstack + thread0.td_kstack_pages * | ||||
thread0.td_kstack_pages * PAGE_SIZE - 16); | PAGE_SIZE - VM86_STACK_SPACE; | ||||
PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL)); | common_tss0.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); | ||||
common_tss0.tss_ioopt = sizeof(struct i386tss) << 16; | |||||
gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); | gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); | ||||
PCPU_SET(tss_gdt, &gdt[GPROC0_SEL].sd); | PCPU_SET(tss_gdt, &gdt[GPROC0_SEL].sd); | ||||
PCPU_SET(common_tssd, *PCPU_GET(tss_gdt)); | PCPU_SET(common_tssd, *PCPU_GET(tss_gdt)); | ||||
PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16); | |||||
ltr(gsel_tss); | ltr(gsel_tss); | ||||
/* Initialize the PIC early for vm86 calls. */ | /* Initialize the PIC early for vm86 calls. */ | ||||
#ifdef DEV_ISA | #ifdef DEV_ISA | ||||
#ifdef DEV_ATPIC | #ifdef DEV_ATPIC | ||||
elcr_probe(); | elcr_probe(); | ||||
atpic_startup(); | atpic_startup(); | ||||
#else | #else | ||||
/* Reset and mask the atpics and leave them shut down. */ | /* Reset and mask the atpics and leave them shut down. */ | ||||
atpic_reset(); | atpic_reset(); | ||||
/* | /* | ||||
* Point the ICU spurious interrupt vectors at the APIC spurious | * Point the ICU spurious interrupt vectors at the APIC spurious | ||||
* interrupt handler. | * interrupt handler. | ||||
*/ | */ | ||||
setidt(IDT_IO_INTS + 7, IDTVEC(spuriousint), SDT_SYS386IGT, SEL_KPL, | i386_setidt3(); | ||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
setidt(IDT_IO_INTS + 15, IDTVEC(spuriousint), SDT_SYS386IGT, SEL_KPL, | |||||
GSEL(GCODE_SEL, SEL_KPL)); | |||||
#endif | #endif | ||||
#endif | #endif | ||||
/* | /* | ||||
* The console and kdb should be initialized even earlier than here, | * The console and kdb should be initialized even earlier than here, | ||||
* but some console drivers don't work until after getmemsize(). | * but some console drivers don't work until after getmemsize(). | ||||
* Default to late console initialization to support these drivers. | * Default to late console initialization to support these drivers. | ||||
* This loses mainly printf()s in getmemsize() and early debugging. | * This loses mainly printf()s in getmemsize() and early debugging. | ||||
Show All 33 Lines | #endif | ||||
if (use_xsave) { | if (use_xsave) { | ||||
xhdr = (struct xstate_hdr *)(get_pcb_user_save_td(&thread0) + | xhdr = (struct xstate_hdr *)(get_pcb_user_save_td(&thread0) + | ||||
1); | 1); | ||||
xhdr->xstate_bv = xsave_mask; | xhdr->xstate_bv = xsave_mask; | ||||
} | } | ||||
PCPU_SET(curpcb, thread0.td_pcb); | PCPU_SET(curpcb, thread0.td_pcb); | ||||
/* Move esp0 in the tss to its final place. */ | /* Move esp0 in the tss to its final place. */ | ||||
/* Note: -16 is so we can grow the trapframe if we came from vm86 */ | /* Note: -16 is so we can grow the trapframe if we came from vm86 */ | ||||
PCPU_SET(common_tss.tss_esp0, (vm_offset_t)thread0.td_pcb - 16); | common_tss0.tss_esp0 = (vm_offset_t)thread0.td_pcb - VM86_STACK_SPACE; | ||||
gdt[GPROC0_SEL].sd.sd_type = SDT_SYS386TSS; /* clear busy bit */ | gdt[GPROC0_SEL].sd.sd_type = SDT_SYS386TSS; /* clear busy bit */ | ||||
ltr(gsel_tss); | ltr(gsel_tss); | ||||
/* make a call gate to reenter kernel with */ | |||||
gdp = &ldt[LSYS5CALLS_SEL].gd; | |||||
x = (int) &IDTVEC(lcall_syscall); | |||||
gdp->gd_looffset = x; | |||||
gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL); | |||||
gdp->gd_stkcpy = 1; | |||||
gdp->gd_type = SDT_SYS386CGT; | |||||
gdp->gd_dpl = SEL_UPL; | |||||
gdp->gd_p = 1; | |||||
gdp->gd_hioffset = x >> 16; | |||||
/* transfer to user mode */ | /* transfer to user mode */ | ||||
_ucodesel = GSEL(GUCODE_SEL, SEL_UPL); | _ucodesel = GSEL(GUCODE_SEL, SEL_UPL); | ||||
_udatasel = GSEL(GUDATA_SEL, SEL_UPL); | _udatasel = GSEL(GUDATA_SEL, SEL_UPL); | ||||
/* setup proc 0's pcb */ | /* setup proc 0's pcb */ | ||||
thread0.td_pcb->pcb_flags = 0; | thread0.td_pcb->pcb_flags = 0; | ||||
#if defined(PAE) || defined(PAE_TABLES) | #if defined(PAE) || defined(PAE_TABLES) | ||||
Show All 9 Lines | |||||
#ifdef FDT | #ifdef FDT | ||||
x86_init_fdt(); | x86_init_fdt(); | ||||
#endif | #endif | ||||
/* Location of kernel stack for locore */ | /* Location of kernel stack for locore */ | ||||
return ((register_t)thread0.td_pcb); | return ((register_t)thread0.td_pcb); | ||||
} | } | ||||
extern u_int tramp_idleptd; | |||||
static void | |||||
machdep_init_trampoline(void) | |||||
{ | |||||
struct region_descriptor r_gdt, r_idt; | |||||
struct i386tss *tss; | |||||
char *trampoline, *tramp_stack_base; | |||||
u_int *tramp_idleptd_reloced; | |||||
int x; | |||||
gdt = pmap_trm_alloc(sizeof(union descriptor) * NGDT * mp_ncpus, | |||||
M_NOWAIT | M_ZERO); | |||||
bcopy(gdt0, gdt, sizeof(union descriptor) * NGDT); | |||||
r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; | |||||
r_gdt.rd_base = (int)gdt; | |||||
lgdt(&r_gdt); | |||||
tss = pmap_trm_alloc(sizeof(struct i386tss) * mp_ncpus, | |||||
M_NOWAIT | M_ZERO); | |||||
bcopy(&common_tss0, tss, sizeof(struct i386tss)); | |||||
gdt[GPROC0_SEL].sd.sd_lobase = (int)tss; | |||||
gdt[GPROC0_SEL].sd.sd_hibase = (u_int)tss >> 24; | |||||
gdt[GPROC0_SEL].sd.sd_type = SDT_SYS386TSS; | |||||
ltr(GSEL(GPROC0_SEL, SEL_KPL)); | |||||
PCPU_SET(fsgs_gdt, &gdt[GUFS_SEL].sd); | |||||
PCPU_SET(tss_gdt, &gdt[GPROC0_SEL].sd); | |||||
PCPU_SET(common_tssd, *PCPU_GET(tss_gdt)); | |||||
PCPU_SET(common_tssp, tss); | |||||
trampoline = pmap_trm_alloc(end_exceptions - start_exceptions, | |||||
M_NOWAIT); | |||||
bcopy(start_exceptions, trampoline, end_exceptions - start_exceptions); | |||||
tramp_stack_base = pmap_trm_alloc(TRAMP_STACK_SZ, M_NOWAIT); | |||||
PCPU_SET(trampstk, (uintptr_t)tramp_stack_base + TRAMP_STACK_SZ - | |||||
VM86_STACK_SPACE); | |||||
tss[0].tss_esp0 = PCPU_GET(trampstk); | |||||
idt = pmap_trm_alloc(sizeof(idt0), M_NOWAIT | M_ZERO); | |||||
bcopy(idt0, idt, sizeof(idt0)); | |||||
/* Re-initialize new IDT since the handlers were relocated */ | |||||
setidt_disp = trampoline - start_exceptions; | |||||
fixup_idt(); | |||||
tramp_idleptd_reloced = (u_int *)((uintptr_t)&tramp_idleptd + | |||||
setidt_disp); | |||||
#if defined(PAE) || defined(PAE_TABLES) | |||||
*tramp_idleptd_reloced = (u_int)IdlePDPT; | |||||
#else | |||||
*tramp_idleptd_reloced = (u_int)IdlePTD; | |||||
#endif | |||||
r_idt.rd_limit = sizeof(struct gate_descriptor) * NIDT - 1; | |||||
r_idt.rd_base = (int)idt; | |||||
lidt(&r_idt); | |||||
/* dblfault TSS */ | |||||
dblfault_tss = pmap_trm_alloc(sizeof(struct i386tss), M_NOWAIT | M_ZERO); | |||||
dblfault_stack = pmap_trm_alloc(PAGE_SIZE, M_NOWAIT); | |||||
dblfault_tss->tss_esp = dblfault_tss->tss_esp0 = | |||||
dblfault_tss->tss_esp1 = dblfault_tss->tss_esp2 = | |||||
(int)dblfault_stack + PAGE_SIZE; | |||||
dblfault_tss->tss_ss = dblfault_tss->tss_ss0 = dblfault_tss->tss_ss1 = | |||||
dblfault_tss->tss_ss2 = GSEL(GDATA_SEL, SEL_KPL); | |||||
#if defined(PAE) || defined(PAE_TABLES) | |||||
dblfault_tss->tss_cr3 = (int)IdlePDPT; | |||||
#else | |||||
dblfault_tss->tss_cr3 = (int)IdlePTD; | |||||
#endif | |||||
dblfault_tss->tss_eip = (int)dblfault_handler; | |||||
dblfault_tss->tss_eflags = PSL_KERNEL; | |||||
dblfault_tss->tss_ds = dblfault_tss->tss_es = | |||||
dblfault_tss->tss_gs = GSEL(GDATA_SEL, SEL_KPL); | |||||
dblfault_tss->tss_fs = GSEL(GPRIV_SEL, SEL_KPL); | |||||
dblfault_tss->tss_cs = GSEL(GCODE_SEL, SEL_KPL); | |||||
dblfault_tss->tss_ldt = GSEL(GLDT_SEL, SEL_KPL); | |||||
gdt[GPANIC_SEL].sd.sd_lobase = (int)dblfault_tss; | |||||
gdt[GPANIC_SEL].sd.sd_hibase = (u_int)dblfault_tss >> 24; | |||||
/* make ldt memory segments */ | |||||
ldt = pmap_trm_alloc(sizeof(union descriptor) * NLDT, | |||||
M_NOWAIT | M_ZERO); | |||||
gdt[GLDT_SEL].sd.sd_lobase = (int)ldt; | |||||
gdt[GLDT_SEL].sd.sd_hibase = (u_int)ldt >> 24; | |||||
ldt_segs[LUCODE_SEL].ssd_limit = atop(0 - 1); | |||||
ldt_segs[LUDATA_SEL].ssd_limit = atop(0 - 1); | |||||
for (x = 0; x < nitems(ldt_segs); x++) | |||||
ssdtosd(&ldt_segs[x], &ldt[x].sd); | |||||
_default_ldt = GSEL(GLDT_SEL, SEL_KPL); | |||||
lldt(_default_ldt); | |||||
PCPU_SET(currentldt, _default_ldt); | |||||
} | |||||
SYSINIT(vm_mem, SI_SUB_VM, SI_ORDER_SECOND, machdep_init_trampoline, NULL); | |||||
#ifdef COMPAT_43 | |||||
static void | |||||
i386_setup_lcall_gate(void) | |||||
{ | |||||
struct sysentvec *sv; | |||||
struct user_segment_descriptor desc; | |||||
u_int lcall_addr; | |||||
sv = &elf32_freebsd_sysvec; | |||||
lcall_addr = (uintptr_t)sv->sv_psstrings - sz_lcall_tramp; | |||||
bzero(&desc, sizeof(desc)); | |||||
desc.sd_type = SDT_MEMERA; | |||||
desc.sd_dpl = SEL_UPL; | |||||
desc.sd_p = 1; | |||||
desc.sd_def32 = 1; | |||||
desc.sd_gran = 1; | |||||
desc.sd_lolimit = 0xffff; | |||||
desc.sd_hilimit = 0xf; | |||||
desc.sd_lobase = lcall_addr; | |||||
desc.sd_hibase = lcall_addr >> 24; | |||||
bcopy(&desc, &ldt[LSYS5CALLS_SEL], sizeof(desc)); | |||||
} | |||||
SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY, i386_setup_lcall_gate, NULL); | |||||
#endif | |||||
void | void | ||||
cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) | cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) | ||||
{ | { | ||||
pcpu->pc_acpi_id = 0xffffffff; | pcpu->pc_acpi_id = 0xffffffff; | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
#if defined(I586_CPU) && !defined(NO_F00F_HACK) | #if defined(I586_CPU) && !defined(NO_F00F_HACK) | ||||
static void f00f_hack(void *unused); | static void f00f_hack(void *unused); | ||||
SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL); | SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL); | ||||
static void | static void | ||||
f00f_hack(void *unused) | f00f_hack(void *unused) | ||||
{ | { | ||||
struct region_descriptor r_idt; | |||||
struct gate_descriptor *new_idt; | struct gate_descriptor *new_idt; | ||||
vm_offset_t tmp; | vm_offset_t tmp; | ||||
if (!has_f00f_bug) | if (!has_f00f_bug) | ||||
return; | return; | ||||
GIANT_REQUIRED; | GIANT_REQUIRED; | ||||
printf("Intel Pentium detected, installing workaround for F00F bug\n"); | printf("Intel Pentium detected, installing workaround for F00F bug\n"); | ||||
tmp = kmem_malloc(kernel_arena, PAGE_SIZE * 2, M_WAITOK | M_ZERO); | tmp = (vm_offset_t)pmap_trm_alloc(PAGE_SIZE * 3, M_NOWAIT | M_ZERO); | ||||
if (tmp == 0) | if (tmp == 0) | ||||
panic("kmem_malloc returned 0"); | panic("kmem_malloc returned 0"); | ||||
tmp = round_page(tmp); | |||||
/* Put the problematic entry (#6) at the end of the lower page. */ | /* Put the problematic entry (#6) at the end of the lower page. */ | ||||
new_idt = (struct gate_descriptor*) | new_idt = (struct gate_descriptor *) | ||||
(tmp + PAGE_SIZE - 7 * sizeof(struct gate_descriptor)); | (tmp + PAGE_SIZE - 7 * sizeof(struct gate_descriptor)); | ||||
bcopy(idt, new_idt, sizeof(idt0)); | bcopy(idt, new_idt, sizeof(idt0)); | ||||
r_idt.rd_base = (u_int)new_idt; | r_idt.rd_base = (u_int)new_idt; | ||||
r_idt.rd_limit = sizeof(idt0) - 1; | |||||
lidt(&r_idt); | lidt(&r_idt); | ||||
/* SMP machines do not need the F00F hack. */ | |||||
idt = new_idt; | idt = new_idt; | ||||
pmap_protect(kernel_pmap, tmp, tmp + PAGE_SIZE, VM_PROT_READ); | pmap_protect(kernel_pmap, tmp, tmp + PAGE_SIZE, VM_PROT_READ); | ||||
} | } | ||||
#endif /* defined(I586_CPU) && !NO_F00F_HACK */ | #endif /* defined(I586_CPU) && !NO_F00F_HACK */ | ||||
/* | /* | ||||
* Construct a PCB from a trapframe. This is called from kdb_trap() where | * Construct a PCB from a trapframe. This is called from kdb_trap() where | ||||
* we want to start a backtrace from the function that caused us to enter | * we want to start a backtrace from the function that caused us to enter | ||||
▲ Show 20 Lines • Show All 502 Lines • Show Last 20 Lines |
For cases where there is already a 4-clause license I think we should add a new 2-clause FreeBSD for ours.