void arch_mm_init(unsigned long *pt_pfn, unsigned long pt_base, unsigned long nr_pt_frames, unsigned long nr_pages) { unsigned long start_pfn = (nr_pt_frames - NOT_L1_FRAMES) * L1_PAGETABLE_ENTRIES; unsigned long end_pfn = nr_pages; build_page_tables((pgentry_t *)pt_base, pt_pfn, pfn_to_virt(start_pfn), pfn_to_virt(end_pfn)); }
/*ARGSUSED*/ void startup_kernel(void) { char *cmdline; uintptr_t addr; #if defined(__xpv) physdev_set_iopl_t set_iopl; #endif /* __xpv */ /* * At this point we are executing in a 32 bit real mode. */ #if defined(__xpv) cmdline = (char *)xen_info->cmd_line; #else /* __xpv */ cmdline = (char *)mb_info->cmdline; #endif /* __xpv */ prom_debug = (strstr(cmdline, "prom_debug") != NULL); map_debug = (strstr(cmdline, "map_debug") != NULL); #if defined(__xpv) /* * For dom0, before we initialize the console subsystem we'll * need to enable io operations, so set I/O priveldge level to 1. */ if (DOMAIN_IS_INITDOMAIN(xen_info)) { set_iopl.iopl = 1; (void) HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); } #endif /* __xpv */ bcons_init(cmdline); DBG_MSG("\n\nSolaris prekernel set: "); DBG_MSG(cmdline); DBG_MSG("\n"); if (strstr(cmdline, "multiboot") != NULL) { dboot_panic(NO_MULTIBOOT); } /* * boot info must be 16 byte aligned for 64 bit kernel ABI */ addr = (uintptr_t)boot_info; addr = (addr + 0xf) & ~0xf; bi = (struct xboot_info *)addr; DBG((uintptr_t)bi); bi->bi_cmdline = (native_ptr_t)(uintptr_t)cmdline; /* * Need correct target_kernel_text value */ #if defined(_BOOT_TARGET_amd64) target_kernel_text = KERNEL_TEXT_amd64; #elif defined(__xpv) target_kernel_text = KERNEL_TEXT_i386_xpv; #else target_kernel_text = KERNEL_TEXT_i386; #endif DBG(target_kernel_text); #if defined(__xpv) /* * XXPV Derive this stuff from CPUID / what the hypervisor has enabled */ #if defined(_BOOT_TARGET_amd64) /* * 64-bit hypervisor. */ amd64_support = 1; pae_support = 1; #else /* _BOOT_TARGET_amd64 */ /* * See if we are running on a PAE Hypervisor */ { xen_capabilities_info_t caps; if (HYPERVISOR_xen_version(XENVER_capabilities, &caps) != 0) dboot_panic("HYPERVISOR_xen_version(caps) failed"); caps[sizeof (caps) - 1] = 0; if (prom_debug) dboot_printf("xen capabilities %s\n", caps); if (strstr(caps, "x86_32p") != NULL) pae_support = 1; } #endif /* _BOOT_TARGET_amd64 */ { xen_platform_parameters_t p; if (HYPERVISOR_xen_version(XENVER_platform_parameters, &p) != 0) dboot_panic("HYPERVISOR_xen_version(parms) failed"); DBG(p.virt_start); mfn_to_pfn_mapping = (pfn_t *)(xen_virt_start = p.virt_start); } /* * The hypervisor loads stuff starting at 1Gig */ mfn_base = ONE_GIG; DBG(mfn_base); /* * enable writable page table mode for the hypervisor */ if (HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables) < 0) dboot_panic("HYPERVISOR_vm_assist(writable_pagetables) failed"); /* * check for NX support */ if (pae_support) { uint32_t eax = 0x80000000; uint32_t edx = get_cpuid_edx(&eax); if (eax >= 0x80000001) { eax = 0x80000001; edx = get_cpuid_edx(&eax); if (edx & CPUID_AMD_EDX_NX) NX_support = 1; } } #if !defined(_BOOT_TARGET_amd64) /* * The 32-bit hypervisor uses segmentation to protect itself from * guests. This means when a guest attempts to install a flat 4GB * code or data descriptor the 32-bit hypervisor will protect itself * by silently shrinking the segment such that if the guest attempts * any access where the hypervisor lives a #gp fault is generated. * The problem is that some applications expect a full 4GB flat * segment for their current thread pointer and will use negative * offset segment wrap around to access data. TLS support in linux * brand is one example of this. * * The 32-bit hypervisor can catch the #gp fault in these cases * and emulate the access without passing the #gp fault to the guest * but only if VMASST_TYPE_4gb_segments is explicitly turned on. * Seems like this should have been the default. * Either way, we want the hypervisor -- and not Solaris -- to deal * to deal with emulating these accesses. */ if (HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments) < 0) dboot_panic("HYPERVISOR_vm_assist(4gb_segments) failed"); #endif /* !_BOOT_TARGET_amd64 */ #else /* __xpv */ /* * use cpuid to enable MMU features */ if (have_cpuid()) { uint32_t eax, edx; eax = 1; edx = get_cpuid_edx(&eax); if (edx & CPUID_INTC_EDX_PSE) largepage_support = 1; if (edx & CPUID_INTC_EDX_PGE) pge_support = 1; if (edx & CPUID_INTC_EDX_PAE) pae_support = 1; eax = 0x80000000; edx = get_cpuid_edx(&eax); if (eax >= 0x80000001) { eax = 0x80000001; edx = get_cpuid_edx(&eax); if (edx & CPUID_AMD_EDX_LM) amd64_support = 1; if (edx & CPUID_AMD_EDX_NX) NX_support = 1; } } else { dboot_printf("cpuid not supported\n"); } #endif /* __xpv */ #if defined(_BOOT_TARGET_amd64) if (amd64_support == 0) dboot_panic("long mode not supported, rebooting"); else if (pae_support == 0) dboot_panic("long mode, but no PAE; rebooting"); #else /* * Allow the command line to over-ride use of PAE for 32 bit. */ if (strstr(cmdline, "disablePAE=true") != NULL) { pae_support = 0; NX_support = 0; amd64_support = 0; } #endif /* * initialize the simple memory allocator */ init_mem_alloc(); #if !defined(__xpv) && !defined(_BOOT_TARGET_amd64) /* * disable PAE on 32 bit h/w w/o NX and < 4Gig of memory */ if (max_mem < FOUR_GIG && NX_support == 0) pae_support = 0; #endif /* * configure mmu information */ if (pae_support) { shift_amt = shift_amt_pae; ptes_per_table = 512; pte_size = 8; lpagesize = TWO_MEG; #if defined(_BOOT_TARGET_amd64) top_level = 3; #else top_level = 2; #endif } else { pae_support = 0; NX_support = 0; shift_amt = shift_amt_nopae; ptes_per_table = 1024; pte_size = 4; lpagesize = FOUR_MEG; top_level = 1; } DBG(pge_support); DBG(NX_support); DBG(largepage_support); DBG(amd64_support); DBG(top_level); DBG(pte_size); DBG(ptes_per_table); DBG(lpagesize); #if defined(__xpv) ktext_phys = ONE_GIG; /* from UNIX Mapfile */ #else ktext_phys = FOUR_MEG; /* from UNIX Mapfile */ #endif #if !defined(__xpv) && defined(_BOOT_TARGET_amd64) /* * For grub, copy kernel bits from the ELF64 file to final place. */ DBG_MSG("\nAllocating nucleus pages.\n"); ktext_phys = (uintptr_t)do_mem_alloc(ksize, FOUR_MEG); if (ktext_phys == 0) dboot_panic("failed to allocate aligned kernel memory"); if (dboot_elfload64(mb_header.load_addr) != 0) dboot_panic("failed to parse kernel ELF image, rebooting"); #endif DBG(ktext_phys); /* * Allocate page tables. */ build_page_tables(); /* * return to assembly code to switch to running kernel */ entry_addr_low = (uint32_t)target_kernel_text; DBG(entry_addr_low); bi->bi_use_largepage = largepage_support; bi->bi_use_pae = pae_support; bi->bi_use_pge = pge_support; bi->bi_use_nx = NX_support; #if defined(__xpv) bi->bi_next_paddr = next_avail_addr - mfn_base; DBG(bi->bi_next_paddr); bi->bi_next_vaddr = (native_ptr_t)next_avail_addr; DBG(bi->bi_next_vaddr); /* * unmap unused pages in start area to make them available for DMA */ while (next_avail_addr < scratch_end) { (void) HYPERVISOR_update_va_mapping(next_avail_addr, 0, UVMF_INVLPG | UVMF_LOCAL); next_avail_addr += MMU_PAGESIZE; } bi->bi_xen_start_info = (uintptr_t)xen_info; DBG((uintptr_t)HYPERVISOR_shared_info); bi->bi_shared_info = (native_ptr_t)HYPERVISOR_shared_info; bi->bi_top_page_table = (uintptr_t)top_page_table - mfn_base; #else /* __xpv */ bi->bi_next_paddr = next_avail_addr; DBG(bi->bi_next_paddr); bi->bi_next_vaddr = (uintptr_t)next_avail_addr; DBG(bi->bi_next_vaddr); bi->bi_mb_info = (uintptr_t)mb_info; bi->bi_top_page_table = (uintptr_t)top_page_table; #endif /* __xpv */ bi->bi_kseg_size = FOUR_MEG; DBG(bi->bi_kseg_size); #ifndef __xpv if (map_debug) dump_tables(); #endif DBG_MSG("\n\n*** DBOOT DONE -- back to asm to jump to kernel\n\n"); }