#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.852 2026/07/10 15:11:25 riastradh Exp $");
#include "opt_beep.h"
#include "opt_compat_freebsd.h"
#include "opt_compat_netbsd.h"
#include "opt_cpureset_delay.h"
#include "opt_ddb.h"
#include "opt_kgdb.h"
#include "opt_mtrr.h"
#include "opt_modular.h"
#include "opt_multiboot.h"
#include "opt_multiprocessor.h"
#include "opt_physmem.h"
#include "opt_realmem.h"
#include "opt_user_ldt.h"
#include "opt_xen.h"
#include "isa.h"
#include "pci.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/signal.h>
#include <sys/signalvar.h>
#include <sys/kernel.h>
#include <sys/cpu.h>
#include <sys/exec.h>
#include <sys/fcntl.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/msgbuf.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <sys/core.h>
#include <sys/kcore.h>
#include <sys/ucontext.h>
#include <sys/ras.h>
#include <sys/ksyms.h>
#include <sys/device.h>
#include <sys/timevar.h>
#ifdef KGDB
#include <sys/kgdb.h>
#endif
#include <dev/cons.h>
#include <dev/mm.h>
#include <uvm/uvm.h>
#include <uvm/uvm_page.h>
#include <sys/sysctl.h>
#include <x86/efi.h>
#include <machine/cpu.h>
#include <machine/cpu_rng.h>
#include <machine/cpufunc.h>
#include <machine/cpuvar.h>
#include <machine/gdt.h>
#include <machine/intr.h>
#include <machine/kcore.h>
#include <machine/pio.h>
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/specialreg.h>
#include <machine/bootinfo.h>
#include <machine/mtrr.h>
#include <machine/pmap_private.h>
#include <x86/x86/tsc.h>
#include <x86/bootspace.h>
#include <x86/fpu.h>
#include <x86/dbregs.h>
#include <x86/machdep.h>
#include <machine/multiboot.h>
#ifdef XEN
#include <xen/evtchn.h>
#include <xen/xen.h>
#include <xen/hypervisor.h>
#endif
#include <dev/isa/isareg.h>
#include <machine/isa_machdep.h>
#include <dev/ic/i8042reg.h>
#include <ddb/db_active.h>
#ifdef DDB
#include <machine/db_machdep.h>
#include <ddb/db_extern.h>
#endif
#include "acpica.h"
#include "bioscall.h"
#if NBIOSCALL > 0
#include <machine/bioscall.h>
#endif
#if NACPICA > 0
#include <dev/acpi/acpivar.h>
#define ACPI_MACHDEP_PRIVATE
#include <machine/acpi_machdep.h>
#else
#include <machine/i82489var.h>
#endif
#include "isa.h"
#include "isadma.h"
#include "ksyms.h"
#include "cardbus.h"
#if NCARDBUS > 0
#include <sys/bus.h>
#include <dev/cardbus/rbus.h>
#include <machine/rbus_machdep.h>
#endif
#include "mca.h"
#if NMCA > 0
#include <machine/mca_machdep.h>
#endif
#ifdef MULTIPROCESSOR
#include <machine/mpbiosvar.h>
#endif
char machine[] = "i386";
char machine_arch[] = "i386";
#ifdef CPURESET_DELAY
int cpureset_delay = CPURESET_DELAY;
#else
int cpureset_delay = 2000;
#endif
#ifdef MTRR
const struct mtrr_funcs *mtrr_funcs;
#endif
int cpu_class;
int use_pae;
int i386_fpu_fdivbug;
int i386_use_fxsave;
int i386_has_sse;
int i386_has_sse2;
vaddr_t idt_vaddr;
paddr_t idt_paddr;
vaddr_t gdt_vaddr;
paddr_t gdt_paddr;
vaddr_t ldt_vaddr;
paddr_t ldt_paddr;
vaddr_t pentium_idt_vaddr;
struct vm_map *phys_map = NULL;
extern struct bootspace bootspace;
extern paddr_t lowmem_rsvd;
extern paddr_t avail_start, avail_end;
#ifdef XENPV
extern paddr_t pmap_pa_start, pmap_pa_end;
void hypervisor_callback(void);
void failsafe_callback(void);
#endif
phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
int mem_cluster_cnt = 0;
void init_bootspace(void);
void init386(paddr_t);
void initgdt(union descriptor *);
static void i386_proc0_pcb_ldt_init(void);
static int cpu_getmcontext_xsave(struct lwp *, mcontext_t *, unsigned *,
const struct xsave_header *, size_t, struct xsave_header *);
int *esym;
int *eblob;
extern int boothowto;
#ifndef XENPV
#ifndef REALBASEMEM
int biosbasemem = 0;
#else
int biosbasemem = REALBASEMEM;
#endif
#ifndef REALEXTMEM
int biosextmem = 0;
#else
int biosextmem = REALEXTMEM;
#endif
int biosmem_implicit;
struct bootinfo_source {
uint32_t bs_naddrs;
void *bs_addrs[1];
};
void native_loader(int, int, struct bootinfo_source *, paddr_t, int, int);
void
native_loader(int bl_boothowto, int bl_bootdev,
struct bootinfo_source *bl_bootinfo, paddr_t bl_esym,
int bl_biosextmem, int bl_biosbasemem)
{
#define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
*RELOC(int *, &boothowto) = bl_boothowto;
if (bl_esym != 0)
*RELOC(int **, &esym) = (int *)((vaddr_t)bl_esym + KERNBASE);
else
*RELOC(int **, &esym) = 0;
if (bl_bootinfo != NULL) {
size_t i;
uint8_t *data;
struct bootinfo *bidest;
struct btinfo_modulelist *bi;
bidest = RELOC(struct bootinfo *, &bootinfo);
data = &bidest->bi_data[0];
for (i = 0; i < bl_bootinfo->bs_naddrs; i++) {
struct btinfo_common *bc;
bc = bl_bootinfo->bs_addrs[i];
if ((data + bc->len) >
(&bidest->bi_data[0] + BOOTINFO_MAXSIZE))
break;
memcpy(data, bc, bc->len);
bi = (struct btinfo_modulelist *)data;
if (bi->common.type == BTINFO_MODULELIST) {
*RELOC(int **, &eblob) =
(int *)(bi->endpa + KERNBASE);
}
data += bc->len;
}
bidest->bi_nentries = i;
}
if (*RELOC(int *, &biosbasemem) == 0) {
*RELOC(int *, &biosbasemem) = bl_biosbasemem;
*RELOC(int *, &biosmem_implicit) = 1;
}
if (*RELOC(int *, &biosextmem) == 0) {
*RELOC(int *, &biosextmem) = bl_biosextmem;
*RELOC(int *, &biosmem_implicit) = 1;
}
#undef RELOC
}
#endif
void
cpu_startup(void)
{
int x, y;
vaddr_t minaddr, maxaddr;
psize_t sz;
consinit();
if (msgbuf_p_cnt == 0)
panic("msgbuf paddr map has not been set up");
for (x = 0, sz = 0; x < msgbuf_p_cnt; sz += msgbuf_p_seg[x++].sz)
continue;
msgbuf_vaddr = uvm_km_alloc(kernel_map, sz, 0, UVM_KMF_VAONLY);
if (msgbuf_vaddr == 0)
panic("failed to valloc msgbuf_vaddr");
for (y = 0, sz = 0; y < msgbuf_p_cnt; y++) {
for (x = 0; x < btoc(msgbuf_p_seg[y].sz); x++, sz += PAGE_SIZE)
pmap_kenter_pa((vaddr_t)msgbuf_vaddr + sz,
msgbuf_p_seg[y].paddr + x * PAGE_SIZE,
VM_PROT_READ|VM_PROT_WRITE, 0);
}
pmap_update(pmap_kernel());
initmsgbuf((void *)msgbuf_vaddr, sz);
#ifdef MULTIBOOT
multiboot1_print_info();
multiboot2_print_info();
#endif
#if NCARDBUS > 0
rbus_min_start_hint(ctob((psize_t)physmem));
#endif
minaddr = 0;
phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
VM_PHYS_SIZE, 0, false, NULL);
banner();
#if NISA > 0 || NPCI > 0
x86_bus_space_mallocok();
#endif
gdt_init();
i386_proc0_pcb_ldt_init();
cpu_init_tss(&cpu_info_primary);
#ifndef XENPV
ltr(cpu_info_primary.ci_tss_sel);
#endif
x86_startup();
}
static void
i386_proc0_pcb_ldt_init(void)
{
struct lwp *l = &lwp0;
struct pcb *pcb = lwp_getpcb(l);
pcb->pcb_cr0 = rcr0() & ~CR0_TS;
pcb->pcb_esp0 = uvm_lwp_getuarea(l) + USPACE - 16;
pcb->pcb_iopl = IOPL_KPL;
l->l_md.md_regs = (struct trapframe *)pcb->pcb_esp0 - 1;
memcpy(&pcb->pcb_fsd, &gdtstore[GUDATA_SEL], sizeof(pcb->pcb_fsd));
memcpy(&pcb->pcb_gsd, &gdtstore[GUDATA_SEL], sizeof(pcb->pcb_gsd));
pcb->pcb_dbregs = NULL;
#ifndef XENPV
lldt(GSEL(GLDT_SEL, SEL_KPL));
#else
HYPERVISOR_fpu_taskswitch(1);
HYPERVISOR_stack_switch(GSEL(GDATA_SEL, SEL_KPL), pcb->pcb_esp0);
#endif
}
#ifdef XENPV
void i386_switch_context(lwp_t *);
void i386_tls_switch(lwp_t *);
void
i386_switch_context(lwp_t *l)
{
struct pcb *pcb;
pcb = lwp_getpcb(l);
HYPERVISOR_stack_switch(GSEL(GDATA_SEL, SEL_KPL), pcb->pcb_esp0);
struct physdev_set_iopl set_iopl;
set_iopl.iopl = pcb->pcb_iopl;
HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
}
void
i386_tls_switch(lwp_t *l)
{
struct cpu_info *ci = curcpu();
struct pcb *pcb = lwp_getpcb(l);
(void)splhigh();
update_descriptor(&ci->ci_gdt[GUFS_SEL],
(union descriptor *)&pcb->pcb_fsd);
update_descriptor(&ci->ci_gdt[GUGS_SEL],
(union descriptor *)&pcb->pcb_gsd);
}
#endif
#define IDTVEC(name) __CONCAT(X, name)
typedef void (vector)(void);
#ifndef XENPV
static void tss_init(struct i386tss *, void *, void *);
static void
tss_init(struct i386tss *tss, void *stack, void *func)
{
KASSERT(curcpu()->ci_pmap == pmap_kernel());
memset(tss, 0, sizeof *tss);
tss->tss_esp0 = tss->tss_esp = (int)((char *)stack + USPACE - 16);
tss->tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
tss->__tss_cs = GSEL(GCODE_SEL, SEL_KPL);
tss->tss_fs = GSEL(GCPU_SEL, SEL_KPL);
tss->tss_gs = tss->__tss_es = tss->__tss_ds =
tss->__tss_ss = GSEL(GDATA_SEL, SEL_KPL);
tss->tss_cr3 = rcr3();
tss->tss_esp = (int)((char *)stack + USPACE - 16);
tss->tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
tss->__tss_eflags = PSL_MBO | PSL_NT;
tss->__tss_eip = (int)func;
}
extern vector IDTVEC(tss_trap08);
#if defined(DDB) && defined(MULTIPROCESSOR)
extern vector Xintr_ddbipi, Xintr_x2apic_ddbipi;
extern int ddb_vec;
#endif
void
cpu_set_tss_gates(struct cpu_info *ci)
{
struct segment_descriptor sd;
void *doubleflt_stack;
idt_descriptor_t *idt;
doubleflt_stack = (void *)uvm_km_alloc(kernel_map, USPACE, 0,
UVM_KMF_WIRED);
tss_init(&ci->ci_tss->dblflt_tss, doubleflt_stack, IDTVEC(tss_trap08));
setsegment(&sd, &ci->ci_tss->dblflt_tss, sizeof(struct i386tss) - 1,
SDT_SYS386TSS, SEL_KPL, 0, 0);
ci->ci_gdt[GTRAPTSS_SEL].sd = sd;
idt = cpu_info_primary.ci_idtvec.iv_idt;
set_idtgate(&idt[8], NULL, 0, SDT_SYSTASKGT, SEL_KPL,
GSEL(GTRAPTSS_SEL, SEL_KPL));
#if defined(DDB) && defined(MULTIPROCESSOR)
void *ddbipi_stack;
ddbipi_stack = (void *)uvm_km_alloc(kernel_map, USPACE, 0,
UVM_KMF_WIRED);
tss_init(&ci->ci_tss->ddbipi_tss, ddbipi_stack,
x2apic_mode ? Xintr_x2apic_ddbipi : Xintr_ddbipi);
setsegment(&sd, &ci->ci_tss->ddbipi_tss, sizeof(struct i386tss) - 1,
SDT_SYS386TSS, SEL_KPL, 0, 0);
ci->ci_gdt[GIPITSS_SEL].sd = sd;
set_idtgate(&idt[ddb_vec], NULL, 0, SDT_SYSTASKGT, SEL_KPL,
GSEL(GIPITSS_SEL, SEL_KPL));
#endif
}
#endif
void
cpu_init_tss(struct cpu_info *ci)
{
struct cpu_tss *cputss;
cputss = (struct cpu_tss *)uvm_km_alloc(kernel_map,
sizeof(struct cpu_tss), 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
cputss->tss.tss_iobase = IOMAP_INVALOFF << 16;
#ifndef XENPV
cputss->tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
cputss->tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
cputss->tss.tss_cr3 = rcr3();
#endif
ci->ci_tss = cputss;
#ifndef XENPV
ci->ci_tss_sel = tss_alloc(&cputss->tss);
#endif
}
void *
getframe(struct lwp *l, int sig, int *onstack)
{
struct proc *p = l->l_proc;
struct trapframe *tf = l->l_md.md_regs;
*onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0
&& (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
if (*onstack)
return (char *)l->l_sigstk.ss_sp + l->l_sigstk.ss_size;
return (void *)tf->tf_esp;
}
void
buildcontext(struct lwp *l, int sel, void *catcher, void *fp)
{
struct trapframe *tf = l->l_md.md_regs;
tf->tf_gs = GSEL(GUGS_SEL, SEL_UPL);
tf->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_eip = (int)catcher;
tf->tf_cs = GSEL(sel, SEL_UPL);
tf->tf_eflags &= ~PSL_CLEARSIG;
tf->tf_esp = (int)fp;
tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
fpu_sigreset(l);
}
void
sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask)
{
struct lwp *l = curlwp;
struct proc *p = l->l_proc;
struct pmap *pmap = vm_map_pmap(&p->p_vmspace->vm_map);
int sel = pmap->pm_hiexec > I386_MAX_EXE_ADDR ?
GUCODEBIG_SEL : GUCODE_SEL;
struct sigacts *ps = p->p_sigacts;
int onstack, error;
int sig = ksi->ksi_signo;
struct sigframe_siginfo *fp, frame;
sig_t catcher = SIGACTION(p, sig).sa_handler;
struct trapframe *tf = l->l_md.md_regs;
const struct xsave_header *xsavebuf = NULL;
size_t xsavelen = 0;
struct xsave_header *user_xsave = NULL;
char *sp;
KASSERT(mutex_owned(p->p_lock));
onstack =
(l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
(SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
if (onstack) {
KASSERT(l->l_sigstk.ss_size >= MINSIGSTKSZ);
sp = ((char *)l->l_sigstk.ss_sp + l->l_sigstk.ss_size);
} else {
sp = (char *)tf->tf_esp;
}
__CTASSERT(STACK_ALIGNBYTES + sizeof(struct sigframe_siginfo) +
(XSAVE_ALIGN - 1) + XSAVE_MAX_BYTES <= MINSIGSTKSZ);
if (process_xsave_needed_p(l)) {
process_read_xsave(l, &xsavebuf, &xsavelen);
KASSERT(xsavebuf != NULL);
KASSERT(xsavelen <= XSAVE_MAX_BYTES);
KASSERT(!onstack || sp >= (char *)l->l_sigstk.ss_sp);
KASSERT(!onstack ||
sp - (char *)l->l_sigstk.ss_sp >= xsavelen);
sp -= xsavelen;
KASSERT(!onstack || sp >= (char *)l->l_sigstk.ss_sp);
KASSERT(!onstack ||
sp - (char *)l->l_sigstk.ss_sp >= XSAVE_ALIGN - 1);
sp = (char *)((uintptr_t)sp & ~(XSAVE_ALIGN - 1));
KASSERT(!onstack || sp >= (char *)l->l_sigstk.ss_sp);
KASSERT(((uintptr_t)sp & (XSAVE_ALIGN - 1)) == 0);
user_xsave = (void *)sp;
}
KASSERT(!onstack || sp >= (char *)l->l_sigstk.ss_sp);
KASSERT(!onstack || (size_t)(sp - (char *)l->l_sigstk.ss_sp) >=
STACK_ALIGNBYTES + sizeof(struct sigframe_siginfo));
fp = (struct sigframe_siginfo *)sp;
fp--;
fp = (struct sigframe_siginfo *)((uintptr_t)fp & ~STACK_ALIGNBYTES);
memset(&frame, 0, sizeof(frame));
frame.sf_ra = (int)ps->sa_sigdesc[sig].sd_tramp;
frame.sf_signum = sig;
frame.sf_sip = &fp->sf_si;
frame.sf_ucp = &fp->sf_uc;
frame.sf_si._info = ksi->ksi_info;
frame.sf_uc.uc_flags = _UC_SIGMASK|_UC_VM;
frame.sf_uc.uc_sigmask = *mask;
frame.sf_uc.uc_link = l->l_ctxlink;
frame.sf_uc.uc_flags |= (l->l_sigstk.ss_flags & SS_ONSTACK)
? _UC_SETSTACK : _UC_CLRSTACK;
sendsig_reset(l, sig);
mutex_exit(p->p_lock);
cpu_getmcontext(l, &frame.sf_uc.uc_mcontext, &frame.sf_uc.uc_flags);
if (xsavebuf) {
error = cpu_getmcontext_xsave(l, &frame.sf_uc.uc_mcontext,
&frame.sf_uc.uc_flags, xsavebuf, xsavelen, user_xsave);
if (error != 0)
goto relock;
}
error = copyout(&frame, fp, sizeof(frame));
relock:
mutex_enter(p->p_lock);
if (error != 0) {
sigexit(l, SIGILL);
}
buildcontext(l, sel, catcher, fp);
if (onstack)
l->l_sigstk.ss_flags |= SS_ONSTACK;
}
static void
maybe_dump(int howto)
{
int s;
s = splhigh();
if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
dumpsys();
splx(s);
}
void
cpu_reboot(int howto, char *bootstr)
{
static bool syncdone = false;
int s = IPL_NONE;
if (cold) {
howto |= RB_HALT;
goto haltsys;
}
boothowto = howto;
maybe_dump(howto);
if ((howto & RB_NOSYNC) == 0 && panicstr == NULL) {
if (!syncdone) {
syncdone = true;
vfs_sync_all(curlwp);
}
while (vfs_unmountall1(curlwp, false, false) ||
config_detach_all(boothowto) ||
vfs_unmount_forceone(curlwp))
;
} else {
if (!db_active)
suspendsched();
}
pmf_system_shutdown(boothowto);
s = splhigh();
haltsys:
doshutdownhooks();
if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
#if NACPICA > 0
if (s != IPL_NONE)
splx(s);
acpi_enter_sleep_state(ACPI_STATE_S5);
#else
__USE(s);
#endif
#ifdef XEN
if (vm_guest == VM_GUEST_XENPV ||
vm_guest == VM_GUEST_XENPVH ||
vm_guest == VM_GUEST_XENPVHVM)
HYPERVISOR_shutdown();
#endif
}
#ifdef MULTIPROCESSOR
cpu_broadcast_halt();
#endif
if (howto & RB_HALT) {
#if NACPICA > 0
acpi_disable();
#endif
printf("\n");
printf("The operating system has halted.\n");
printf("Please press any key to reboot.\n\n");
#ifdef BEEP_ONHALT
{
int c;
for (c = BEEP_ONHALT_COUNT; c > 0; c--) {
sysbeep(BEEP_ONHALT_PITCH,
BEEP_ONHALT_PERIOD * hz / 1000);
delay(BEEP_ONHALT_PERIOD * 1000);
sysbeep(0, BEEP_ONHALT_PERIOD * hz / 1000);
delay(BEEP_ONHALT_PERIOD * 1000);
}
}
#endif
cnpollc(true);
if (cngetc() == 0) {
printf("No keyboard - cannot reboot after all.\n");
for(;;) {
x86_hlt();
}
}
cnpollc(false);
}
printf("rebooting...\n");
if (cpureset_delay > 0)
delay(cpureset_delay * 1000);
cpu_reset();
for(;;) ;
}
void
setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
{
struct pmap *pmap = vm_map_pmap(&l->l_proc->p_vmspace->vm_map);
struct pcb *pcb = lwp_getpcb(l);
struct trapframe *tf;
#ifdef USER_LDT
pmap_ldt_cleanup(l);
#endif
fpu_clear(l, pack->ep_osversion >= 699002600
? __INITIAL_NPXCW__ : __NetBSD_COMPAT_NPXCW__);
memcpy(&pcb->pcb_fsd, &gdtstore[GUDATA_SEL], sizeof(pcb->pcb_fsd));
memcpy(&pcb->pcb_gsd, &gdtstore[GUDATA_SEL], sizeof(pcb->pcb_gsd));
x86_dbregs_clear(l);
tf = l->l_md.md_regs;
memset(tf, 0, sizeof(*tf));
tf->tf_trapno = T_ASTFLT;
tf->tf_gs = GSEL(GUGS_SEL, SEL_UPL);
tf->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL);
tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL);
tf->tf_edi = 0;
tf->tf_esi = 0;
tf->tf_ebp = 0;
tf->tf_ebx = l->l_proc->p_psstrp;
tf->tf_edx = 0;
tf->tf_ecx = 0;
tf->tf_eax = 0;
tf->tf_eip = pack->ep_entry;
tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ?
LSEL(LUCODEBIG_SEL, SEL_UPL) : LSEL(LUCODE_SEL, SEL_UPL);
tf->tf_eflags = PSL_USERSET;
tf->tf_esp = stack;
tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL);
}
union descriptor *gdtstore, *ldtstore;
union descriptor *pentium_idt;
extern vaddr_t lwp0uarea;
void
setgate(struct gate_descriptor *gd, void *func, int args, int type, int dpl,
int sel)
{
gd->gd_looffset = (int)func;
gd->gd_selector = sel;
gd->gd_stkcpy = args;
gd->gd_xx = 0;
gd->gd_type = type;
gd->gd_dpl = dpl;
gd->gd_p = 1;
gd->gd_hioffset = (int)func >> 16;
}
void
unsetgate(struct gate_descriptor *gd)
{
gd->gd_p = 0;
gd->gd_hioffset = 0;
gd->gd_looffset = 0;
gd->gd_selector = 0;
gd->gd_xx = 0;
gd->gd_stkcpy = 0;
gd->gd_type = 0;
gd->gd_dpl = 0;
}
void
setregion(struct region_descriptor *rd, void *base, size_t limit)
{
rd->rd_limit = (int)limit;
rd->rd_base = (int)base;
}
void
setsegment(struct segment_descriptor *sd, const void *base, size_t limit,
int type, int dpl, int def32, int gran)
{
sd->sd_lolimit = (int)limit;
sd->sd_lobase = (int)base;
sd->sd_type = type;
sd->sd_dpl = dpl;
sd->sd_p = 1;
sd->sd_hilimit = (int)limit >> 16;
sd->sd_xx = 0;
sd->sd_def32 = def32;
sd->sd_gran = gran;
sd->sd_hibase = (int)base >> 24;
}
extern vector IDTVEC(syscall);
extern vector *IDTVEC(exceptions)[];
#ifdef XENPV
extern union descriptor tmpgdt[];
#endif
void
cpu_init_idt(struct cpu_info *ci)
{
struct region_descriptor region;
struct idt_vec *iv;
idt_descriptor_t *idt;
iv = &ci->ci_idtvec;
idt = iv->iv_idt_pentium;
setregion(®ion, idt, NIDT * sizeof(idt[0]) - 1);
lidt(®ion);
}
void
initgdt(union descriptor *tgdt)
{
KASSERT(tgdt != NULL);
gdtstore = tgdt;
#ifdef XENPV
u_long frames[16];
#else
struct region_descriptor region;
memset(gdtstore, 0, NGDT * sizeof(*gdtstore));
#endif
setsegment(&gdtstore[GCODE_SEL].sd, 0, 0xfffff,
SDT_MEMERA, SEL_KPL, 1, 1);
setsegment(&gdtstore[GDATA_SEL].sd, 0, 0xfffff,
SDT_MEMRWA, SEL_KPL, 1, 1);
setsegment(&gdtstore[GUCODE_SEL].sd, 0, x86_btop(I386_MAX_EXE_ADDR) - 1,
SDT_MEMERA, SEL_UPL, 1, 1);
setsegment(&gdtstore[GUCODEBIG_SEL].sd, 0, 0xfffff,
SDT_MEMERA, SEL_UPL, 1, 1);
setsegment(&gdtstore[GUDATA_SEL].sd, 0, 0xfffff,
SDT_MEMRWA, SEL_UPL, 1, 1);
#if NBIOSCALL > 0 && !defined(XENPV)
setsegment(&gdtstore[GBIOSCODE_SEL].sd, 0, 0xfffff,
SDT_MEMERA, SEL_KPL, 0, 0);
setsegment(&gdtstore[GBIOSDATA_SEL].sd, 0, 0xfffff,
SDT_MEMRWA, SEL_KPL, 0, 0);
#endif
setsegment(&gdtstore[GCPU_SEL].sd, &cpu_info_primary,
sizeof(struct cpu_info) - 1, SDT_MEMRWA, SEL_KPL, 1, 0);
#ifndef XENPV
setregion(®ion, gdtstore, NGDT * sizeof(gdtstore[0]) - 1);
lgdt(®ion);
#else
xpmap_phys_to_machine_mapping =
(unsigned long *)xen_start_info.mfn_list;
frames[0] = xpmap_ptom((uint32_t)gdtstore - KERNBASE) >> PAGE_SHIFT;
{
extern pt_entry_t xpmap_pg_nx;
pt_entry_t pte;
pte = pmap_pa2pte((vaddr_t)gdtstore - KERNBASE);
pte |= xpmap_pg_nx | PTE_P;
if (HYPERVISOR_update_va_mapping((vaddr_t)gdtstore, pte,
UVMF_INVLPG) < 0) {
panic("gdt page RO update failed.\n");
}
}
if (HYPERVISOR_set_gdt(frames, NGDT ))
panic("HYPERVISOR_set_gdt failed!\n");
lgdt_finish();
#endif
}
#if !defined(XENPV) && NBIOSCALL > 0
static void
init386_pte0(void)
{
paddr_t paddr;
vaddr_t vaddr;
paddr = 4 * PAGE_SIZE;
vaddr = (vaddr_t)vtopte(0);
pmap_kenter_pa(vaddr, paddr, VM_PROT_ALL, 0);
pmap_update(pmap_kernel());
memset((void *)vaddr, 0, PAGE_SIZE);
}
#endif
#ifndef XENPV
static void
init386_ksyms(void)
{
#if NKSYMS || defined(DDB) || defined(MODULAR)
extern int end;
struct btinfo_symtab *symtab;
#ifdef DDB
db_machine_init();
#endif
#if defined(MULTIBOOT)
if (multiboot1_ksyms_addsyms_elf())
return;
if (multiboot2_ksyms_addsyms_elf())
return;
#endif
#ifdef XEN
if (pvh_boot && vm_guest != VM_GUEST_XENPVH) {
ksyms_addsyms_elf(0, ((int *)&end) + 1, esym);
return;
}
#endif
if ((symtab = lookup_bootinfo(BTINFO_SYMTAB)) == NULL) {
ksyms_addsyms_elf(*(int *)&end, ((int *)&end) + 1, esym);
return;
}
symtab->ssym += KERNBASE;
symtab->esym += KERNBASE;
ksyms_addsyms_elf(symtab->nsym, (int *)symtab->ssym, (int *)symtab->esym);
#endif
}
#endif
void
init_bootspace(void)
{
extern char __rodata_start;
extern char __data_start;
extern char __kernel_end;
size_t i = 0;
memset(&bootspace, 0, sizeof(bootspace));
bootspace.head.va = KERNTEXTOFF;
bootspace.head.pa = KERNTEXTOFF - KERNBASE;
bootspace.head.sz = 0;
bootspace.segs[i].type = BTSEG_TEXT;
bootspace.segs[i].va = KERNTEXTOFF;
bootspace.segs[i].pa = KERNTEXTOFF - KERNBASE;
bootspace.segs[i].sz = (size_t)&__rodata_start - KERNTEXTOFF;
i++;
bootspace.segs[i].type = BTSEG_RODATA;
bootspace.segs[i].va = (vaddr_t)&__rodata_start;
bootspace.segs[i].pa = (paddr_t)(vaddr_t)&__rodata_start - KERNBASE;
bootspace.segs[i].sz = (size_t)&__data_start - (size_t)&__rodata_start;
i++;
bootspace.segs[i].type = BTSEG_DATA;
bootspace.segs[i].va = (vaddr_t)&__data_start;
bootspace.segs[i].pa = (paddr_t)(vaddr_t)&__data_start - KERNBASE;
bootspace.segs[i].sz = (size_t)&__kernel_end - (size_t)&__data_start;
i++;
bootspace.boot.va = (vaddr_t)&__kernel_end;
bootspace.boot.pa = (paddr_t)(vaddr_t)&__kernel_end - KERNBASE;
bootspace.boot.sz = (size_t)(atdevbase + IOM_SIZE) -
(size_t)&__kernel_end;
bootspace.pdir = (vaddr_t)(PDPpaddr + KERNBASE);
}
void
init386(paddr_t first_avail)
{
extern void consinit(void);
int x;
#ifndef XENPV
extern paddr_t local_apic_pa;
union descriptor *tgdt;
struct region_descriptor region;
#if NBIOSCALL > 0
extern int biostramp_image_size;
extern u_char biostramp_image[];
#endif
#endif
struct pcb *pcb;
struct idt_vec *iv;
idt_descriptor_t *idt;
KASSERT(first_avail % PAGE_SIZE == 0);
#ifdef XENPV
KASSERT(HYPERVISOR_shared_info != NULL);
cpu_info_primary.ci_vcpu = &HYPERVISOR_shared_info->vcpu_info[0];
#endif
#ifdef XEN
if (pvh_boot)
xen_parse_cmdline(XEN_PARSE_BOOTFLAGS, NULL);
#endif
uvm_lwp_setuarea(&lwp0, lwp0uarea);
cpu_probe(&cpu_info_primary);
cpu_init_msrs(&cpu_info_primary, true);
#ifndef XENPV
cpu_speculation_init(&cpu_info_primary);
#endif
#ifdef PAE
use_pae = 1;
#else
use_pae = 0;
#endif
pcb = lwp_getpcb(&lwp0);
#ifdef XENPV
pcb->pcb_cr3 = PDPpaddr;
#endif
#if defined(PAE) && !defined(XENPV)
cpu_info_primary.ci_pae_l3_pdirpa = rcr3();
cpu_info_primary.ci_pae_l3_pdir = (pd_entry_t *)(rcr3() + KERNBASE);
#endif
uvm_md_init();
uvmexp.ncolors = 2;
avail_start = first_avail;
#ifndef XENPV
lowmem_rsvd = 6 * PAGE_SIZE;
#else
xen_parse_cmdline(XEN_PARSE_BOOTFLAGS, NULL);
extern vaddr_t xen_dummy_page;
gdtstore = (void *)xen_dummy_page;
avail_end = ctob((paddr_t)xen_start_info.nr_pages);
pmap_pa_start = (KERNTEXTOFF - KERNBASE);
pmap_pa_end = pmap_pa_start + ctob((paddr_t)xen_start_info.nr_pages);
mem_clusters[0].start = avail_start;
mem_clusters[0].size = avail_end - avail_start;
mem_cluster_cnt++;
physmem += xen_start_info.nr_pages;
uvmexp.wired += atop(avail_start);
initgdt(gdtstore);
mutex_init(&pte_lock, MUTEX_DEFAULT, IPL_VM);
#endif
#if NISA > 0 || NPCI > 0
x86_bus_space_init();
#endif
consinit();
#ifdef DEBUG_MEMLOAD
printf("mem_cluster_count: %d\n", mem_cluster_cnt);
#endif
pmap_bootstrap((vaddr_t)atdevbase + IOM_SIZE);
cpu_rng_init();
x86_rndseed();
#ifndef XENPV
init_x86_clusters();
init_x86_vm(avail_start);
#else
uvm_page_physload(atop(avail_start), atop(avail_end),
atop(avail_start), atop(avail_end),
VM_FREELIST_DEFAULT);
{
extern pt_entry_t xpmap_pg_nx;
pt_entry_t pte;
pte = pmap_pa2pte((vaddr_t)tmpgdt - KERNBASE);
pte |= PTE_W | xpmap_pg_nx | PTE_P;
if (HYPERVISOR_update_va_mapping((vaddr_t)tmpgdt, pte, UVMF_INVLPG) < 0) {
panic("tmpgdt page relaim RW update failed.\n");
}
}
#endif
init_x86_msgbuf();
#if !defined(XENPV) && NBIOSCALL > 0
init386_pte0();
KASSERT(biostramp_image_size <= PAGE_SIZE);
pmap_kenter_pa((vaddr_t)BIOSTRAMP_BASE, (paddr_t)BIOSTRAMP_BASE,
VM_PROT_ALL, 0);
pmap_update(pmap_kernel());
memcpy((void *)BIOSTRAMP_BASE, biostramp_image, biostramp_image_size);
cpu_info_primary.ci_pmap = pmap_kernel();
#endif
#ifndef XENPV
pmap_kenter_pa(local_apic_va, local_apic_pa,
VM_PROT_READ|VM_PROT_WRITE, 0);
pmap_update(pmap_kernel());
memset((void *)local_apic_va, 0, PAGE_SIZE);
#endif
pmap_kenter_pa(idt_vaddr, idt_paddr, VM_PROT_READ|VM_PROT_WRITE, 0);
pmap_kenter_pa(gdt_vaddr, gdt_paddr, VM_PROT_READ|VM_PROT_WRITE, 0);
pmap_kenter_pa(ldt_vaddr, ldt_paddr, VM_PROT_READ|VM_PROT_WRITE, 0);
pmap_update(pmap_kernel());
memset((void *)idt_vaddr, 0, PAGE_SIZE);
memset((void *)gdt_vaddr, 0, PAGE_SIZE);
memset((void *)ldt_vaddr, 0, PAGE_SIZE);
pmap_kenter_pa(pentium_idt_vaddr, idt_paddr, VM_PROT_READ, 0);
pmap_update(pmap_kernel());
iv = &(cpu_info_primary.ci_idtvec);
idt_vec_init_cpu_md(iv, cpu_index(&cpu_info_primary));
idt = (idt_descriptor_t *)iv->iv_idt;
#ifndef XENPV
tgdt = gdtstore;
gdtstore = (union descriptor *)gdt_vaddr;
ldtstore = (union descriptor *)ldt_vaddr;
memcpy(gdtstore, tgdt, NGDT * sizeof(*gdtstore));
setsegment(&gdtstore[GLDT_SEL].sd, ldtstore,
NLDT * sizeof(ldtstore[0]) - 1, SDT_SYSLDT, SEL_KPL, 0, 0);
#else
HYPERVISOR_set_callbacks(
GSEL(GCODE_SEL, SEL_KPL), (unsigned long)hypervisor_callback,
GSEL(GCODE_SEL, SEL_KPL), (unsigned long)failsafe_callback);
ldtstore = (union descriptor *)ldt_vaddr;
#endif
ldtstore[LUCODE_SEL] = gdtstore[GUCODE_SEL];
ldtstore[LUCODEBIG_SEL] = gdtstore[GUCODEBIG_SEL];
ldtstore[LUDATA_SEL] = gdtstore[GUDATA_SEL];
for (x = 0; x < 32; x++) {
int sel;
#ifdef XENPV
sel = SEL_XEN;
#else
sel = SEL_KPL;
#endif
idt_vec_reserve(iv, x);
switch (x) {
#ifdef XENPV
case 2:
case 18:
sel |= 0x4;
break;
#endif
case 3:
case 4:
sel = SEL_UPL;
break;
default:
break;
}
set_idtgate(&idt[x], IDTVEC(exceptions)[x], 0, SDT_SYS386IGT,
sel, GSEL(GCODE_SEL, SEL_KPL));
}
idt_vec_reserve(iv, 128);
set_idtgate(&idt[128], &IDTVEC(syscall), 0, SDT_SYS386IGT, SEL_UPL,
GSEL(GCODE_SEL, SEL_KPL));
#ifndef XENPV
setregion(®ion, gdtstore, NGDT * sizeof(gdtstore[0]) - 1);
lgdt(®ion);
#endif
lldt(GSEL(GLDT_SEL, SEL_KPL));
cpu_init_idt(&cpu_info_primary);
#ifdef XENPV
xen_init_ksyms();
#else
#ifdef XEN
if (vm_guest == VM_GUEST_XENPVH)
xen_init_ksyms();
else
#endif
init386_ksyms();
#endif
#if NMCA > 0
if (lookup_bootinfo(BTINFO_EFI) == NULL && vm_guest != VM_GUEST_XENPVH)
mca_busprobe();
#endif
#ifdef XENPV
extern int tmpstk;
cpu_info_primary.ci_intrstack = &tmpstk;
events_default_setup();
#else
intr_default_setup();
#endif
splraise(IPL_HIGH);
x86_enable_intr();
#ifdef DDB
if (boothowto & RB_KDB)
Debugger();
#endif
#ifdef KGDB
kgdb_port_init();
if (boothowto & RB_KDB) {
kgdb_debug_init = 1;
kgdb_connect(1);
}
#endif
if (physmem < btoc(2 * 1024 * 1024)) {
printf("warning: too little memory available; "
"have %lu bytes, want %lu bytes\n"
"running in degraded mode\n"
"press a key to confirm\n\n",
(unsigned long)ptoa(physmem), 2*1024*1024UL);
cngetc();
}
pcb->pcb_dbregs = NULL;
x86_dbregs_init();
}
#include <dev/ic/mc146818reg.h>
#include <i386/isa/nvram.h>
void
cpu_reset(void)
{
#ifdef XENPV
HYPERVISOR_reboot();
for (;;);
#else
struct region_descriptor region;
idt_descriptor_t *idt;
idt = (idt_descriptor_t *)cpu_info_primary.ci_idtvec.iv_idt;
x86_disable_intr();
outb(IO_RTC, NVRAM_RESET);
outb(IO_RTC+1, NVRAM_RESET_RST);
if (cpu_info_primary.ci_signature == 0x540) {
outl(0xcf8, 0x80009044);
outl(0xcfc, 0xf);
}
x86_reset();
memset((void *)idt, 0, NIDT * sizeof(idt[0]));
setregion(®ion, idt, NIDT * sizeof(idt[0]) - 1);
lidt(®ion);
breakpoint();
#if 0
memset((void *)PTD, 0, PAGE_SIZE);
tlbflush();
#endif
for (;;);
#endif
}
void
cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
{
const struct trapframe *tf = l->l_md.md_regs;
__greg_t *gr = mcp->__gregs;
__greg_t ras_eip;
gr[_REG_GS] = tf->tf_gs;
gr[_REG_FS] = tf->tf_fs;
gr[_REG_ES] = tf->tf_es;
gr[_REG_DS] = tf->tf_ds;
gr[_REG_EFL] = tf->tf_eflags;
gr[_REG_EDI] = tf->tf_edi;
gr[_REG_ESI] = tf->tf_esi;
gr[_REG_EBP] = tf->tf_ebp;
gr[_REG_EBX] = tf->tf_ebx;
gr[_REG_EDX] = tf->tf_edx;
gr[_REG_ECX] = tf->tf_ecx;
gr[_REG_EAX] = tf->tf_eax;
gr[_REG_EIP] = tf->tf_eip;
gr[_REG_CS] = tf->tf_cs;
gr[_REG_ESP] = tf->tf_esp;
gr[_REG_UESP] = tf->tf_esp;
gr[_REG_SS] = tf->tf_ss;
gr[_REG_TRAPNO] = tf->tf_trapno;
gr[_REG_ERR] = tf->tf_err;
if ((ras_eip = (__greg_t)ras_lookup(l->l_proc,
(void *) gr[_REG_EIP])) != -1)
gr[_REG_EIP] = ras_eip;
*flags |= _UC_CPU;
mcp->_mc_tlsbase = (uintptr_t)l->l_private;
*flags |= _UC_TLSBASE;
__CTASSERT(sizeof (struct fxsave) ==
sizeof mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
process_read_fpregs_xmm(l, (struct fxsave *)
&mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
memset(&mcp->__fpregs.__fp_pad, 0, sizeof mcp->__fpregs.__fp_pad);
*flags |= _UC_FXSAVE | _UC_FPU;
}
static int
cpu_getmcontext_xsave(struct lwp *l, mcontext_t *mcp, unsigned int *flags,
const struct xsave_header *xsavebuf, size_t xsavelen,
struct xsave_header *user_xsave)
{
int error;
KASSERT(*flags & _UC_FPU);
KASSERT(*flags & _UC_FXSAVE);
error = copyout(xsavebuf, user_xsave, xsavelen);
if (error != 0)
return error;
mcp->__fpregs.__fp_reg_set.__xsave.__xsaveptr =
(__greg_t)(uintptr_t)user_xsave;
mcp->__fpregs.__fp_reg_set.__xsave.__xsavelen = (__greg_t)xsavelen;
*flags |= _UC_XSAVE;
return 0;
}
int
cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
{
const __greg_t *gr = mcp->__gregs;
struct trapframe *tf = l->l_md.md_regs;
if (((gr[_REG_EFL] ^ tf->tf_eflags) & PSL_USERSTATIC) ||
!USERMODE(gr[_REG_CS]))
return EINVAL;
return 0;
}
int
cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
{
struct trapframe *tf = l->l_md.md_regs;
const __greg_t *gr = mcp->__gregs;
struct proc *p = l->l_proc;
struct xsave_header *xsavebuf = NULL;
size_t xsavelen = 0;
int error;
if ((flags & _UC_XSAVE) != 0) {
const __greg_t user_xsave =
mcp->__fpregs.__fp_reg_set.__xsave.__xsaveptr;
xsavelen = mcp->__fpregs.__fp_reg_set.__xsave.__xsavelen;
error = process_verify_xsavelen(l, xsavelen);
if (error != 0)
goto out;
xsavebuf = kmem_alloc(xsavelen, KM_SLEEP);
error = copyin((const void *)user_xsave, xsavebuf, xsavelen);
if (error != 0)
goto out;
error = process_verify_xsave(l, xsavebuf, xsavelen);
if (error != 0)
goto out;
}
if ((flags & _UC_CPU) != 0) {
error = cpu_mcontext_validate(l, mcp);
if (error)
return error;
tf->tf_gs = gr[_REG_GS];
tf->tf_fs = gr[_REG_FS];
tf->tf_es = gr[_REG_ES];
tf->tf_ds = gr[_REG_DS];
tf->tf_eflags &= ~PSL_USER;
tf->tf_eflags |= (gr[_REG_EFL] & PSL_USER);
tf->tf_edi = gr[_REG_EDI];
tf->tf_esi = gr[_REG_ESI];
tf->tf_ebp = gr[_REG_EBP];
tf->tf_ebx = gr[_REG_EBX];
tf->tf_edx = gr[_REG_EDX];
tf->tf_ecx = gr[_REG_ECX];
tf->tf_eax = gr[_REG_EAX];
tf->tf_eip = gr[_REG_EIP];
tf->tf_cs = gr[_REG_CS];
tf->tf_esp = gr[_REG_UESP];
tf->tf_ss = gr[_REG_SS];
}
if ((flags & _UC_TLSBASE) != 0)
lwp_setprivate(l, (void *)(uintptr_t)mcp->_mc_tlsbase);
if ((flags & _UC_XSAVE) != 0) {
KASSERT(xsavebuf != NULL);
process_write_xsave(l, xsavebuf, xsavelen);
} else if ((flags & _UC_FPU) != 0) {
__CTASSERT(sizeof (struct fxsave) ==
sizeof mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
__CTASSERT(sizeof (struct save87) ==
sizeof mcp->__fpregs.__fp_reg_set.__fpchip_state);
if (flags & _UC_FXSAVE) {
process_write_fpregs_xmm(l, (const struct fxsave *)
&mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
} else {
process_write_fpregs_s87(l, (const struct save87 *)
&mcp->__fpregs.__fp_reg_set.__fpchip_state);
}
}
mutex_enter(p->p_lock);
if (flags & _UC_SETSTACK)
l->l_sigstk.ss_flags |= SS_ONSTACK;
if (flags & _UC_CLRSTACK)
l->l_sigstk.ss_flags &= ~SS_ONSTACK;
mutex_exit(p->p_lock);
error = 0;
out: if (xsavebuf)
kmem_free(xsavebuf, xsavelen);
return error;
}
#define DEV_IO 14
int
mm_md_open(dev_t dev, int flag, int mode, struct lwp *l)
{
switch (minor(dev)) {
case DEV_IO:
if (flag & FWRITE) {
struct trapframe *fp;
int error;
error = kauth_authorize_machdep(l->l_cred,
KAUTH_MACHDEP_IOPL, NULL, NULL, NULL, NULL);
if (error)
return (error);
fp = curlwp->l_md.md_regs;
fp->tf_eflags |= PSL_IOPL;
}
break;
default:
break;
}
return 0;
}
#ifdef PAE
void
cpu_alloc_l3_page(struct cpu_info *ci)
{
int ret;
struct pglist pg;
struct vm_page *vmap;
KASSERT(ci != NULL);
ret = uvm_pglistalloc(PAGE_SIZE, 0, 0x100000000ULL, 32, 0, &pg, 1, 0);
vmap = TAILQ_FIRST(&pg);
if (ret != 0 || vmap == NULL)
panic("%s: failed to allocate L3 pglist for CPU %d (ret %d)\n",
__func__, cpu_index(ci), ret);
ci->ci_pae_l3_pdirpa = VM_PAGE_TO_PHYS(vmap);
ci->ci_pae_l3_pdir = (paddr_t *)uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
UVM_KMF_VAONLY | UVM_KMF_NOWAIT);
if (ci->ci_pae_l3_pdir == NULL)
panic("%s: failed to allocate L3 PD for CPU %d\n",
__func__, cpu_index(ci));
pmap_kenter_pa((vaddr_t)ci->ci_pae_l3_pdir, ci->ci_pae_l3_pdirpa,
VM_PROT_READ | VM_PROT_WRITE, 0);
pmap_update(pmap_kernel());
}
#endif
static void
idt_vec_copy(struct idt_vec *dst, struct idt_vec *src)
{
idt_descriptor_t *idt_dst;
idt_dst = dst->iv_idt;
memcpy(idt_dst, src->iv_idt, PAGE_SIZE);
memcpy(dst->iv_allocmap, src->iv_allocmap, sizeof(dst->iv_allocmap));
}
void
idt_vec_init_cpu_md(struct idt_vec *iv, cpuid_t cid)
{
vaddr_t va_idt, va_pentium_idt;
struct vm_page *pg;
if (idt_vec_is_pcpu() &&
cid != cpu_index(&cpu_info_primary)) {
va_idt = uvm_km_alloc(kernel_map, PAGE_SIZE,
0, UVM_KMF_VAONLY);
pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
if (pg == NULL) {
panic("failed to allocate pcpu idt PA");
}
pmap_kenter_pa(va_idt, VM_PAGE_TO_PHYS(pg),
VM_PROT_READ|VM_PROT_WRITE, 0);
pmap_update(pmap_kernel());
memset((void *)va_idt, 0, PAGE_SIZE);
va_pentium_idt = uvm_km_alloc(kernel_map, PAGE_SIZE,
0, UVM_KMF_VAONLY);
pmap_kenter_pa(va_pentium_idt, VM_PAGE_TO_PHYS(pg),
VM_PROT_READ, 0);
pmap_update(pmap_kernel());
iv->iv_idt = (void *)va_idt;
iv->iv_idt_pentium = (void *)va_pentium_idt;
idt_vec_copy(iv, &(cpu_info_primary.ci_idtvec));
} else {
iv->iv_idt = (void *)idt_vaddr;
iv->iv_idt_pentium = (void *)pentium_idt_vaddr;
}
}