#include "opt_atpic.h"
#include "opt_cpu.h"
#include "opt_ddb.h"
#include "opt_inet.h"
#include "opt_isa.h"
#include "opt_kstack_pages.h"
#include "opt_maxmem.h"
#include "opt_pci.h"
#include "opt_platform.h"
#include "opt_sched.h"
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/asan.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/bus.h>
#include <sys/callout.h>
#include <sys/cons.h>
#include <sys/cpu.h>
#include <sys/csan.h>
#include <sys/efi.h>
#include <sys/eventhandler.h>
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/kdb.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/memrange.h>
#include <sys/msan.h>
#include <sys/msgbuf.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
#include <sys/ptrace.h>
#include <sys/reboot.h>
#include <sys/reg.h>
#include <sys/rwlock.h>
#include <sys/sched.h>
#include <sys/signalvar.h>
#include <sys/smp.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/ucontext.h>
#include <sys/vmmeter.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_extern.h>
#include <vm/vm_kern.h>
#include <vm/vm_page.h>
#include <vm/vm_map.h>
#include <vm/vm_object.h>
#include <vm/vm_pager.h>
#include <vm/vm_phys.h>
#include <vm/vm_dumpset.h>
#ifdef DDB
#ifndef KDB
#error KDB must be enabled in order for DDB to work!
#endif
#include <ddb/ddb.h>
#include <ddb/db_sym.h>
#endif
#include <net/netisr.h>
#include <dev/smbios/smbios.h>
#include <machine/clock.h>
#include <machine/cpu.h>
#include <machine/cputypes.h>
#include <machine/frame.h>
#include <machine/intr_machdep.h>
#include <x86/mca.h>
#include <machine/md_var.h>
#include <machine/metadata.h>
#include <machine/pc/bios.h>
#include <machine/pcb.h>
#include <machine/proc.h>
#include <machine/sigframe.h>
#include <machine/specialreg.h>
#include <machine/trap.h>
#include <machine/tss.h>
#include <x86/ucode.h>
#include <x86/ifunc.h>
#include <machine/smp.h>
#ifdef FDT
#include <x86/fdt.h>
#endif
#ifdef DEV_ATPIC
#include <x86/isa/icu.h>
#else
#include <x86/apicvar.h>
#endif
#include <isa/isareg.h>
#include <isa/rtc.h>
#include <x86/init.h>
#ifndef SMP
#error amd64 requires options SMP
#endif
CTASSERT(offsetof(struct pcpu, pc_curthread) == 0);
CTASSERT(PC_PTI_STACK_SZ * sizeof(register_t) >= 2 * sizeof(struct pti_frame) -
offsetof(struct pti_frame, pti_rip));
extern u_int64_t hammer_time(u_int64_t, u_int64_t);
static void cpu_startup(void *);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
static void native_clock_source_init(void);
static void native_parse_preload_data(u_int64_t);
static void native_parse_memmap(vm_paddr_t *, int *);
struct init_ops init_ops = {
.parse_preload_data = native_parse_preload_data,
.early_clock_source_init = native_clock_source_init,
.early_delay = i8254_delay,
.parse_memmap = native_parse_memmap,
};
vm_paddr_t efi_systbl_phys;
uint32_t efi_map_regs;
#define ICH_PMBASE 0x400
#define ICH_SMI_EN ICH_PMBASE + 0x30
int _udatasel, _ucodesel, _ucode32sel, _ufssel, _ugssel;
int cold = 1;
long Maxmem = 0;
long realmem = 0;
int late_console = 1;
int lass_enabled = 0;
struct kva_md_info kmi;
struct region_descriptor r_idt;
struct pcpu *__pcpu;
struct pcpu temp_bsp_pcpu;
struct mtx icu_lock;
struct mem_range_softc mem_range_softc;
struct mtx dt_lock;
void (*vmm_suspend_p)(void);
void (*vmm_resume_p)(void);
bool efi_boot;
static void
cpu_startup(void *dummy)
{
uintmax_t memsize;
char *sysenv;
sysenv = kern_getenv("smbios.system.product");
if (sysenv != NULL) {
if (strncmp(sysenv, "MacBook1,1", 10) == 0 ||
strncmp(sysenv, "MacBook3,1", 10) == 0 ||
strncmp(sysenv, "MacBook4,1", 10) == 0 ||
strncmp(sysenv, "MacBookPro1,1", 13) == 0 ||
strncmp(sysenv, "MacBookPro1,2", 13) == 0 ||
strncmp(sysenv, "MacBookPro3,1", 13) == 0 ||
strncmp(sysenv, "MacBookPro4,1", 13) == 0 ||
strncmp(sysenv, "Macmini1,1", 10) == 0) {
if (bootverbose)
printf("Disabling LEGACY_USB_EN bit on "
"Intel ICH.\n");
outl(ICH_SMI_EN, inl(ICH_SMI_EN) & ~0x8);
}
freeenv(sysenv);
}
startrtclock();
printcpuinfo();
memsize = 0;
sysenv = kern_getenv("smbios.memory.enabled");
if (sysenv != NULL) {
memsize = (uintmax_t)strtoul(sysenv, (char **)NULL, 10) << 10;
freeenv(sysenv);
}
if (memsize < ptoa((uintmax_t)vm_free_count()))
memsize = ptoa((uintmax_t)Maxmem);
printf("real memory = %ju (%ju MB)\n", memsize, memsize >> 20);
realmem = atop(memsize);
if (bootverbose) {
int indx;
printf("Physical memory chunk(s):\n");
for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) {
vm_paddr_t size;
size = phys_avail[indx + 1] - phys_avail[indx];
printf(
"0x%016jx - 0x%016jx, %ju bytes (%ju pages)\n",
(uintmax_t)phys_avail[indx],
(uintmax_t)phys_avail[indx + 1] - 1,
(uintmax_t)size, (uintmax_t)size / PAGE_SIZE);
}
}
vm_ksubmap_init(&kmi);
printf("avail memory = %ju (%ju MB)\n",
ptoa((uintmax_t)vm_free_count()),
ptoa((uintmax_t)vm_free_count()) / 1048576);
#ifdef DEV_PCI
if (bootverbose && intel_graphics_stolen_base != 0)
printf("intel stolen mem: base %#jx size %ju MB\n",
(uintmax_t)intel_graphics_stolen_base,
(uintmax_t)intel_graphics_stolen_size / 1024 / 1024);
#endif
bufinit();
vm_pager_bufferinit();
cpu_setregs();
}
static void
late_ifunc_resolve(void *dummy __unused)
{
link_elf_late_ireloc();
}
SYSINIT(late_ifunc_resolve, SI_SUB_CPU, SI_ORDER_ANY, late_ifunc_resolve, NULL);
void
cpu_setregs(void)
{
register_t cr0;
TSENTER();
cr0 = rcr0();
cr0 |= CR0_MP | CR0_NE | CR0_TS | CR0_WP | CR0_AM;
TSENTER2("load_cr0");
load_cr0(cr0);
TSEXIT2("load_cr0");
TSEXIT();
}
static struct gate_descriptor idt0[NIDT];
struct gate_descriptor *idt = &idt0[0];
static char dblfault_stack[DBLFAULT_STACK_SIZE] __aligned(16);
static char mce0_stack[MCE_STACK_SIZE] __aligned(16);
static char nmi0_stack[NMI_STACK_SIZE] __aligned(16);
static char dbg0_stack[DBG_STACK_SIZE] __aligned(16);
CTASSERT(sizeof(struct nmi_pcpu) == 16);
struct soft_segment_descriptor gdt_segs[] = {
[GNULL_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0x0,
.ssd_type = 0,
.ssd_dpl = 0,
.ssd_p = 0,
.ssd_long = 0,
.ssd_def32 = 0,
.ssd_gran = 0 },
[GNULL2_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0x0,
.ssd_type = 0,
.ssd_dpl = 0,
.ssd_p = 0,
.ssd_long = 0,
.ssd_def32 = 0,
.ssd_gran = 0 },
[GUFS32_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0xfffff,
.ssd_type = SDT_MEMRWA,
.ssd_dpl = SEL_UPL,
.ssd_p = 1,
.ssd_long = 0,
.ssd_def32 = 1,
.ssd_gran = 1 },
[GUGS32_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0xfffff,
.ssd_type = SDT_MEMRWA,
.ssd_dpl = SEL_UPL,
.ssd_p = 1,
.ssd_long = 0,
.ssd_def32 = 1,
.ssd_gran = 1 },
[GCODE_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0xfffff,
.ssd_type = SDT_MEMERA,
.ssd_dpl = SEL_KPL,
.ssd_p = 1,
.ssd_long = 1,
.ssd_def32 = 0,
.ssd_gran = 1 },
[GDATA_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0xfffff,
.ssd_type = SDT_MEMRWA,
.ssd_dpl = SEL_KPL,
.ssd_p = 1,
.ssd_long = 1,
.ssd_def32 = 0,
.ssd_gran = 1 },
[GUCODE32_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0xfffff,
.ssd_type = SDT_MEMERA,
.ssd_dpl = SEL_UPL,
.ssd_p = 1,
.ssd_long = 0,
.ssd_def32 = 1,
.ssd_gran = 1 },
[GUDATA_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0xfffff,
.ssd_type = SDT_MEMRWA,
.ssd_dpl = SEL_UPL,
.ssd_p = 1,
.ssd_long = 0,
.ssd_def32 = 1,
.ssd_gran = 1 },
[GUCODE_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0xfffff,
.ssd_type = SDT_MEMERA,
.ssd_dpl = SEL_UPL,
.ssd_p = 1,
.ssd_long = 1,
.ssd_def32 = 0,
.ssd_gran = 1 },
[GPROC0_SEL] = {
.ssd_base = 0x0,
.ssd_limit = sizeof(struct amd64tss) + IOPERM_BITMAP_SIZE - 1,
.ssd_type = SDT_SYSTSS,
.ssd_dpl = SEL_KPL,
.ssd_p = 1,
.ssd_long = 0,
.ssd_def32 = 0,
.ssd_gran = 0 },
[GPROC0_SEL + 1] = {
.ssd_base = 0x0,
.ssd_limit = 0x0,
.ssd_type = 0,
.ssd_dpl = 0,
.ssd_p = 0,
.ssd_long = 0,
.ssd_def32 = 0,
.ssd_gran = 0 },
[GUSERLDT_SEL] = {
.ssd_base = 0x0,
.ssd_limit = 0x0,
.ssd_type = 0,
.ssd_dpl = 0,
.ssd_p = 0,
.ssd_long = 0,
.ssd_def32 = 0,
.ssd_gran = 0 },
[GUSERLDT_SEL + 1] = {
.ssd_base = 0x0,
.ssd_limit = 0x0,
.ssd_type = 0,
.ssd_dpl = 0,
.ssd_p = 0,
.ssd_long = 0,
.ssd_def32 = 0,
.ssd_gran = 0 },
};
_Static_assert(nitems(gdt_segs) == NGDT, "Stale NGDT");
void
setidt(int idx, inthand_t *func, int typ, int dpl, int ist)
{
struct gate_descriptor *ip;
ip = idt + idx;
ip->gd_looffset = (uintptr_t)func;
ip->gd_selector = GSEL(GCODE_SEL, SEL_KPL);
ip->gd_ist = ist;
ip->gd_xx = 0;
ip->gd_type = typ;
ip->gd_dpl = dpl;
ip->gd_p = 1;
ip->gd_hioffset = ((uintptr_t)func)>>16 ;
}
extern inthand_t
IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm),
IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align),
IDTVEC(xmm), IDTVEC(dblfault),
IDTVEC(div_pti), IDTVEC(bpt_pti),
IDTVEC(ofl_pti), IDTVEC(bnd_pti), IDTVEC(ill_pti), IDTVEC(dna_pti),
IDTVEC(fpusegm_pti), IDTVEC(tss_pti), IDTVEC(missing_pti),
IDTVEC(stk_pti), IDTVEC(prot_pti), IDTVEC(page_pti),
IDTVEC(rsvd_pti), IDTVEC(fpu_pti), IDTVEC(align_pti),
IDTVEC(xmm_pti),
#ifdef KDTRACE_HOOKS
IDTVEC(dtrace_ret), IDTVEC(dtrace_ret_pti),
#endif
#ifdef XENHVM
IDTVEC(xen_intr_upcall), IDTVEC(xen_intr_upcall_pti),
#endif
IDTVEC(fast_syscall), IDTVEC(fast_syscall32),
IDTVEC(fast_syscall_pti);
#ifdef DDB
DB_SHOW_COMMAND_FLAGS(idt, db_show_idt, DB_CMD_MEMSAFE)
{
struct gate_descriptor *ip;
int idx;
uintptr_t func;
ip = idt;
for (idx = 0; idx < NIDT && !db_pager_quit; idx++) {
func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
if (func != (uintptr_t)&IDTVEC(rsvd)) {
db_printf("%3d\t", idx);
db_printsym(func, DB_STGY_PROC);
db_printf("\n");
}
ip++;
}
}
DB_SHOW_COMMAND_FLAGS(sysregs, db_show_sysregs, DB_CMD_MEMSAFE)
{
struct {
uint16_t limit;
uint64_t base;
} __packed idtr, gdtr;
uint16_t ldt, tr;
__asm __volatile("sidt %0" : "=m" (idtr));
db_printf("idtr\t0x%016lx/%04x\n",
(u_long)idtr.base, (u_int)idtr.limit);
__asm __volatile("sgdt %0" : "=m" (gdtr));
db_printf("gdtr\t0x%016lx/%04x\n",
(u_long)gdtr.base, (u_int)gdtr.limit);
__asm __volatile("sldt %0" : "=r" (ldt));
db_printf("ldtr\t0x%04x\n", ldt);
__asm __volatile("str %0" : "=r" (tr));
db_printf("tr\t0x%04x\n", tr);
db_printf("cr0\t0x%016lx\n", rcr0());
db_printf("cr2\t0x%016lx\n", rcr2());
db_printf("cr3\t0x%016lx\n", rcr3());
db_printf("cr4\t0x%016lx\n", rcr4());
if (rcr4() & CR4_XSAVE)
db_printf("xcr0\t0x%016lx\n", rxcr(0));
db_printf("EFER\t0x%016lx\n", rdmsr(MSR_EFER));
if (cpu_feature2 & (CPUID2_VMX | CPUID2_SMX))
db_printf("FEATURES_CTL\t%016lx\n",
rdmsr(MSR_IA32_FEATURE_CONTROL));
db_printf("DEBUG_CTL\t0x%016lx\n", rdmsr(MSR_DEBUGCTLMSR));
db_printf("PAT\t0x%016lx\n", rdmsr(MSR_PAT));
db_printf("GSBASE\t0x%016lx\n", rdmsr(MSR_GSBASE));
}
DB_SHOW_COMMAND_FLAGS(dbregs, db_show_dbregs, DB_CMD_MEMSAFE)
{
db_printf("dr0\t0x%016lx\n", rdr0());
db_printf("dr1\t0x%016lx\n", rdr1());
db_printf("dr2\t0x%016lx\n", rdr2());
db_printf("dr3\t0x%016lx\n", rdr3());
db_printf("dr6\t0x%016lx\n", rdr6());
db_printf("dr7\t0x%016lx\n", rdr7());
}
#endif
void
sdtossd(struct user_segment_descriptor *sd, struct soft_segment_descriptor *ssd)
{
ssd->ssd_base = (sd->sd_hibase << 24) | sd->sd_lobase;
ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit;
ssd->ssd_type = sd->sd_type;
ssd->ssd_dpl = sd->sd_dpl;
ssd->ssd_p = sd->sd_p;
ssd->ssd_long = sd->sd_long;
ssd->ssd_def32 = sd->sd_def32;
ssd->ssd_gran = sd->sd_gran;
}
void
ssdtosd(struct soft_segment_descriptor *ssd, struct user_segment_descriptor *sd)
{
sd->sd_lobase = (ssd->ssd_base) & 0xffffff;
sd->sd_hibase = (ssd->ssd_base >> 24) & 0xff;
sd->sd_lolimit = (ssd->ssd_limit) & 0xffff;
sd->sd_hilimit = (ssd->ssd_limit >> 16) & 0xf;
sd->sd_type = ssd->ssd_type;
sd->sd_dpl = ssd->ssd_dpl;
sd->sd_p = ssd->ssd_p;
sd->sd_long = ssd->ssd_long;
sd->sd_def32 = ssd->ssd_def32;
sd->sd_gran = ssd->ssd_gran;
}
void
ssdtosyssd(struct soft_segment_descriptor *ssd, struct system_segment_descriptor *sd)
{
sd->sd_lobase = (ssd->ssd_base) & 0xffffff;
sd->sd_hibase = (ssd->ssd_base >> 24) & 0xfffffffffful;
sd->sd_lolimit = (ssd->ssd_limit) & 0xffff;
sd->sd_hilimit = (ssd->ssd_limit >> 16) & 0xf;
sd->sd_type = ssd->ssd_type;
sd->sd_dpl = ssd->ssd_dpl;
sd->sd_p = ssd->ssd_p;
sd->sd_gran = ssd->ssd_gran;
}
u_int basemem;
static int
add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap,
int *physmap_idxp)
{
int i, insert_idx, physmap_idx;
physmap_idx = *physmap_idxp;
if (length == 0)
return (1);
insert_idx = physmap_idx;
for (i = 0; i < physmap_idx; i += 2) {
if (base < physmap[i + 1]) {
if (base + length <= physmap[i]) {
insert_idx = i;
break;
}
if (boothowto & RB_VERBOSE)
printf(
"Overlapping memory regions, ignoring second region\n");
return (1);
}
}
if (insert_idx < physmap_idx && base + length == physmap[insert_idx]) {
physmap[insert_idx] = base;
return (1);
}
if (insert_idx > 0 && base == physmap[insert_idx - 1]) {
physmap[insert_idx - 1] += length;
return (1);
}
if (physmap_idx == PHYS_AVAIL_ENTRIES) {
printf(
"Too many segments in the physical address map, giving up\n");
return (0);
}
for (i = physmap_idx; i > insert_idx; i -= 2) {
physmap[i] = physmap[i - 2];
physmap[i + 1] = physmap[i - 1];
}
physmap_idx += 2;
*physmap_idxp = physmap_idx;
physmap[insert_idx] = base;
physmap[insert_idx + 1] = base + length;
return (1);
}
void
bios_add_smap_entries(struct bios_smap *smapbase, u_int32_t smapsize,
vm_paddr_t *physmap, int *physmap_idx)
{
struct bios_smap *smap, *smapend;
smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize);
for (smap = smapbase; smap < smapend; smap++) {
if (boothowto & RB_VERBOSE)
printf("SMAP type=%02x base=%016lx len=%016lx\n",
smap->type, smap->base, smap->length);
if (smap->type != SMAP_TYPE_MEMORY)
continue;
if (!add_physmap_entry(smap->base, smap->length, physmap,
physmap_idx))
break;
}
}
static void
add_efi_map_entries(struct efi_map_header *efihdr, vm_paddr_t *physmap,
int *physmap_idx)
{
struct efi_md *map, *p;
const char *type;
size_t efisz;
int ndesc, i;
static const char *types[] = {
"Reserved",
"LoaderCode",
"LoaderData",
"BootServicesCode",
"BootServicesData",
"RuntimeServicesCode",
"RuntimeServicesData",
"ConventionalMemory",
"UnusableMemory",
"ACPIReclaimMemory",
"ACPIMemoryNVS",
"MemoryMappedIO",
"MemoryMappedIOPortSpace",
"PalCode",
"PersistentMemory"
};
efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
map = (struct efi_md *)((uint8_t *)efihdr + efisz);
if (efihdr->descriptor_size == 0)
return;
ndesc = efihdr->memory_size / efihdr->descriptor_size;
if (boothowto & RB_VERBOSE)
printf("%23s %12s %12s %8s %4s\n",
"Type", "Physical", "Virtual", "#Pages", "Attr");
TUNABLE_INT_FETCH("machdep.efirt.regs", &efi_map_regs);
for (i = 0, p = map; i < ndesc; i++,
p = efi_next_descriptor(p, efihdr->descriptor_size)) {
if (boothowto & RB_VERBOSE) {
if (p->md_type < nitems(types))
type = types[p->md_type];
else
type = "<INVALID>";
printf("%23s %012lx %012lx %08lx ", type, p->md_phys,
p->md_virt, p->md_pages);
if (p->md_attr & EFI_MD_ATTR_UC)
printf("UC ");
if (p->md_attr & EFI_MD_ATTR_WC)
printf("WC ");
if (p->md_attr & EFI_MD_ATTR_WT)
printf("WT ");
if (p->md_attr & EFI_MD_ATTR_WB)
printf("WB ");
if (p->md_attr & EFI_MD_ATTR_UCE)
printf("UCE ");
if (p->md_attr & EFI_MD_ATTR_WP)
printf("WP ");
if (p->md_attr & EFI_MD_ATTR_RP)
printf("RP ");
if (p->md_attr & EFI_MD_ATTR_XP)
printf("XP ");
if (p->md_attr & EFI_MD_ATTR_NV)
printf("NV ");
if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE)
printf("MORE_RELIABLE ");
if (p->md_attr & EFI_MD_ATTR_RO)
printf("RO ");
if (p->md_attr & EFI_MD_ATTR_RT)
printf("RUNTIME");
printf("\n");
}
switch (p->md_type) {
case EFI_MD_TYPE_BS_CODE:
case EFI_MD_TYPE_BS_DATA:
if (EFI_MAP_BOOTTYPE_ALLOWED(p->md_type))
continue;
case EFI_MD_TYPE_CODE:
case EFI_MD_TYPE_DATA:
case EFI_MD_TYPE_FREE:
break;
default:
continue;
}
if (!add_physmap_entry(p->md_phys, p->md_pages * EFI_PAGE_SIZE,
physmap, physmap_idx))
break;
}
}
static void
native_parse_memmap(vm_paddr_t *physmap, int *physmap_idx)
{
struct bios_smap *smap;
struct efi_map_header *efihdr;
efihdr = (struct efi_map_header *)preload_search_info(preload_kmdp,
MODINFO_METADATA | MODINFOMD_EFI_MAP);
smap = (struct bios_smap *)preload_search_info(preload_kmdp,
MODINFO_METADATA | MODINFOMD_SMAP);
if (efihdr == NULL && smap == NULL)
panic("No BIOS smap or EFI map info from loader!");
if (efihdr != NULL) {
add_efi_map_entries(efihdr, physmap, physmap_idx);
strlcpy(bootmethod, "UEFI", sizeof(bootmethod));
} else {
u_int32_t size = *((u_int32_t *)smap - 1);
bios_add_smap_entries(smap, size, physmap, physmap_idx);
strlcpy(bootmethod, "BIOS", sizeof(bootmethod));
}
}
#define PAGES_PER_GB (1024 * 1024 * 1024 / PAGE_SIZE)
static void
getmemsize(u_int64_t first)
{
int i, physmap_idx, pa_indx, da_indx;
vm_paddr_t pa, physmap[PHYS_AVAIL_ENTRIES];
u_long physmem_start, physmem_tunable, memtest;
pt_entry_t *pte;
quad_t dcons_addr, dcons_size;
int page_counter;
TSENTER();
vm_phys_early_add_seg((vm_paddr_t)kernphys, trunc_page(first));
bzero(physmap, sizeof(physmap));
physmap_idx = 0;
init_ops.parse_memmap(physmap, &physmap_idx);
physmap_idx -= 2;
basemem = 0;
for (i = 0; i <= physmap_idx; i += 2) {
if (physmap[i] <= 0xA0000) {
basemem = physmap[i + 1] / 1024;
break;
}
}
if (basemem == 0 || basemem > 640) {
if (bootverbose)
printf(
"Memory map doesn't contain a basemem segment, faking it");
basemem = 640;
}
Maxmem = atop(physmap[physmap_idx + 1]);
#ifdef MAXMEM
Maxmem = MAXMEM / 4;
#endif
if (TUNABLE_ULONG_FETCH("hw.physmem", &physmem_tunable))
Maxmem = atop(physmem_tunable);
memtest = 0;
TUNABLE_ULONG_FETCH("hw.memtest.tests", &memtest);
if (Maxmem > atop(physmap[physmap_idx + 1]))
Maxmem = atop(physmap[physmap_idx + 1]);
if (atop(physmap[physmap_idx + 1]) != Maxmem &&
(boothowto & RB_VERBOSE))
printf("Physical memory use set to %ldK\n", Maxmem * 4);
pmap_bootstrap(&first);
physmem_start = (vm_guest > VM_GUEST_NO ? 1 : 16) << PAGE_SHIFT;
TUNABLE_ULONG_FETCH("hw.physmem.start", &physmem_start);
if (physmap[0] < physmem_start) {
if (physmem_start < PAGE_SIZE)
physmap[0] = PAGE_SIZE;
else if (physmem_start >= physmap[1])
physmap[0] = round_page(physmap[1] - PAGE_SIZE);
else
physmap[0] = round_page(physmem_start);
}
pa_indx = 0;
da_indx = 1;
phys_avail[pa_indx++] = physmap[0];
phys_avail[pa_indx] = physmap[0];
dump_avail[da_indx] = physmap[0];
pte = CMAP1;
if (getenv_quad("dcons.addr", &dcons_addr) == 0 ||
getenv_quad("dcons.size", &dcons_size) == 0)
dcons_addr = 0;
page_counter = 0;
if (memtest != 0)
printf("Testing system memory");
for (i = 0; i <= physmap_idx; i += 2) {
vm_paddr_t end;
end = ptoa((vm_paddr_t)Maxmem);
if (physmap[i + 1] < end)
end = trunc_page(physmap[i + 1]);
for (pa = round_page(physmap[i]); pa < end; pa += PAGE_SIZE) {
int *ptr = (int *)CADDR1;
int tmp;
bool full, page_bad;
full = false;
if (pa >= (vm_paddr_t)kernphys && pa < first)
goto do_dump_avail;
if (dcons_addr > 0
&& pa >= trunc_page(dcons_addr)
&& pa < dcons_addr + dcons_size)
goto do_dump_avail;
page_bad = false;
if (memtest == 0)
goto skip_memtest;
page_counter++;
if ((page_counter % PAGES_PER_GB) == 0)
printf(".");
*pte = pa | PG_V | PG_RW | PG_NC_PWT | PG_NC_PCD;
invltlb();
tmp = *(int *)ptr;
*(volatile int *)ptr = 0xaaaaaaaa;
if (*(volatile int *)ptr != 0xaaaaaaaa)
page_bad = true;
*(volatile int *)ptr = 0x55555555;
if (*(volatile int *)ptr != 0x55555555)
page_bad = true;
*(volatile int *)ptr = 0xffffffff;
if (*(volatile int *)ptr != 0xffffffff)
page_bad = true;
*(volatile int *)ptr = 0x0;
if (*(volatile int *)ptr != 0x0)
page_bad = true;
*(int *)ptr = tmp;
skip_memtest:
if (page_bad == true)
continue;
if (phys_avail[pa_indx] == pa) {
phys_avail[pa_indx] += PAGE_SIZE;
} else {
pa_indx++;
if (pa_indx == PHYS_AVAIL_ENTRIES) {
printf(
"Too many holes in the physical address space, giving up\n");
pa_indx--;
full = true;
goto do_dump_avail;
}
phys_avail[pa_indx++] = pa;
phys_avail[pa_indx] = pa + PAGE_SIZE;
}
physmem++;
do_dump_avail:
if (dump_avail[da_indx] == pa) {
dump_avail[da_indx] += PAGE_SIZE;
} else {
da_indx++;
if (da_indx == PHYS_AVAIL_ENTRIES) {
da_indx--;
goto do_next;
}
dump_avail[da_indx++] = pa;
dump_avail[da_indx] = pa + PAGE_SIZE;
}
do_next:
if (full)
break;
}
}
*pte = 0;
invltlb();
if (memtest != 0)
printf("\n");
while (phys_avail[pa_indx - 1] + PAGE_SIZE +
round_page(msgbufsize) >= phys_avail[pa_indx]) {
physmem -= atop(phys_avail[pa_indx] - phys_avail[pa_indx - 1]);
phys_avail[pa_indx--] = 0;
phys_avail[pa_indx--] = 0;
}
Maxmem = atop(phys_avail[pa_indx]);
phys_avail[pa_indx] -= round_page(msgbufsize);
msgbufp = (struct msgbuf *)PHYS_TO_DMAP(phys_avail[pa_indx]);
TSEXIT();
}
static void
native_parse_preload_data(u_int64_t modulep)
{
char *envp;
#ifdef DDB
vm_offset_t ksym_start;
vm_offset_t ksym_end;
#endif
preload_metadata = (caddr_t)(uintptr_t)(modulep + KERNBASE);
preload_bootstrap_relocate(KERNBASE);
preload_initkmdp(true);
boothowto = MD_FETCH(preload_kmdp, MODINFOMD_HOWTO, int);
envp = MD_FETCH(preload_kmdp, MODINFOMD_ENVP, char *);
if (envp != NULL)
envp += KERNBASE;
init_static_kenv(envp, 0);
#ifdef DDB
ksym_start = MD_FETCH(preload_kmdp, MODINFOMD_SSYM, uintptr_t);
ksym_end = MD_FETCH(preload_kmdp, MODINFOMD_ESYM, uintptr_t);
db_fetch_ksymtab(ksym_start, ksym_end, 0);
#endif
efi_systbl_phys = MD_FETCH(preload_kmdp, MODINFOMD_FW_HANDLE,
vm_paddr_t);
}
static void
native_clock_source_init(void)
{
i8254_init();
}
static void
amd64_kdb_init(void)
{
kdb_init();
#ifdef KDB
if (boothowto & RB_KDB)
kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
#endif
}
void
amd64_conf_fast_syscall(void)
{
uint64_t msr;
msr = rdmsr(MSR_EFER) | EFER_SCE;
wrmsr(MSR_EFER, msr);
wrmsr(MSR_LSTAR, pti ? (u_int64_t)IDTVEC(fast_syscall_pti) :
(u_int64_t)IDTVEC(fast_syscall));
wrmsr(MSR_CSTAR, (u_int64_t)IDTVEC(fast_syscall32));
msr = ((u_int64_t)GSEL(GCODE_SEL, SEL_KPL) << 32) |
((u_int64_t)GSEL(GUCODE32_SEL, SEL_UPL) << 48);
wrmsr(MSR_STAR, msr);
wrmsr(MSR_SF_MASK, PSL_NT | PSL_T | PSL_I | PSL_C | PSL_D | PSL_AC);
}
void
amd64_bsp_pcpu_init1(struct pcpu *pc)
{
struct user_segment_descriptor *gdt;
PCPU_SET(prvspace, pc);
gdt = *PCPU_PTR(gdt);
PCPU_SET(curthread, &thread0);
PCPU_SET(tssp, PCPU_PTR(common_tss));
PCPU_SET(tss, (struct system_segment_descriptor *)&gdt[GPROC0_SEL]);
PCPU_SET(ldt, (struct system_segment_descriptor *)&gdt[GUSERLDT_SEL]);
PCPU_SET(fs32p, &gdt[GUFS32_SEL]);
PCPU_SET(gs32p, &gdt[GUGS32_SEL]);
PCPU_SET(ucr3_load_mask, PMAP_UCR3_NOMASK);
PCPU_SET(smp_tlb_gen, 1);
}
void
amd64_bsp_pcpu_init2(uint64_t rsp0)
{
PCPU_SET(rsp0, rsp0);
PCPU_SET(pti_rsp0, STACKALIGN((vm_offset_t)PCPU_PTR(pti_stack) +
PC_PTI_STACK_SZ * sizeof(uint64_t)));
PCPU_SET(curpcb, thread0.td_pcb);
}
void
amd64_bsp_ist_init(struct pcpu *pc)
{
struct nmi_pcpu *np;
struct amd64tss *tssp;
tssp = &pc->pc_common_tss;
np = ((struct nmi_pcpu *)&dblfault_stack[sizeof(dblfault_stack)]) - 1;
np->np_pcpu = (register_t)pc;
tssp->tss_ist1 = (long)np;
np = ((struct nmi_pcpu *)&nmi0_stack[sizeof(nmi0_stack)]) - 1;
np->np_pcpu = (register_t)pc;
tssp->tss_ist2 = (long)np;
np = ((struct nmi_pcpu *)&mce0_stack[sizeof(mce0_stack)]) - 1;
np->np_pcpu = (register_t)pc;
tssp->tss_ist3 = (long)np;
np = ((struct nmi_pcpu *)&dbg0_stack[sizeof(dbg0_stack)]) - 1;
np->np_pcpu = (register_t)pc;
tssp->tss_ist4 = (long)np;
}
vm_paddr_t __nosanitizeaddress __nosanitizememory
amd64_loadaddr(void)
{
pml4_entry_t *pml4e;
pdp_entry_t *pdpe;
pd_entry_t *pde;
uint64_t cr3;
cr3 = rcr3();
pml4e = (pml4_entry_t *)cr3 + pmap_pml4e_index(KERNSTART);
pdpe = (pdp_entry_t *)(*pml4e & PG_FRAME) + pmap_pdpe_index(KERNSTART);
pde = (pd_entry_t *)(*pdpe & PG_FRAME) + pmap_pde_index(KERNSTART);
return (*pde & PG_FRAME);
}
u_int64_t
hammer_time(u_int64_t modulep, u_int64_t physfree)
{
int gsel_tss, x;
struct pcpu *pc;
uint64_t rsp0;
char *env;
struct user_segment_descriptor *gdt;
struct region_descriptor r_gdt;
size_t kstack0_sz;
TSRAW(&thread0, TS_ENTER, __func__, NULL);
kernphys = amd64_loadaddr();
physfree += kernphys;
init_ops.parse_preload_data(modulep);
efi_boot = preload_search_info(preload_kmdp, MODINFO_METADATA |
MODINFOMD_EFI_MAP) != NULL;
if (!efi_boot) {
atomic_store_short((u_short *)0x472, 0x1234);
}
physfree += ucode_load_bsp(physfree - kernphys + KERNSTART);
physfree = roundup2(physfree, PAGE_SIZE);
identify_cpu1();
identify_hypervisor();
identify_hypervisor_smbios();
identify_cpu_fixup_bsp();
identify_cpu2();
initializecpucache();
pti = pti_get_default();
TUNABLE_INT_FETCH("vm.pmap.pti", &pti);
TUNABLE_INT_FETCH("vm.pmap.pcid_enabled", &pmap_pcid_enabled);
if ((cpu_feature2 & CPUID2_PCID) == 0)
pmap_pcid_enabled = 0;
invpcid_works = (cpu_stdext_feature & CPUID_STDEXT_INVPCID) != 0;
TUNABLE_INT_FETCH("vm.pmap.pcid_invlpg_workaround",
&pmap_pcid_invlpg_workaround_uena);
cpu_init_small_core();
if ((cpu_feature2 & CPUID2_XSAVE) != 0) {
use_xsave = 1;
TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave);
}
sched_instance_select();
link_elf_ireloc();
proc_linkup0(&proc0, &thread0);
init_param1();
thread0.td_kstack = physfree - kernphys + KERNSTART;
thread0.td_kstack_pages = kstack_pages;
kstack0_sz = thread0.td_kstack_pages * PAGE_SIZE;
bzero((void *)thread0.td_kstack, kstack0_sz);
physfree += kstack0_sz;
pmap_thread_init_invl_gen(&thread0);
pc = &temp_bsp_pcpu;
pcpu_init(pc, 0, sizeof(struct pcpu));
gdt = &temp_bsp_pcpu.pc_gdt[0];
for (x = 0; x < NGDT; x++) {
if (x != GPROC0_SEL && x != (GPROC0_SEL + 1) &&
x != GUSERLDT_SEL && x != (GUSERLDT_SEL + 1))
ssdtosd(&gdt_segs[x], &gdt[x]);
}
gdt_segs[GPROC0_SEL].ssd_base = (uintptr_t)&pc->pc_common_tss;
ssdtosyssd(&gdt_segs[GPROC0_SEL],
(struct system_segment_descriptor *)&gdt[GPROC0_SEL]);
r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1;
r_gdt.rd_base = (long)gdt;
lgdt(&r_gdt);
wrmsr(MSR_FSBASE, 0);
wrmsr(MSR_GSBASE, (u_int64_t)pc);
wrmsr(MSR_KGSBASE, 0);
dpcpu_init((void *)(physfree - kernphys + KERNSTART), 0);
physfree += DPCPU_SIZE;
amd64_bsp_pcpu_init1(pc);
mutex_init();
mtx_init(&icu_lock, "icu", NULL, MTX_SPIN | MTX_NOWITNESS);
mtx_init(&dt_lock, "descriptor tables", NULL, MTX_DEF);
for (x = 0; x < NIDT; x++)
setidt(x, pti ? &IDTVEC(rsvd_pti) : &IDTVEC(rsvd), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_DE, pti ? &IDTVEC(div_pti) : &IDTVEC(div), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_DB, &IDTVEC(dbg), SDT_SYSIGT, SEL_KPL, 4);
setidt(IDT_NMI, &IDTVEC(nmi), SDT_SYSIGT, SEL_KPL, 2);
setidt(IDT_BP, pti ? &IDTVEC(bpt_pti) : &IDTVEC(bpt), SDT_SYSIGT,
SEL_UPL, 0);
setidt(IDT_OF, pti ? &IDTVEC(ofl_pti) : &IDTVEC(ofl), SDT_SYSIGT,
SEL_UPL, 0);
setidt(IDT_BR, pti ? &IDTVEC(bnd_pti) : &IDTVEC(bnd), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_UD, pti ? &IDTVEC(ill_pti) : &IDTVEC(ill), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_NM, pti ? &IDTVEC(dna_pti) : &IDTVEC(dna), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_DF, &IDTVEC(dblfault), SDT_SYSIGT, SEL_KPL, 1);
setidt(IDT_FPUGP, pti ? &IDTVEC(fpusegm_pti) : &IDTVEC(fpusegm),
SDT_SYSIGT, SEL_KPL, 0);
setidt(IDT_TS, pti ? &IDTVEC(tss_pti) : &IDTVEC(tss), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_NP, pti ? &IDTVEC(missing_pti) : &IDTVEC(missing),
SDT_SYSIGT, SEL_KPL, 0);
setidt(IDT_SS, pti ? &IDTVEC(stk_pti) : &IDTVEC(stk), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_GP, pti ? &IDTVEC(prot_pti) : &IDTVEC(prot), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_PF, pti ? &IDTVEC(page_pti) : &IDTVEC(page), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_MF, pti ? &IDTVEC(fpu_pti) : &IDTVEC(fpu), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_AC, pti ? &IDTVEC(align_pti) : &IDTVEC(align), SDT_SYSIGT,
SEL_KPL, 0);
setidt(IDT_MC, &IDTVEC(mchk), SDT_SYSIGT, SEL_KPL, 3);
setidt(IDT_XF, pti ? &IDTVEC(xmm_pti) : &IDTVEC(xmm), SDT_SYSIGT,
SEL_KPL, 0);
#ifdef KDTRACE_HOOKS
setidt(IDT_DTRACE_RET, pti ? &IDTVEC(dtrace_ret_pti) :
&IDTVEC(dtrace_ret), SDT_SYSIGT, SEL_UPL, 0);
#endif
#ifdef XENHVM
setidt(IDT_EVTCHN, pti ? &IDTVEC(xen_intr_upcall_pti) :
&IDTVEC(xen_intr_upcall), SDT_SYSIGT, SEL_KPL, 0);
#endif
r_idt.rd_limit = sizeof(idt0) - 1;
r_idt.rd_base = (long) idt;
lidt(&r_idt);
TUNABLE_INT_FETCH("hw.ibrs_disable", &hw_ibrs_disable);
TUNABLE_INT_FETCH("machdep.mitigations.ibrs.disable", &hw_ibrs_disable);
TUNABLE_INT_FETCH("hw.spec_store_bypass_disable", &hw_ssb_disable);
TUNABLE_INT_FETCH("machdep.mitigations.ssb.disable", &hw_ssb_disable);
TUNABLE_INT_FETCH("machdep.syscall_ret_flush_l1d",
&syscall_ret_l1d_flush_mode);
TUNABLE_INT_FETCH("hw.mds_disable", &hw_mds_disable);
TUNABLE_INT_FETCH("machdep.mitigations.mds.disable", &hw_mds_disable);
TUNABLE_INT_FETCH("machdep.mitigations.taa.enable", &x86_taa_enable);
TUNABLE_INT_FETCH("machdep.mitigations.rngds.enable",
&x86_rngds_mitg_enable);
TUNABLE_INT_FETCH("machdep.mitigations.zenbleed.enable",
&zenbleed_enable);
zenbleed_sanitize_enable();
finishidentcpu();
invlpgb_works = (amd_extended_feature_extensions &
AMDFEID_INVLPGB) != 0;
TUNABLE_INT_FETCH("vm.pmap.invlpgb_works", &invlpgb_works);
if (invlpgb_works)
invlpgb_maxcnt = cpu_procinfo3 & AMDID_INVLPGB_MAXCNT;
clock_init();
initializecpu();
amd64_bsp_ist_init(pc);
pc->pc_common_tss.tss_iobase = sizeof(struct amd64tss) +
IOPERM_BITMAP_SIZE;
gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
ltr(gsel_tss);
amd64_conf_fast_syscall();
cpu_max_ext_state_size = sizeof(struct savefpu);
set_top_of_stack_td(&thread0);
thread0.td_pcb = get_pcb_td(&thread0);
TUNABLE_INT_FETCH("debug.late_console", &late_console);
if (!late_console) {
cninit();
amd64_kdb_init();
}
getmemsize(physfree);
init_param2(physmem);
#ifdef DEV_PCI
pci_early_quirks();
#endif
if (late_console)
cninit();
if (getenv_is_true("debug.dump_modinfo_at_boot"))
preload_dump();
#ifdef DEV_ISA
#ifdef DEV_ATPIC
elcr_probe();
atpic_startup();
#else
atpic_reset();
setidt(IDT_IO_INTS + 7, IDTVEC(spuriousint), SDT_SYSIGT, SEL_KPL, 0);
setidt(IDT_IO_INTS + 15, IDTVEC(spuriousint), SDT_SYSIGT, SEL_KPL, 0);
#endif
#else
#error "have you forgotten the isa device?"
#endif
if (late_console)
amd64_kdb_init();
msgbufinit(msgbufp, msgbufsize);
fpuinit();
rsp0 = thread0.td_md.md_stack_base;
rsp0 = STACKALIGN(rsp0);
PCPU_PTR(common_tss)->tss_rsp0 = rsp0;
amd64_bsp_pcpu_init2(rsp0);
_ucodesel = GSEL(GUCODE_SEL, SEL_UPL);
_udatasel = GSEL(GUDATA_SEL, SEL_UPL);
_ucode32sel = GSEL(GUCODE32_SEL, SEL_UPL);
_ufssel = GSEL(GUFS32_SEL, SEL_UPL);
_ugssel = GSEL(GUGS32_SEL, SEL_UPL);
load_ds(_udatasel);
load_es(_udatasel);
load_fs(_ufssel);
thread0.td_pcb->pcb_flags = 0;
env = kern_getenv("kernelname");
if (env != NULL)
strlcpy(kernelname, env, sizeof(kernelname));
kcsan_cpu_init(0);
#ifdef FDT
x86_init_fdt();
#endif
kasan_init();
kmsan_init();
TSEXIT();
return (thread0.td_md.md_stack_base);
}
void
cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
{
pcpu->pc_acpi_id = 0xffffffff;
}
static int
smap_sysctl_handler(SYSCTL_HANDLER_ARGS)
{
struct bios_smap *smapbase;
struct bios_smap_xattr smap;
uint32_t *smapattr;
int count, error, i;
smapbase = (struct bios_smap *)preload_search_info(preload_kmdp,
MODINFO_METADATA | MODINFOMD_SMAP);
if (smapbase == NULL)
return (0);
smapattr = (uint32_t *)preload_search_info(preload_kmdp,
MODINFO_METADATA | MODINFOMD_SMAP_XATTR);
count = *((uint32_t *)smapbase - 1) / sizeof(*smapbase);
error = 0;
for (i = 0; i < count; i++) {
smap.base = smapbase[i].base;
smap.length = smapbase[i].length;
smap.type = smapbase[i].type;
if (smapattr != NULL)
smap.xattr = smapattr[i];
else
smap.xattr = 0;
error = SYSCTL_OUT(req, &smap, sizeof(smap));
}
return (error);
}
SYSCTL_PROC(_machdep, OID_AUTO, smap,
CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
smap_sysctl_handler, "S,bios_smap_xattr",
"Raw BIOS SMAP data");
static int
efi_map_sysctl_handler(SYSCTL_HANDLER_ARGS)
{
struct efi_map_header *efihdr;
uint32_t efisize;
efihdr = (struct efi_map_header *)preload_search_info(preload_kmdp,
MODINFO_METADATA | MODINFOMD_EFI_MAP);
if (efihdr == NULL)
return (0);
efisize = *((uint32_t *)efihdr - 1);
return (SYSCTL_OUT(req, efihdr, efisize));
}
SYSCTL_PROC(_machdep, OID_AUTO, efi_map,
CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
efi_map_sysctl_handler, "S,efi_map_header",
"Raw EFI Memory Map");
static int
efi_arch_sysctl_handler(SYSCTL_HANDLER_ARGS)
{
char *arch;
arch = (char *)preload_search_info(preload_kmdp,
MODINFO_METADATA | MODINFOMD_EFI_ARCH);
if (arch == NULL)
return (0);
return (SYSCTL_OUT_STR(req, arch));
}
SYSCTL_PROC(_machdep, OID_AUTO, efi_arch,
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
efi_arch_sysctl_handler, "A", "EFI Firmware Architecture");
void
spinlock_enter(void)
{
struct thread *td;
register_t flags;
td = curthread;
if (td->td_md.md_spinlock_count == 0) {
flags = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_flags = flags;
critical_enter();
} else
td->td_md.md_spinlock_count++;
}
void
spinlock_exit(void)
{
struct thread *td;
register_t flags;
td = curthread;
flags = td->td_md.md_saved_flags;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0) {
critical_exit();
intr_restore(flags);
}
}
void
makectx(struct trapframe *tf, struct pcb *pcb)
{
pcb->pcb_r12 = tf->tf_r12;
pcb->pcb_r13 = tf->tf_r13;
pcb->pcb_r14 = tf->tf_r14;
pcb->pcb_r15 = tf->tf_r15;
pcb->pcb_rbp = tf->tf_rbp;
pcb->pcb_rbx = tf->tf_rbx;
pcb->pcb_rip = tf->tf_rip;
pcb->pcb_rsp = tf->tf_rsp;
}
void
set_pcb_flags_raw(struct pcb *pcb, const u_int flags)
{
__asm __volatile("orl %1,%0"
: "=m" (pcb->pcb_flags) : "ir" (flags), "m" (pcb->pcb_flags)
: "cc", "memory");
}
static void
set_pcb_flags_fsgsbase(struct pcb *pcb, const u_int flags)
{
register_t r;
if (curpcb == pcb &&
(flags & PCB_FULL_IRET) != 0 &&
(pcb->pcb_flags & PCB_FULL_IRET) == 0) {
r = intr_disable();
if ((pcb->pcb_flags & PCB_FULL_IRET) == 0) {
pcb->pcb_fsbase = rdfsbase();
pcb->pcb_gsbase = rdmsr(MSR_KGSBASE);
}
set_pcb_flags_raw(pcb, flags);
intr_restore(r);
} else {
set_pcb_flags_raw(pcb, flags);
}
}
DEFINE_IFUNC(, void, set_pcb_flags, (struct pcb *, const u_int))
{
return ((cpu_stdext_feature & CPUID_STDEXT_FSGSBASE) != 0 ?
set_pcb_flags_fsgsbase : set_pcb_flags_raw);
}
void
clear_pcb_flags(struct pcb *pcb, const u_int flags)
{
__asm __volatile("andl %1,%0"
: "=m" (pcb->pcb_flags) : "ir" (~flags), "m" (pcb->pcb_flags)
: "cc", "memory");
}
extern const char wrmsr_early_safe_gp_handler[];
static struct region_descriptor wrmsr_early_safe_orig_efi_idt;
void
wrmsr_early_safe_start(void)
{
struct region_descriptor efi_idt;
struct gate_descriptor *gpf_descr;
sidt(&wrmsr_early_safe_orig_efi_idt);
efi_idt.rd_limit = 32 * sizeof(idt0[0]);
efi_idt.rd_base = (uintptr_t)idt0;
lidt(&efi_idt);
gpf_descr = &idt0[IDT_GP];
gpf_descr->gd_looffset = (uintptr_t)wrmsr_early_safe_gp_handler;
gpf_descr->gd_hioffset = (uintptr_t)wrmsr_early_safe_gp_handler >> 16;
gpf_descr->gd_selector = rcs();
gpf_descr->gd_type = SDT_SYSTGT;
gpf_descr->gd_p = 1;
}
void
wrmsr_early_safe_end(void)
{
struct gate_descriptor *gpf_descr;
lidt(&wrmsr_early_safe_orig_efi_idt);
gpf_descr = &idt0[IDT_GP];
memset_early(gpf_descr, 0, sizeof(*gpf_descr));
}
#ifdef KDB
u_char inb_(u_short);
void outb_(u_short, u_char);
u_char
inb_(u_short port)
{
return inb(port);
}
void
outb_(u_short port, u_char data)
{
outb(port, data);
}
#endif
#undef memset
#undef memmove
#undef memcpy
void *memset_std(void *buf, int c, size_t len);
void *memset_erms(void *buf, int c, size_t len);
void *memmove_std(void * _Nonnull dst, const void * _Nonnull src,
size_t len);
void *memmove_erms(void * _Nonnull dst, const void * _Nonnull src,
size_t len);
void *memcpy_std(void * _Nonnull dst, const void * _Nonnull src,
size_t len);
void *memcpy_erms(void * _Nonnull dst, const void * _Nonnull src,
size_t len);
#ifdef KCSAN
void *
memset(void *buf, int c, size_t len)
{
return (memset_std(buf, c, len));
}
void *
memmove(void * _Nonnull dst, const void * _Nonnull src, size_t len)
{
return (memmove_std(dst, src, len));
}
void *
memcpy(void * _Nonnull dst, const void * _Nonnull src, size_t len)
{
return (memcpy_std(dst, src, len));
}
#else
DEFINE_IFUNC(, void *, memset, (void *, int, size_t))
{
return ((cpu_stdext_feature & CPUID_STDEXT_ERMS) != 0 ?
memset_erms : memset_std);
}
DEFINE_IFUNC(, void *, memmove, (void * _Nonnull, const void * _Nonnull,
size_t))
{
return ((cpu_stdext_feature & CPUID_STDEXT_ERMS) != 0 ?
memmove_erms : memmove_std);
}
DEFINE_IFUNC(, void *, memcpy, (void * _Nonnull, const void * _Nonnull,size_t))
{
return ((cpu_stdext_feature & CPUID_STDEXT_ERMS) != 0 ?
memcpy_erms : memcpy_std);
}
#endif
void pagezero_std(void *addr);
void pagezero_erms(void *addr);
DEFINE_IFUNC(, void , pagezero, (void *))
{
return ((cpu_stdext_feature & CPUID_STDEXT_ERMS) != 0 ?
pagezero_erms : pagezero_std);
}