diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -1272,16 +1272,6 @@ (boothowto & RB_VERBOSE)) printf("Physical memory use set to %ldK\n", Maxmem * 4); - /* - * Make hole for "AP -> long mode" bootstrap code. The - * mp_bootaddress vector is only available when the kernel - * is configured to support APs and APs for the system start - * in real mode mode (e.g. SMP bare metal). - */ -#ifdef SMP - alloc_ap_trampoline(physmap, &physmap_idx); -#endif - /* call pmap initialization to make new kernel address space */ pmap_bootstrap(&first); diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -112,7 +112,7 @@ * Local data and functions. */ -static int start_ap(int apic_id); +static int start_ap(int apic_id, vm_paddr_t boot_address); /* * Initialize the IPI handlers and start up the AP's. @@ -322,17 +322,25 @@ int start_all_aps(void) { - vm_page_t m_pml4, m_pdp, m_pd[4]; + vm_page_t m_boottramp, m_pml4, m_pdp, m_pd[4]; pml5_entry_t old_pml45; pml4_entry_t *v_pml4; pdp_entry_t *v_pdp; pd_entry_t *v_pd; + vm_paddr_t boot_address; u_int32_t mpbioswarmvec; int apic_id, cpu, domain, i; u_char mpbiosreason; mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); + MPASS(bootMP_size <= PAGE_SIZE); + m_boottramp = vm_page_alloc_contig(NULL, 0, VM_ALLOC_NORMAL | + VM_ALLOC_NOBUSY | VM_ALLOC_NOOBJ, 1, 0, + (1ULL << 20), /* Trampoline should be below 1M for real mode */ + PAGE_SIZE, 0, VM_MEMATTR_DEFAULT); + boot_address = VM_PAGE_TO_PHYS(m_boottramp); + /* Create a transient 1:1 mapping of low 4G */ if (la57) { m_pml4 = pmap_page_alloc_below_4g(true); @@ -382,7 +390,7 @@ /* copy the AP 1st level boot code */ bcopy(mptramp_start, (void *)PHYS_TO_DMAP(boot_address), bootMP_size); if (bootverbose) - printf("AP boot address %#x\n", boot_address); + printf("AP boot address %#lx\n", boot_address); /* save the current value of the warm-start vector */ if (!efi_boot) @@ -436,7 +444,7 @@ bootAP = cpu; /* attempt to start the Application Processor */ - if (!start_ap(apic_id)) { + if (!start_ap(apic_id, boot_address)) { /* restore the warmstart vector */ *(u_int32_t *) WARMBOOT_OFF = mpbioswarmvec; panic("AP #%d (PHY# %d) failed!", cpu, apic_id); @@ -461,6 +469,7 @@ vm_page_free(m_pd[1]); vm_page_free(m_pd[0]); vm_page_free(m_pdp); + vm_page_free(m_boottramp); /* number of APs actually started */ return (mp_naps); @@ -474,7 +483,7 @@ * but it seems to work. */ static int -start_ap(int apic_id) +start_ap(int apic_id, vm_paddr_t boot_address) { int vector, ms; int cpus; diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -147,6 +147,61 @@ static char *ap_copyout_buf; static char *ap_tramp_stack_base; + +unsigned int boot_address; + +#define MiB(v) (v ## ULL << 20) + +/* Allocate memory for the AP trampoline. */ +void +alloc_ap_trampoline(vm_paddr_t *physmap, unsigned int *physmap_idx) +{ + unsigned int i; + bool allocated; + + allocated = false; + for (i = *physmap_idx; i <= *physmap_idx; i -= 2) { + /* + * Find a memory region big enough and below the 1MB boundary + * for the trampoline code. + * NB: needs to be page aligned. + */ + if (physmap[i] >= MiB(1) || + (trunc_page(physmap[i + 1]) - round_page(physmap[i])) < + round_page(bootMP_size)) + continue; + + allocated = true; + /* + * Try to steal from the end of the region to mimic previous + * behaviour, else fallback to steal from the start. + */ + if (physmap[i + 1] < MiB(1)) { + boot_address = trunc_page(physmap[i + 1]); + if ((physmap[i + 1] - boot_address) < bootMP_size) + boot_address -= round_page(bootMP_size); + physmap[i + 1] = boot_address; + } else { + boot_address = round_page(physmap[i]); + physmap[i] = boot_address + round_page(bootMP_size); + } + if (physmap[i] == physmap[i + 1] && *physmap_idx != 0) { + memmove(&physmap[i], &physmap[i + 2], + sizeof(*physmap) * (*physmap_idx - i + 2)); + *physmap_idx -= 2; + } + break; + } + + if (!allocated) { + boot_address = basemem * 1024 - bootMP_size; + if (bootverbose) + printf( +"Cannot find enough space for the boot trampoline, placing it at %#x", + boot_address); + } +} + /* * Initialize the IPI handlers and start up the AP's. */ diff --git a/sys/x86/include/x86_smp.h b/sys/x86/include/x86_smp.h --- a/sys/x86/include/x86_smp.h +++ b/sys/x86/include/x86_smp.h @@ -23,6 +23,10 @@ struct pmap; +#ifdef __i386__ +extern unsigned int boot_address; +#endif + /* global data in mp_x86.c */ extern int mp_naps; extern int boot_cpu_id; @@ -32,7 +36,6 @@ extern void *dpcpu; extern char *bootSTK; extern void *bootstacks[]; -extern unsigned int boot_address; extern unsigned int bootMP_size; extern volatile int aps_ready; extern struct mtx ap_boot_mtx; @@ -84,12 +87,15 @@ typedef void (*smp_invl_cb_t)(struct pmap *, vm_offset_t addr1, vm_offset_t addr2); +#ifdef __i386__ +void alloc_ap_trampoline(vm_paddr_t *physmap, unsigned int *physmap_idx); +#endif + /* functions in x86_mp.c */ void assign_cpu_ids(void); void cpu_add(u_int apic_id, char boot_cpu); void cpustop_handler(void); void cpususpend_handler(void); -void alloc_ap_trampoline(vm_paddr_t *physmap, unsigned int *physmap_idx); void init_secondary_tail(void); void init_secondary(void); void ipi_startup(int apic_id, int vector); diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c --- a/sys/x86/x86/mp_x86.c +++ b/sys/x86/x86/mp_x86.c @@ -168,14 +168,10 @@ int present; } static caches[MAX_CACHE_LEVELS]; -unsigned int boot_address; - static bool stop_mwait = false; SYSCTL_BOOL(_machdep, OID_AUTO, stop_mwait, CTLFLAG_RWTUN, &stop_mwait, 0, "Use MONITOR/MWAIT when stopping CPU, if available"); -#define MiB(v) (v ## ULL << 20) - void mem_range_AP_init(void) { @@ -939,56 +935,6 @@ return (mp_ncpus > 1); } -/* Allocate memory for the AP trampoline. */ -void -alloc_ap_trampoline(vm_paddr_t *physmap, unsigned int *physmap_idx) -{ - unsigned int i; - bool allocated; - - allocated = false; - for (i = *physmap_idx; i <= *physmap_idx; i -= 2) { - /* - * Find a memory region big enough and below the 1MB boundary - * for the trampoline code. - * NB: needs to be page aligned. - */ - if (physmap[i] >= MiB(1) || - (trunc_page(physmap[i + 1]) - round_page(physmap[i])) < - round_page(bootMP_size)) - continue; - - allocated = true; - /* - * Try to steal from the end of the region to mimic previous - * behaviour, else fallback to steal from the start. - */ - if (physmap[i + 1] < MiB(1)) { - boot_address = trunc_page(physmap[i + 1]); - if ((physmap[i + 1] - boot_address) < bootMP_size) - boot_address -= round_page(bootMP_size); - physmap[i + 1] = boot_address; - } else { - boot_address = round_page(physmap[i]); - physmap[i] = boot_address + round_page(bootMP_size); - } - if (physmap[i] == physmap[i + 1] && *physmap_idx != 0) { - memmove(&physmap[i], &physmap[i + 2], - sizeof(*physmap) * (*physmap_idx - i + 2)); - *physmap_idx -= 2; - } - break; - } - - if (!allocated) { - boot_address = basemem * 1024 - bootMP_size; - if (bootverbose) - printf( -"Cannot find enough space for the boot trampoline, placing it at %#x", - boot_address); - } -} - /* * AP CPU's call this to initialize themselves. */