17656SSherry.Moore@Sun.COM /* 27656SSherry.Moore@Sun.COM * CDDL HEADER START 37656SSherry.Moore@Sun.COM * 47656SSherry.Moore@Sun.COM * The contents of this file are subject to the terms of the 57656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License"). 67656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License. 77656SSherry.Moore@Sun.COM * 87656SSherry.Moore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97656SSherry.Moore@Sun.COM * or http://www.opensolaris.org/os/licensing. 107656SSherry.Moore@Sun.COM * See the License for the specific language governing permissions 117656SSherry.Moore@Sun.COM * and limitations under the License. 127656SSherry.Moore@Sun.COM * 137656SSherry.Moore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147656SSherry.Moore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157656SSherry.Moore@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167656SSherry.Moore@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177656SSherry.Moore@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187656SSherry.Moore@Sun.COM * 197656SSherry.Moore@Sun.COM * CDDL HEADER END 207656SSherry.Moore@Sun.COM */ 217656SSherry.Moore@Sun.COM 227656SSherry.Moore@Sun.COM /* 237656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247656SSherry.Moore@Sun.COM * Use is subject to license terms. 257656SSherry.Moore@Sun.COM */ 267656SSherry.Moore@Sun.COM 27*7750SSherry.Moore@Sun.COM /* 28*7750SSherry.Moore@Sun.COM * This file contains the functions for performing Fast Reboot -- a 29*7750SSherry.Moore@Sun.COM * reboot which bypasses the firmware and bootloader, considerably 30*7750SSherry.Moore@Sun.COM * reducing downtime. 31*7750SSherry.Moore@Sun.COM * 32*7750SSherry.Moore@Sun.COM * load_kernel(): This function is invoked by mdpreboot() in the reboot 33*7750SSherry.Moore@Sun.COM * path. It loads the new kernel and boot archive into memory, builds 34*7750SSherry.Moore@Sun.COM * the data structure containing sufficient information about the new 35*7750SSherry.Moore@Sun.COM * kernel and boot archive to be passed to the fast reboot switcher 36*7750SSherry.Moore@Sun.COM * (see fb_swtch_src.s for details). When invoked the switcher relocates 37*7750SSherry.Moore@Sun.COM * the new kernel and boot archive to physically contiguous low memory, 38*7750SSherry.Moore@Sun.COM * similar to where the boot loader would have loaded them, and jumps to 39*7750SSherry.Moore@Sun.COM * the new kernel. 40*7750SSherry.Moore@Sun.COM * 41*7750SSherry.Moore@Sun.COM * The physical addresses of the memory allocated for the new kernel, boot 42*7750SSherry.Moore@Sun.COM * archive and their page tables must be above where the boot archive ends 43*7750SSherry.Moore@Sun.COM * after it has been relocated by the switcher, otherwise the new files 44*7750SSherry.Moore@Sun.COM * and their page tables could be overridden during relocation. 45*7750SSherry.Moore@Sun.COM * 46*7750SSherry.Moore@Sun.COM * fast_reboot(): This function is invoked by mdboot() once it's determined 47*7750SSherry.Moore@Sun.COM * that the system is capable of fast reboot. It jumps to the fast reboot 48*7750SSherry.Moore@Sun.COM * switcher with the data structure built by load_kernel() as the argument. 49*7750SSherry.Moore@Sun.COM */ 507656SSherry.Moore@Sun.COM 517656SSherry.Moore@Sun.COM #include <sys/types.h> 527656SSherry.Moore@Sun.COM #include <sys/param.h> 537656SSherry.Moore@Sun.COM #include <sys/segments.h> 547656SSherry.Moore@Sun.COM #include <sys/sysmacros.h> 557656SSherry.Moore@Sun.COM #include <sys/vm.h> 567656SSherry.Moore@Sun.COM 577656SSherry.Moore@Sun.COM #include <sys/proc.h> 587656SSherry.Moore@Sun.COM #include <sys/buf.h> 597656SSherry.Moore@Sun.COM #include <sys/kmem.h> 607656SSherry.Moore@Sun.COM 617656SSherry.Moore@Sun.COM #include <sys/reboot.h> 627656SSherry.Moore@Sun.COM #include <sys/uadmin.h> 637656SSherry.Moore@Sun.COM 647656SSherry.Moore@Sun.COM #include <sys/cred.h> 657656SSherry.Moore@Sun.COM #include <sys/vnode.h> 667656SSherry.Moore@Sun.COM #include <sys/file.h> 677656SSherry.Moore@Sun.COM 687656SSherry.Moore@Sun.COM #include <sys/cmn_err.h> 697656SSherry.Moore@Sun.COM #include <sys/dumphdr.h> 707656SSherry.Moore@Sun.COM #include <sys/bootconf.h> 717656SSherry.Moore@Sun.COM #include <sys/ddidmareq.h> 727656SSherry.Moore@Sun.COM #include <sys/varargs.h> 737656SSherry.Moore@Sun.COM #include <sys/promif.h> 747656SSherry.Moore@Sun.COM #include <sys/modctl.h> 757656SSherry.Moore@Sun.COM 767656SSherry.Moore@Sun.COM #include <vm/hat.h> 777656SSherry.Moore@Sun.COM #include <vm/as.h> 787656SSherry.Moore@Sun.COM #include <vm/page.h> 797656SSherry.Moore@Sun.COM #include <vm/seg.h> 807656SSherry.Moore@Sun.COM #include <vm/hat_i86.h> 817656SSherry.Moore@Sun.COM #include <sys/vm_machparam.h> 827656SSherry.Moore@Sun.COM #include <sys/archsystm.h> 837656SSherry.Moore@Sun.COM #include <sys/machsystm.h> 847656SSherry.Moore@Sun.COM #include <sys/mman.h> 857656SSherry.Moore@Sun.COM #include <sys/x86_archext.h> 867656SSherry.Moore@Sun.COM 877656SSherry.Moore@Sun.COM #include <sys/fastboot.h> 887656SSherry.Moore@Sun.COM #include <sys/machelf.h> 897656SSherry.Moore@Sun.COM #include <sys/kobj.h> 907656SSherry.Moore@Sun.COM #include <sys/multiboot.h> 917656SSherry.Moore@Sun.COM 92*7750SSherry.Moore@Sun.COM /* 93*7750SSherry.Moore@Sun.COM * Data structure containing necessary information for the fast reboot 94*7750SSherry.Moore@Sun.COM * switcher to jump to the new kernel. 95*7750SSherry.Moore@Sun.COM */ 967656SSherry.Moore@Sun.COM fastboot_info_t newkernel = { 0 }; 97*7750SSherry.Moore@Sun.COM 987656SSherry.Moore@Sun.COM static char fastboot_filename[2][OBP_MAXPATHLEN] = { { 0 }, { 0 }}; 997656SSherry.Moore@Sun.COM static x86pte_t ptp_bits = PT_VALID | PT_REF | PT_USER | PT_WRITABLE; 1007656SSherry.Moore@Sun.COM static x86pte_t pte_bits = 1017656SSherry.Moore@Sun.COM PT_VALID | PT_REF | PT_MOD | PT_NOCONSIST | PT_WRITABLE; 1027656SSherry.Moore@Sun.COM static uint_t fastboot_shift_amt_pae[] = {12, 21, 30, 39}; 1037656SSherry.Moore@Sun.COM 1047656SSherry.Moore@Sun.COM int fastboot_debug = 0; 1057656SSherry.Moore@Sun.COM int fastboot_contig = 0; 1067656SSherry.Moore@Sun.COM 1077656SSherry.Moore@Sun.COM /* 1087656SSherry.Moore@Sun.COM * Fake starting va for new kernel and boot archive. 1097656SSherry.Moore@Sun.COM */ 1107656SSherry.Moore@Sun.COM static uintptr_t fake_va = FASTBOOT_FAKE_VA; 1117656SSherry.Moore@Sun.COM 1127656SSherry.Moore@Sun.COM /* 1137656SSherry.Moore@Sun.COM * Below 1G for page tables as we are using 2G as the fake virtual address for 1147656SSherry.Moore@Sun.COM * the new kernel and boot archive. 1157656SSherry.Moore@Sun.COM */ 1167656SSherry.Moore@Sun.COM static ddi_dma_attr_t fastboot_below_1G_dma_attr = { 1177656SSherry.Moore@Sun.COM DMA_ATTR_V0, 1187656SSherry.Moore@Sun.COM 0x0000000008000000ULL, /* dma_attr_addr_lo: 128MB */ 1197656SSherry.Moore@Sun.COM 0x000000003FFFFFFFULL, /* dma_attr_addr_hi: 1G */ 1207656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_count_max */ 1217656SSherry.Moore@Sun.COM 0x0000000000001000ULL, /* dma_attr_align: 4KB */ 1227656SSherry.Moore@Sun.COM 1, /* dma_attr_burstsize */ 1237656SSherry.Moore@Sun.COM 1, /* dma_attr_minxfer */ 1247656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_maxxfer */ 1257656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_seg */ 1267656SSherry.Moore@Sun.COM 1, /* dma_attr_sgllen */ 1277656SSherry.Moore@Sun.COM 0x1000ULL, /* dma_attr_granular */ 1287656SSherry.Moore@Sun.COM 0, /* dma_attr_flags */ 1297656SSherry.Moore@Sun.COM }; 1307656SSherry.Moore@Sun.COM 1317656SSherry.Moore@Sun.COM static ddi_dma_attr_t fastboot_dma_attr = { 1327656SSherry.Moore@Sun.COM DMA_ATTR_V0, 1337656SSherry.Moore@Sun.COM 0x0000000008000000ULL, /* dma_attr_addr_lo: 128MB */ 1347656SSherry.Moore@Sun.COM 0x0000000FFFFFFFFFULL, /* dma_attr_addr_hi: 64GB */ 1357656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_count_max */ 1367656SSherry.Moore@Sun.COM 0x0000000000001000ULL, /* dma_attr_align: 4KB */ 1377656SSherry.Moore@Sun.COM 1, /* dma_attr_burstsize */ 1387656SSherry.Moore@Sun.COM 1, /* dma_attr_minxfer */ 1397656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_maxxfer */ 1407656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_seg */ 1417656SSherry.Moore@Sun.COM 1, /* dma_attr_sgllen */ 1427656SSherry.Moore@Sun.COM 0x1000ULL, /* dma_attr_granular */ 1437656SSherry.Moore@Sun.COM 0, /* dma_attr_flags */ 1447656SSherry.Moore@Sun.COM }; 1457656SSherry.Moore@Sun.COM 1467656SSherry.Moore@Sun.COM /* 1477656SSherry.Moore@Sun.COM * Various information saved from the previous boot to reconstruct 1487656SSherry.Moore@Sun.COM * multiboot_info. 1497656SSherry.Moore@Sun.COM */ 1507656SSherry.Moore@Sun.COM extern multiboot_info_t saved_mbi; 1517656SSherry.Moore@Sun.COM extern mb_memory_map_t saved_mmap[FASTBOOT_SAVED_MMAP_COUNT]; 1527656SSherry.Moore@Sun.COM extern struct sol_netinfo saved_drives[FASTBOOT_SAVED_DRIVES_COUNT]; 1537656SSherry.Moore@Sun.COM extern char saved_cmdline[FASTBOOT_SAVED_CMDLINE_LEN]; 1547656SSherry.Moore@Sun.COM extern int saved_cmdline_len; 1557656SSherry.Moore@Sun.COM 1567656SSherry.Moore@Sun.COM extern void* contig_alloc(size_t size, ddi_dma_attr_t *attr, 1577656SSherry.Moore@Sun.COM uintptr_t align, int cansleep); 158*7750SSherry.Moore@Sun.COM extern void contig_free(void *addr, size_t size); 159*7750SSherry.Moore@Sun.COM 1607656SSherry.Moore@Sun.COM 1617656SSherry.Moore@Sun.COM /* PRINTLIKE */ 1627656SSherry.Moore@Sun.COM extern void vprintf(const char *, va_list); 1637656SSherry.Moore@Sun.COM 1647656SSherry.Moore@Sun.COM 1657656SSherry.Moore@Sun.COM /* 1667656SSherry.Moore@Sun.COM * Need to be able to get boot_archives from other places 1677656SSherry.Moore@Sun.COM */ 1687656SSherry.Moore@Sun.COM #define BOOTARCHIVE64 "/platform/i86pc/amd64/boot_archive" 1697656SSherry.Moore@Sun.COM #define BOOTARCHIVE32 "/platform/i86pc/boot_archive" 1707656SSherry.Moore@Sun.COM #define BOOTARCHIVE_FAILSAFE "/boot/x86.miniroot-safe" 1717656SSherry.Moore@Sun.COM #define FAILSAFE_BOOTFILE "/boot/platform/i86pc/kernel/unix" 1727656SSherry.Moore@Sun.COM 1737656SSherry.Moore@Sun.COM static uint_t fastboot_vatoindex(fastboot_info_t *, uintptr_t, int); 1747656SSherry.Moore@Sun.COM static void fastboot_map_with_size(fastboot_info_t *, uintptr_t, 1757656SSherry.Moore@Sun.COM paddr_t, size_t, int); 1767656SSherry.Moore@Sun.COM static void fastboot_build_pagetables(fastboot_info_t *); 1777656SSherry.Moore@Sun.COM static int fastboot_build_mbi(char *, fastboot_info_t *); 1787656SSherry.Moore@Sun.COM 1797656SSherry.Moore@Sun.COM static const char fastboot_enomem_msg[] = "Fastboot: Couldn't allocate 0x%" 1807656SSherry.Moore@Sun.COM PRIx64" bytes below %s to do fast reboot"; 1817656SSherry.Moore@Sun.COM 1827656SSherry.Moore@Sun.COM static void 1837656SSherry.Moore@Sun.COM dprintf(char *fmt, ...) 1847656SSherry.Moore@Sun.COM { 1857656SSherry.Moore@Sun.COM va_list adx; 1867656SSherry.Moore@Sun.COM 1877656SSherry.Moore@Sun.COM if (!fastboot_debug) 1887656SSherry.Moore@Sun.COM return; 1897656SSherry.Moore@Sun.COM 1907656SSherry.Moore@Sun.COM va_start(adx, fmt); 1917656SSherry.Moore@Sun.COM vprintf(fmt, adx); 1927656SSherry.Moore@Sun.COM va_end(adx); 1937656SSherry.Moore@Sun.COM } 1947656SSherry.Moore@Sun.COM 1957656SSherry.Moore@Sun.COM 1967656SSherry.Moore@Sun.COM /* 1977656SSherry.Moore@Sun.COM * Return the index corresponding to a virt address at a given page table level. 1987656SSherry.Moore@Sun.COM */ 1997656SSherry.Moore@Sun.COM static uint_t 2007656SSherry.Moore@Sun.COM fastboot_vatoindex(fastboot_info_t *nk, uintptr_t va, int level) 2017656SSherry.Moore@Sun.COM { 2027656SSherry.Moore@Sun.COM return ((va >> nk->fi_shift_amt[level]) & (nk->fi_ptes_per_table - 1)); 2037656SSherry.Moore@Sun.COM } 2047656SSherry.Moore@Sun.COM 2057656SSherry.Moore@Sun.COM 2067656SSherry.Moore@Sun.COM /* 2077656SSherry.Moore@Sun.COM * Add mapping from vstart to pstart for the specified size. 2087656SSherry.Moore@Sun.COM * Only handles 2 level. Must use 2M pages. vstart, pstart 2097656SSherry.Moore@Sun.COM * and size should all have been aligned at 2M boundaries. 2107656SSherry.Moore@Sun.COM */ 2117656SSherry.Moore@Sun.COM static void 2127656SSherry.Moore@Sun.COM fastboot_map_with_size(fastboot_info_t *nk, uintptr_t vstart, paddr_t pstart, 2137656SSherry.Moore@Sun.COM size_t size, int level) 2147656SSherry.Moore@Sun.COM { 2157656SSherry.Moore@Sun.COM x86pte_t pteval, *table; 2167656SSherry.Moore@Sun.COM uintptr_t vaddr; 2177656SSherry.Moore@Sun.COM paddr_t paddr; 2187656SSherry.Moore@Sun.COM int index, l; 2197656SSherry.Moore@Sun.COM 2207656SSherry.Moore@Sun.COM table = (x86pte_t *)(nk->fi_pagetable_va); 2217656SSherry.Moore@Sun.COM 2227656SSherry.Moore@Sun.COM for (l = nk->fi_top_level; l >= level; l--) { 2237656SSherry.Moore@Sun.COM 2247656SSherry.Moore@Sun.COM index = fastboot_vatoindex(nk, vstart, l); 2257656SSherry.Moore@Sun.COM 2267656SSherry.Moore@Sun.COM if (l == level) { 2277656SSherry.Moore@Sun.COM /* 2287656SSherry.Moore@Sun.COM * Last level. Program the page table entries. 2297656SSherry.Moore@Sun.COM */ 2307656SSherry.Moore@Sun.COM for (vaddr = vstart, paddr = pstart; 2317656SSherry.Moore@Sun.COM vaddr < vstart + size; 2327656SSherry.Moore@Sun.COM vaddr += (1ULL << nk->fi_shift_amt[l]), 2337656SSherry.Moore@Sun.COM paddr += (1ULL << nk->fi_shift_amt[l])) { 2347656SSherry.Moore@Sun.COM 2357656SSherry.Moore@Sun.COM uint_t index = fastboot_vatoindex(nk, vaddr, l); 2367656SSherry.Moore@Sun.COM 2377656SSherry.Moore@Sun.COM if (l > 0) 2387656SSherry.Moore@Sun.COM pteval = paddr | pte_bits | PT_PAGESIZE; 2397656SSherry.Moore@Sun.COM else 2407656SSherry.Moore@Sun.COM pteval = paddr | pte_bits; 2417656SSherry.Moore@Sun.COM 2427656SSherry.Moore@Sun.COM table[index] = pteval; 2437656SSherry.Moore@Sun.COM } 2447656SSherry.Moore@Sun.COM } else if (table[index] & PT_VALID) { 2457656SSherry.Moore@Sun.COM if (l == level) 2467656SSherry.Moore@Sun.COM break; 2477656SSherry.Moore@Sun.COM 2487656SSherry.Moore@Sun.COM table = (x86pte_t *) 2497656SSherry.Moore@Sun.COM ((uintptr_t)(((paddr_t)table[index] & MMU_PAGEMASK) 2507656SSherry.Moore@Sun.COM - nk->fi_pagetable_pa) + nk->fi_pagetable_va); 2517656SSherry.Moore@Sun.COM } else { 2527656SSherry.Moore@Sun.COM /* 2537656SSherry.Moore@Sun.COM * Intermediate levels. Program with either valid 2547656SSherry.Moore@Sun.COM * bit or PTP bits. 2557656SSherry.Moore@Sun.COM */ 2567656SSherry.Moore@Sun.COM if (l == nk->fi_top_level) { 2577656SSherry.Moore@Sun.COM table[index] = nk->fi_next_table_pa | PT_VALID; 2587656SSherry.Moore@Sun.COM } else { 2597656SSherry.Moore@Sun.COM table[index] = nk->fi_next_table_pa | ptp_bits; 2607656SSherry.Moore@Sun.COM } 2617656SSherry.Moore@Sun.COM table = (x86pte_t *)(nk->fi_next_table_va); 2627656SSherry.Moore@Sun.COM nk->fi_next_table_va += MMU_PAGESIZE; 2637656SSherry.Moore@Sun.COM nk->fi_next_table_pa += MMU_PAGESIZE; 2647656SSherry.Moore@Sun.COM } 2657656SSherry.Moore@Sun.COM } 2667656SSherry.Moore@Sun.COM } 2677656SSherry.Moore@Sun.COM 2687656SSherry.Moore@Sun.COM /* 2697656SSherry.Moore@Sun.COM * Build page tables for the lower 1G of physical memory using 2M 2707656SSherry.Moore@Sun.COM * pages, and prepare page tables for mapping new kernel and boot 2717656SSherry.Moore@Sun.COM * archive pages using 4K pages. 2727656SSherry.Moore@Sun.COM */ 2737656SSherry.Moore@Sun.COM static void 2747656SSherry.Moore@Sun.COM fastboot_build_pagetables(fastboot_info_t *nk) 2757656SSherry.Moore@Sun.COM { 2767656SSherry.Moore@Sun.COM /* 2777656SSherry.Moore@Sun.COM * Map lower 1G physical memory. Use large pages. 2787656SSherry.Moore@Sun.COM */ 2797656SSherry.Moore@Sun.COM fastboot_map_with_size(nk, 0, 0, ONE_GIG, 1); 2807656SSherry.Moore@Sun.COM 2817656SSherry.Moore@Sun.COM /* 2827656SSherry.Moore@Sun.COM * Map one 4K page to get the middle page tables set up. 2837656SSherry.Moore@Sun.COM */ 2847656SSherry.Moore@Sun.COM fake_va = P2ALIGN_TYPED(fake_va, nk->fi_lpagesize, uintptr_t); 2857656SSherry.Moore@Sun.COM fastboot_map_with_size(nk, fake_va, 2867656SSherry.Moore@Sun.COM nk->fi_files[0].fb_pte_list_va[0] & MMU_PAGEMASK, PAGESIZE, 0); 2877656SSherry.Moore@Sun.COM } 2887656SSherry.Moore@Sun.COM 2897656SSherry.Moore@Sun.COM 2907656SSherry.Moore@Sun.COM /* 2917656SSherry.Moore@Sun.COM * Sanity check. Look for dboot offset. 2927656SSherry.Moore@Sun.COM */ 2937656SSherry.Moore@Sun.COM static int 2947656SSherry.Moore@Sun.COM fastboot_elf64_find_dboot_load_offset(void *img, off_t imgsz, uint32_t *offp) 2957656SSherry.Moore@Sun.COM { 2967656SSherry.Moore@Sun.COM Elf64_Ehdr *ehdr = (Elf64_Ehdr *)img; 2977656SSherry.Moore@Sun.COM Elf64_Phdr *phdr; 2987656SSherry.Moore@Sun.COM uint8_t *phdrbase; 2997656SSherry.Moore@Sun.COM int i; 3007656SSherry.Moore@Sun.COM 3017656SSherry.Moore@Sun.COM if ((ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize) >= imgsz) 3027656SSherry.Moore@Sun.COM return (-1); 3037656SSherry.Moore@Sun.COM 3047656SSherry.Moore@Sun.COM phdrbase = (uint8_t *)img + ehdr->e_phoff; 3057656SSherry.Moore@Sun.COM 3067656SSherry.Moore@Sun.COM for (i = 0; i < ehdr->e_phnum; i++) { 3077656SSherry.Moore@Sun.COM phdr = (Elf64_Phdr *)(phdrbase + ehdr->e_phentsize * i); 3087656SSherry.Moore@Sun.COM 3097656SSherry.Moore@Sun.COM if (phdr->p_type == PT_LOAD) { 3107656SSherry.Moore@Sun.COM if (phdr->p_vaddr == phdr->p_paddr && 3117656SSherry.Moore@Sun.COM phdr->p_vaddr == DBOOT_ENTRY_ADDRESS) { 3127656SSherry.Moore@Sun.COM ASSERT(phdr->p_offset <= UINT32_MAX); 3137656SSherry.Moore@Sun.COM *offp = (uint32_t)phdr->p_offset; 3147656SSherry.Moore@Sun.COM return (0); 3157656SSherry.Moore@Sun.COM } 3167656SSherry.Moore@Sun.COM } 3177656SSherry.Moore@Sun.COM } 3187656SSherry.Moore@Sun.COM 3197656SSherry.Moore@Sun.COM return (-1); 3207656SSherry.Moore@Sun.COM } 3217656SSherry.Moore@Sun.COM 3227656SSherry.Moore@Sun.COM 3237656SSherry.Moore@Sun.COM /* 3247656SSherry.Moore@Sun.COM * Initialize text and data section information for 32-bit kernel. 3257656SSherry.Moore@Sun.COM */ 3267656SSherry.Moore@Sun.COM static int 3277656SSherry.Moore@Sun.COM fastboot_elf32_find_loadables(void *img, off_t imgsz, fastboot_section_t *sectp, 3287656SSherry.Moore@Sun.COM int *sectcntp, uint32_t *offp) 3297656SSherry.Moore@Sun.COM { 3307656SSherry.Moore@Sun.COM Elf32_Ehdr *ehdr = (Elf32_Ehdr *)img; 3317656SSherry.Moore@Sun.COM Elf32_Phdr *phdr; 3327656SSherry.Moore@Sun.COM uint8_t *phdrbase; 3337656SSherry.Moore@Sun.COM int i; 3347656SSherry.Moore@Sun.COM int used_sections = 0; 3357656SSherry.Moore@Sun.COM 3367656SSherry.Moore@Sun.COM 3377656SSherry.Moore@Sun.COM if ((ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize) >= imgsz) 3387656SSherry.Moore@Sun.COM return (-1); 3397656SSherry.Moore@Sun.COM 3407656SSherry.Moore@Sun.COM phdrbase = (uint8_t *)img + ehdr->e_phoff; 3417656SSherry.Moore@Sun.COM 3427656SSherry.Moore@Sun.COM for (i = 0; i < ehdr->e_phnum; i++) { 3437656SSherry.Moore@Sun.COM phdr = (Elf32_Phdr *)(phdrbase + ehdr->e_phentsize * i); 3447656SSherry.Moore@Sun.COM 3457656SSherry.Moore@Sun.COM if (phdr->p_type == PT_INTERP) 3467656SSherry.Moore@Sun.COM return (-1); 3477656SSherry.Moore@Sun.COM 3487656SSherry.Moore@Sun.COM if (phdr->p_type != PT_LOAD) 3497656SSherry.Moore@Sun.COM continue; 3507656SSherry.Moore@Sun.COM 3517656SSherry.Moore@Sun.COM if (phdr->p_vaddr == phdr->p_paddr && 3527656SSherry.Moore@Sun.COM phdr->p_paddr == DBOOT_ENTRY_ADDRESS) { 3537656SSherry.Moore@Sun.COM *offp = (uint32_t)phdr->p_offset; 3547656SSherry.Moore@Sun.COM } else { 3557656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_offset = phdr->p_offset; 3567656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_paddr = phdr->p_paddr; 3577656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_size = phdr->p_filesz; 3587656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_bss_size = 3597656SSherry.Moore@Sun.COM (phdr->p_filesz < phdr->p_memsz) ? 3607656SSherry.Moore@Sun.COM (phdr->p_memsz - phdr->p_filesz) : 0; 3617656SSherry.Moore@Sun.COM 3627656SSherry.Moore@Sun.COM used_sections++; 3637656SSherry.Moore@Sun.COM } 3647656SSherry.Moore@Sun.COM 3657656SSherry.Moore@Sun.COM } 3667656SSherry.Moore@Sun.COM 3677656SSherry.Moore@Sun.COM *sectcntp = used_sections; 3687656SSherry.Moore@Sun.COM return (0); 3697656SSherry.Moore@Sun.COM } 3707656SSherry.Moore@Sun.COM 3717656SSherry.Moore@Sun.COM /* 3727656SSherry.Moore@Sun.COM * Create multiboot info structure 3737656SSherry.Moore@Sun.COM */ 3747656SSherry.Moore@Sun.COM static int 3757656SSherry.Moore@Sun.COM fastboot_build_mbi(char *mdep, fastboot_info_t *nk) 3767656SSherry.Moore@Sun.COM { 3777656SSherry.Moore@Sun.COM mb_module_t *mbp; 3787656SSherry.Moore@Sun.COM uintptr_t next_addr; 3797656SSherry.Moore@Sun.COM uintptr_t new_mbi_pa; 3807656SSherry.Moore@Sun.COM size_t size; 3817656SSherry.Moore@Sun.COM void *buf = NULL; 3827656SSherry.Moore@Sun.COM size_t arglen; 3837656SSherry.Moore@Sun.COM char bootargs[OBP_MAXPATHLEN]; 3847656SSherry.Moore@Sun.COM 3857656SSherry.Moore@Sun.COM bzero(bootargs, OBP_MAXPATHLEN); 3867656SSherry.Moore@Sun.COM 387*7750SSherry.Moore@Sun.COM if (mdep != NULL && strlen(mdep) != 0) { 3887656SSherry.Moore@Sun.COM arglen = strlen(mdep) + 1; 3897656SSherry.Moore@Sun.COM } else { 3907656SSherry.Moore@Sun.COM arglen = saved_cmdline_len; 3917656SSherry.Moore@Sun.COM } 3927656SSherry.Moore@Sun.COM 3937656SSherry.Moore@Sun.COM size = PAGESIZE + P2ROUNDUP(arglen, PAGESIZE); 3947656SSherry.Moore@Sun.COM buf = contig_alloc(size, &fastboot_below_1G_dma_attr, PAGESIZE, 0); 3957656SSherry.Moore@Sun.COM if (buf == NULL) { 3967656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, (uint64_t)size, "1G"); 3977656SSherry.Moore@Sun.COM return (-1); 3987656SSherry.Moore@Sun.COM } 3997656SSherry.Moore@Sun.COM 4007656SSherry.Moore@Sun.COM bzero(buf, size); 4017656SSherry.Moore@Sun.COM 4027656SSherry.Moore@Sun.COM new_mbi_pa = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, (caddr_t)buf)); 4037656SSherry.Moore@Sun.COM 4047656SSherry.Moore@Sun.COM hat_devload(kas.a_hat, (caddr_t)new_mbi_pa, size, 4057656SSherry.Moore@Sun.COM mmu_btop(new_mbi_pa), PROT_READ | PROT_WRITE, HAT_LOAD_NOCONSIST); 4067656SSherry.Moore@Sun.COM 4077656SSherry.Moore@Sun.COM nk->fi_new_mbi_pa = (paddr_t)new_mbi_pa; 4087656SSherry.Moore@Sun.COM 4097656SSherry.Moore@Sun.COM bcopy(&saved_mbi, (void *)new_mbi_pa, sizeof (multiboot_info_t)); 4107656SSherry.Moore@Sun.COM 4117656SSherry.Moore@Sun.COM next_addr = new_mbi_pa + sizeof (multiboot_info_t); 4127656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->mods_addr = next_addr; 4137656SSherry.Moore@Sun.COM mbp = (mb_module_t *)(uintptr_t)next_addr; 4147656SSherry.Moore@Sun.COM mbp->mod_start = newkernel.fi_files[FASTBOOT_BOOTARCHIVE].fb_dest_pa; 4157656SSherry.Moore@Sun.COM mbp->mod_end = newkernel.fi_files[FASTBOOT_BOOTARCHIVE].fb_next_pa; 4167656SSherry.Moore@Sun.COM 4177656SSherry.Moore@Sun.COM next_addr += sizeof (mb_module_t); 4187656SSherry.Moore@Sun.COM bcopy(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE], (void *)next_addr, 4197656SSherry.Moore@Sun.COM strlen(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE])); 4207656SSherry.Moore@Sun.COM 4217656SSherry.Moore@Sun.COM mbp->mod_name = next_addr; 4227656SSherry.Moore@Sun.COM mbp->reserved = 0; 4237656SSherry.Moore@Sun.COM next_addr += strlen(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE]); 4247656SSherry.Moore@Sun.COM *(char *)next_addr = '\0'; 4257656SSherry.Moore@Sun.COM next_addr++; 4267656SSherry.Moore@Sun.COM next_addr = P2ROUNDUP_TYPED(next_addr, 16, uintptr_t); 4277656SSherry.Moore@Sun.COM 4287656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->mmap_addr = next_addr; 4297656SSherry.Moore@Sun.COM bcopy((void *)(uintptr_t)saved_mmap, (void *)next_addr, 4307656SSherry.Moore@Sun.COM saved_mbi.mmap_length); 4317656SSherry.Moore@Sun.COM next_addr += saved_mbi.mmap_length; 4327656SSherry.Moore@Sun.COM 4337656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->drives_addr = next_addr; 4347656SSherry.Moore@Sun.COM bcopy((void *)(uintptr_t)saved_drives, (void *)next_addr, 4357656SSherry.Moore@Sun.COM saved_mbi.drives_length); 4367656SSherry.Moore@Sun.COM next_addr += saved_mbi.drives_length; 4377656SSherry.Moore@Sun.COM 4387656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->cmdline = next_addr; 4397656SSherry.Moore@Sun.COM 440*7750SSherry.Moore@Sun.COM if (mdep != NULL && strlen(mdep) != 0) { 4417656SSherry.Moore@Sun.COM bcopy(mdep, (void *)(uintptr_t) 4427656SSherry.Moore@Sun.COM (((multiboot_info_t *)new_mbi_pa)->cmdline), (arglen - 1)); 4437656SSherry.Moore@Sun.COM } else { 4447656SSherry.Moore@Sun.COM bcopy((void *)saved_cmdline, (void *)next_addr, (arglen - 1)); 4457656SSherry.Moore@Sun.COM } 4467656SSherry.Moore@Sun.COM /* Terminate the string */ 4477656SSherry.Moore@Sun.COM ((char *)(intptr_t)next_addr)[arglen - 1] = '\0'; 4487656SSherry.Moore@Sun.COM 4497656SSherry.Moore@Sun.COM return (0); 4507656SSherry.Moore@Sun.COM } 4517656SSherry.Moore@Sun.COM 452*7750SSherry.Moore@Sun.COM /* 453*7750SSherry.Moore@Sun.COM * Initialize HAT related fields 454*7750SSherry.Moore@Sun.COM */ 455*7750SSherry.Moore@Sun.COM static void 456*7750SSherry.Moore@Sun.COM fastboot_init_fields(fastboot_info_t *nk) 4577656SSherry.Moore@Sun.COM { 458*7750SSherry.Moore@Sun.COM if (x86_feature & X86_PAE) { 459*7750SSherry.Moore@Sun.COM nk->fi_has_pae = 1; 460*7750SSherry.Moore@Sun.COM nk->fi_shift_amt = fastboot_shift_amt_pae; 461*7750SSherry.Moore@Sun.COM nk->fi_ptes_per_table = 512; 462*7750SSherry.Moore@Sun.COM nk->fi_lpagesize = (2 << 20); /* 2M */ 463*7750SSherry.Moore@Sun.COM nk->fi_top_level = 2; 464*7750SSherry.Moore@Sun.COM } 465*7750SSherry.Moore@Sun.COM } 4667656SSherry.Moore@Sun.COM 467*7750SSherry.Moore@Sun.COM /* 468*7750SSherry.Moore@Sun.COM * Process boot argument 469*7750SSherry.Moore@Sun.COM */ 470*7750SSherry.Moore@Sun.COM static void 471*7750SSherry.Moore@Sun.COM fastboot_parse_mdep(char *mdep, char *kern_bootpath, int *bootpath_len, 472*7750SSherry.Moore@Sun.COM char *bootargs) 473*7750SSherry.Moore@Sun.COM { 474*7750SSherry.Moore@Sun.COM int i; 4757656SSherry.Moore@Sun.COM 4767656SSherry.Moore@Sun.COM /* 4777656SSherry.Moore@Sun.COM * If mdep is not NULL, it comes in the format of 4787656SSherry.Moore@Sun.COM * mountpoint unix args 4797656SSherry.Moore@Sun.COM */ 480*7750SSherry.Moore@Sun.COM if (mdep != NULL && strlen(mdep) != 0) { 4817656SSherry.Moore@Sun.COM if (mdep[0] != '-') { 4827656SSherry.Moore@Sun.COM /* First get the root argument */ 4837656SSherry.Moore@Sun.COM i = 0; 4847656SSherry.Moore@Sun.COM while (mdep[i] != '\0' && mdep[i] != ' ') { 4857656SSherry.Moore@Sun.COM i++; 4867656SSherry.Moore@Sun.COM } 4877656SSherry.Moore@Sun.COM 4887656SSherry.Moore@Sun.COM if (i < 4 || strncmp(&mdep[i-4], "unix", 4) != 0) { 4897656SSherry.Moore@Sun.COM /* mount point */ 4907656SSherry.Moore@Sun.COM bcopy(mdep, kern_bootpath, i); 4917656SSherry.Moore@Sun.COM kern_bootpath[i] = '\0'; 492*7750SSherry.Moore@Sun.COM *bootpath_len = i; 4937656SSherry.Moore@Sun.COM 4947656SSherry.Moore@Sun.COM /* 4957656SSherry.Moore@Sun.COM * Get the next argument. It should be unix as 4967656SSherry.Moore@Sun.COM * we have validated in in halt.c. 4977656SSherry.Moore@Sun.COM */ 4987656SSherry.Moore@Sun.COM if (strlen(mdep) > i) { 4997656SSherry.Moore@Sun.COM mdep += (i + 1); 5007656SSherry.Moore@Sun.COM i = 0; 5017656SSherry.Moore@Sun.COM while (mdep[i] != '\0' && 5027656SSherry.Moore@Sun.COM mdep[i] != ' ') { 5037656SSherry.Moore@Sun.COM i++; 5047656SSherry.Moore@Sun.COM } 5057656SSherry.Moore@Sun.COM } 5067656SSherry.Moore@Sun.COM 5077656SSherry.Moore@Sun.COM } 5087656SSherry.Moore@Sun.COM bcopy(mdep, kern_bootfile, i); 5097656SSherry.Moore@Sun.COM kern_bootfile[i] = '\0'; 510*7750SSherry.Moore@Sun.COM bcopy(mdep, bootargs, strlen(mdep)); 5117656SSherry.Moore@Sun.COM } else { 5127656SSherry.Moore@Sun.COM int off = strlen(kern_bootfile); 5137656SSherry.Moore@Sun.COM bcopy(kern_bootfile, bootargs, off); 5147656SSherry.Moore@Sun.COM bcopy(" ", &bootargs[off++], 1); 5157656SSherry.Moore@Sun.COM bcopy(mdep, &bootargs[off], strlen(mdep)); 5167656SSherry.Moore@Sun.COM off += strlen(mdep); 5177656SSherry.Moore@Sun.COM bootargs[off] = '\0'; 5187656SSherry.Moore@Sun.COM } 5197656SSherry.Moore@Sun.COM } 520*7750SSherry.Moore@Sun.COM } 521*7750SSherry.Moore@Sun.COM 522*7750SSherry.Moore@Sun.COM /* 523*7750SSherry.Moore@Sun.COM * Free up the memory we have allocated for this file 524*7750SSherry.Moore@Sun.COM */ 525*7750SSherry.Moore@Sun.COM static void 526*7750SSherry.Moore@Sun.COM fastboot_free_file(fastboot_file_t *fb) 527*7750SSherry.Moore@Sun.COM { 528*7750SSherry.Moore@Sun.COM size_t fsize_roundup, pt_size; 529*7750SSherry.Moore@Sun.COM int pt_entry_count; 530*7750SSherry.Moore@Sun.COM 531*7750SSherry.Moore@Sun.COM fsize_roundup = P2ROUNDUP_TYPED(fb->fb_size, PAGESIZE, size_t); 532*7750SSherry.Moore@Sun.COM contig_free((void *)fb->fb_va, fsize_roundup); 533*7750SSherry.Moore@Sun.COM 534*7750SSherry.Moore@Sun.COM pt_entry_count = (fsize_roundup >> PAGESHIFT) + 1; 535*7750SSherry.Moore@Sun.COM pt_size = P2ROUNDUP(pt_entry_count * 8, PAGESIZE); 536*7750SSherry.Moore@Sun.COM contig_free((void *)fb->fb_pte_list_va, pt_size); 537*7750SSherry.Moore@Sun.COM } 538*7750SSherry.Moore@Sun.COM 539*7750SSherry.Moore@Sun.COM /* 540*7750SSherry.Moore@Sun.COM * This function performs the following tasks: 541*7750SSherry.Moore@Sun.COM * - Read the sizes of the new kernel and boot archive. 542*7750SSherry.Moore@Sun.COM * - Allocate memory for the new kernel and boot archive. 543*7750SSherry.Moore@Sun.COM * - Allocate memory for page tables necessary for mapping the memory 544*7750SSherry.Moore@Sun.COM * allocated for the files. 545*7750SSherry.Moore@Sun.COM * - Read the new kernel and boot archive into memory. 546*7750SSherry.Moore@Sun.COM * - Map in the fast reboot switcher. 547*7750SSherry.Moore@Sun.COM * - Load the fast reboot switcher to FASTBOOT_SWTCH_PA. 548*7750SSherry.Moore@Sun.COM * - Build the new multiboot_info structure 549*7750SSherry.Moore@Sun.COM * - Build page tables for the low 1G of physical memory. 550*7750SSherry.Moore@Sun.COM * - Mark the data structure as valid if all steps have succeeded. 551*7750SSherry.Moore@Sun.COM */ 552*7750SSherry.Moore@Sun.COM void 553*7750SSherry.Moore@Sun.COM load_kernel(char *mdep) 554*7750SSherry.Moore@Sun.COM { 555*7750SSherry.Moore@Sun.COM void *buf = NULL; 556*7750SSherry.Moore@Sun.COM int i; 557*7750SSherry.Moore@Sun.COM fastboot_file_t *fb; 558*7750SSherry.Moore@Sun.COM uint32_t dboot_start_offset; 559*7750SSherry.Moore@Sun.COM char kern_bootpath[OBP_MAXPATHLEN]; 560*7750SSherry.Moore@Sun.COM char bootargs[OBP_MAXPATHLEN]; 561*7750SSherry.Moore@Sun.COM extern uintptr_t postbootkernelbase; 562*7750SSherry.Moore@Sun.COM extern char fb_swtch_image[]; 563*7750SSherry.Moore@Sun.COM int bootpath_len = 0; 564*7750SSherry.Moore@Sun.COM int is_failsafe = 0; 565*7750SSherry.Moore@Sun.COM int is_retry = 0; 566*7750SSherry.Moore@Sun.COM uint64_t end_addr; 567*7750SSherry.Moore@Sun.COM 568*7750SSherry.Moore@Sun.COM ASSERT(fastreboot_capable); 569*7750SSherry.Moore@Sun.COM 570*7750SSherry.Moore@Sun.COM postbootkernelbase = 0; 571*7750SSherry.Moore@Sun.COM 572*7750SSherry.Moore@Sun.COM /* 573*7750SSherry.Moore@Sun.COM * Initialize various HAT related fields in the data structure 574*7750SSherry.Moore@Sun.COM */ 575*7750SSherry.Moore@Sun.COM fastboot_init_fields(&newkernel); 576*7750SSherry.Moore@Sun.COM 577*7750SSherry.Moore@Sun.COM bzero(kern_bootpath, OBP_MAXPATHLEN); 578*7750SSherry.Moore@Sun.COM 579*7750SSherry.Moore@Sun.COM /* 580*7750SSherry.Moore@Sun.COM * Process the boot argument 581*7750SSherry.Moore@Sun.COM */ 582*7750SSherry.Moore@Sun.COM bzero(bootargs, OBP_MAXPATHLEN); 583*7750SSherry.Moore@Sun.COM fastboot_parse_mdep(mdep, kern_bootpath, &bootpath_len, bootargs); 5847656SSherry.Moore@Sun.COM 5857656SSherry.Moore@Sun.COM /* 5867656SSherry.Moore@Sun.COM * Make sure we get the null character 5877656SSherry.Moore@Sun.COM */ 5887656SSherry.Moore@Sun.COM bcopy(kern_bootpath, fastboot_filename[FASTBOOT_NAME_UNIX], 5897656SSherry.Moore@Sun.COM bootpath_len); 5907656SSherry.Moore@Sun.COM bcopy(kern_bootfile, 5917656SSherry.Moore@Sun.COM &fastboot_filename[FASTBOOT_NAME_UNIX][bootpath_len], 5927656SSherry.Moore@Sun.COM strlen(kern_bootfile) + 1); 5937656SSherry.Moore@Sun.COM 5947656SSherry.Moore@Sun.COM bcopy(kern_bootpath, fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE], 5957656SSherry.Moore@Sun.COM bootpath_len); 5967656SSherry.Moore@Sun.COM 5977656SSherry.Moore@Sun.COM if (bcmp(kern_bootfile, FAILSAFE_BOOTFILE, 5987656SSherry.Moore@Sun.COM (sizeof (FAILSAFE_BOOTFILE) - 1)) == 0) { 5997656SSherry.Moore@Sun.COM is_failsafe = 1; 6007656SSherry.Moore@Sun.COM } 6017656SSherry.Moore@Sun.COM 602*7750SSherry.Moore@Sun.COM load_kernel_retry: 6037656SSherry.Moore@Sun.COM /* 6047656SSherry.Moore@Sun.COM * Read in unix and boot_archive 6057656SSherry.Moore@Sun.COM */ 606*7750SSherry.Moore@Sun.COM end_addr = DBOOT_ENTRY_ADDRESS; 6077656SSherry.Moore@Sun.COM for (i = 0; i < FASTBOOT_MAX_FILES_MAP; i++) { 608*7750SSherry.Moore@Sun.COM struct _buf *file; 609*7750SSherry.Moore@Sun.COM uintptr_t va; 610*7750SSherry.Moore@Sun.COM uint64_t fsize; 611*7750SSherry.Moore@Sun.COM size_t fsize_roundup, pt_size; 612*7750SSherry.Moore@Sun.COM int page_index; 613*7750SSherry.Moore@Sun.COM uintptr_t offset; 614*7750SSherry.Moore@Sun.COM int pt_entry_count; 6157656SSherry.Moore@Sun.COM ddi_dma_attr_t dma_attr = fastboot_dma_attr; 6167656SSherry.Moore@Sun.COM 617*7750SSherry.Moore@Sun.COM 6187656SSherry.Moore@Sun.COM dprintf("fastboot_filename[%d] = %s\n", 6197656SSherry.Moore@Sun.COM i, fastboot_filename[i]); 6207656SSherry.Moore@Sun.COM 6217656SSherry.Moore@Sun.COM if ((file = kobj_open_file(fastboot_filename[i])) == 6227656SSherry.Moore@Sun.COM (struct _buf *)-1) { 6237656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Couldn't open %s", 6247656SSherry.Moore@Sun.COM fastboot_filename[i]); 6257656SSherry.Moore@Sun.COM goto err_out; 6267656SSherry.Moore@Sun.COM } 6277656SSherry.Moore@Sun.COM 6287656SSherry.Moore@Sun.COM if (kobj_get_filesize(file, &fsize) != 0) { 6297656SSherry.Moore@Sun.COM cmn_err(CE_WARN, 6307656SSherry.Moore@Sun.COM "Fastboot: Couldn't get filesize for %s", 6317656SSherry.Moore@Sun.COM fastboot_filename[i]); 6327656SSherry.Moore@Sun.COM goto err_out; 6337656SSherry.Moore@Sun.COM } 6347656SSherry.Moore@Sun.COM 635*7750SSherry.Moore@Sun.COM fsize_roundup = P2ROUNDUP_TYPED(fsize, PAGESIZE, size_t); 636*7750SSherry.Moore@Sun.COM 637*7750SSherry.Moore@Sun.COM /* 638*7750SSherry.Moore@Sun.COM * Where the files end in physical memory after being 639*7750SSherry.Moore@Sun.COM * relocated by the fast boot switcher. 640*7750SSherry.Moore@Sun.COM */ 641*7750SSherry.Moore@Sun.COM end_addr += fsize_roundup; 642*7750SSherry.Moore@Sun.COM if (end_addr > fastboot_below_1G_dma_attr.dma_attr_addr_hi) { 643*7750SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: boot archive is too big"); 644*7750SSherry.Moore@Sun.COM goto err_out; 6457656SSherry.Moore@Sun.COM } 6467656SSherry.Moore@Sun.COM 647*7750SSherry.Moore@Sun.COM /* 648*7750SSherry.Moore@Sun.COM * Adjust dma_attr_addr_lo so that the new kernel and boot 649*7750SSherry.Moore@Sun.COM * archive will not be overridden during relocation. 650*7750SSherry.Moore@Sun.COM */ 651*7750SSherry.Moore@Sun.COM if (end_addr > fastboot_dma_attr.dma_attr_addr_lo || 652*7750SSherry.Moore@Sun.COM end_addr > fastboot_below_1G_dma_attr.dma_attr_addr_lo) { 653*7750SSherry.Moore@Sun.COM 654*7750SSherry.Moore@Sun.COM if (is_retry) { 655*7750SSherry.Moore@Sun.COM /* 656*7750SSherry.Moore@Sun.COM * If we have already tried and didn't succeed, 657*7750SSherry.Moore@Sun.COM * just give up. 658*7750SSherry.Moore@Sun.COM */ 659*7750SSherry.Moore@Sun.COM cmn_err(CE_WARN, 660*7750SSherry.Moore@Sun.COM "Fastboot: boot archive is too big"); 661*7750SSherry.Moore@Sun.COM goto err_out; 662*7750SSherry.Moore@Sun.COM } else { 663*7750SSherry.Moore@Sun.COM int j; 664*7750SSherry.Moore@Sun.COM 665*7750SSherry.Moore@Sun.COM /* Set the flag so we don't keep retrying */ 666*7750SSherry.Moore@Sun.COM is_retry++; 667*7750SSherry.Moore@Sun.COM 668*7750SSherry.Moore@Sun.COM /* Adjust dma_attr_addr_lo */ 669*7750SSherry.Moore@Sun.COM fastboot_dma_attr.dma_attr_addr_lo = end_addr; 670*7750SSherry.Moore@Sun.COM fastboot_below_1G_dma_attr.dma_attr_addr_lo = 671*7750SSherry.Moore@Sun.COM end_addr; 672*7750SSherry.Moore@Sun.COM 673*7750SSherry.Moore@Sun.COM /* 674*7750SSherry.Moore@Sun.COM * Free the memory we have already allocated 675*7750SSherry.Moore@Sun.COM * whose physical addresses might not fit 676*7750SSherry.Moore@Sun.COM * the new lo and hi constraints. 677*7750SSherry.Moore@Sun.COM */ 678*7750SSherry.Moore@Sun.COM for (j = 0; j < i; j++) 679*7750SSherry.Moore@Sun.COM fastboot_free_file( 680*7750SSherry.Moore@Sun.COM &newkernel.fi_files[j]); 681*7750SSherry.Moore@Sun.COM goto load_kernel_retry; 682*7750SSherry.Moore@Sun.COM } 683*7750SSherry.Moore@Sun.COM } 684*7750SSherry.Moore@Sun.COM 685*7750SSherry.Moore@Sun.COM 6867656SSherry.Moore@Sun.COM if (!fastboot_contig) 6877656SSherry.Moore@Sun.COM dma_attr.dma_attr_sgllen = (fsize / PAGESIZE) + 6887656SSherry.Moore@Sun.COM (((fsize % PAGESIZE) == 0) ? 0 : 1); 6897656SSherry.Moore@Sun.COM 6907656SSherry.Moore@Sun.COM if ((buf = contig_alloc(fsize, &dma_attr, PAGESIZE, 0)) 6917656SSherry.Moore@Sun.COM == NULL) { 692*7750SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, fsize, "64G"); 6937656SSherry.Moore@Sun.COM goto err_out; 6947656SSherry.Moore@Sun.COM } 6957656SSherry.Moore@Sun.COM 6967656SSherry.Moore@Sun.COM va = P2ROUNDUP_TYPED((uintptr_t)buf, PAGESIZE, uintptr_t); 6977656SSherry.Moore@Sun.COM 6987656SSherry.Moore@Sun.COM if (kobj_read_file(file, (char *)va, fsize, 0) < 0) { 6997656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Couldn't read %s", 7007656SSherry.Moore@Sun.COM fastboot_filename[i]); 7017656SSherry.Moore@Sun.COM goto err_out; 7027656SSherry.Moore@Sun.COM } 7037656SSherry.Moore@Sun.COM 7047656SSherry.Moore@Sun.COM fb = &newkernel.fi_files[i]; 7057656SSherry.Moore@Sun.COM fb->fb_va = va; 7067656SSherry.Moore@Sun.COM fb->fb_size = fsize; 7077656SSherry.Moore@Sun.COM fb->fb_sectcnt = 0; 7087656SSherry.Moore@Sun.COM 7097656SSherry.Moore@Sun.COM /* 7107656SSherry.Moore@Sun.COM * Allocate one extra page table entry for terminating 7117656SSherry.Moore@Sun.COM * the list. 7127656SSherry.Moore@Sun.COM */ 7137656SSherry.Moore@Sun.COM pt_entry_count = (fsize_roundup >> PAGESHIFT) + 1; 7147656SSherry.Moore@Sun.COM pt_size = P2ROUNDUP(pt_entry_count * 8, PAGESIZE); 7157656SSherry.Moore@Sun.COM 7167656SSherry.Moore@Sun.COM if ((fb->fb_pte_list_va = 7177656SSherry.Moore@Sun.COM (x86pte_t *)contig_alloc(pt_size, 7187656SSherry.Moore@Sun.COM &fastboot_below_1G_dma_attr, PAGESIZE, 0)) == NULL) { 7197656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, 7207656SSherry.Moore@Sun.COM (uint64_t)pt_size, "1G"); 7217656SSherry.Moore@Sun.COM goto err_out; 7227656SSherry.Moore@Sun.COM } 7237656SSherry.Moore@Sun.COM 7247656SSherry.Moore@Sun.COM bzero((void *)(fb->fb_pte_list_va), pt_size); 7257656SSherry.Moore@Sun.COM 7267656SSherry.Moore@Sun.COM fb->fb_pte_list_pa = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, 7277656SSherry.Moore@Sun.COM (caddr_t)fb->fb_pte_list_va)); 7287656SSherry.Moore@Sun.COM 7297656SSherry.Moore@Sun.COM for (page_index = 0, offset = 0; offset < fb->fb_size; 7307656SSherry.Moore@Sun.COM offset += PAGESIZE) { 7317656SSherry.Moore@Sun.COM uint64_t paddr; 7327656SSherry.Moore@Sun.COM 7337656SSherry.Moore@Sun.COM paddr = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, 7347656SSherry.Moore@Sun.COM (caddr_t)fb->fb_va + offset)); 7357656SSherry.Moore@Sun.COM 7367656SSherry.Moore@Sun.COM ASSERT(paddr >= fastboot_dma_attr.dma_attr_addr_lo); 7377656SSherry.Moore@Sun.COM 7387656SSherry.Moore@Sun.COM /* 7397656SSherry.Moore@Sun.COM * Include the pte_bits so we don't have to make 7407656SSherry.Moore@Sun.COM * it in assembly. 7417656SSherry.Moore@Sun.COM */ 7427656SSherry.Moore@Sun.COM fb->fb_pte_list_va[page_index++] = (x86pte_t) 7437656SSherry.Moore@Sun.COM (paddr | pte_bits); 7447656SSherry.Moore@Sun.COM } 7457656SSherry.Moore@Sun.COM 7467656SSherry.Moore@Sun.COM fb->fb_pte_list_va[page_index] = FASTBOOT_TERMINATE; 7477656SSherry.Moore@Sun.COM 7487656SSherry.Moore@Sun.COM if (i == FASTBOOT_UNIX) { 749*7750SSherry.Moore@Sun.COM Ehdr *ehdr = (Ehdr *)va; 750*7750SSherry.Moore@Sun.COM int j; 7517656SSherry.Moore@Sun.COM 7527656SSherry.Moore@Sun.COM /* 7537656SSherry.Moore@Sun.COM * Sanity checks: 7547656SSherry.Moore@Sun.COM */ 7557656SSherry.Moore@Sun.COM for (j = 0; j < SELFMAG; j++) { 7567656SSherry.Moore@Sun.COM if (ehdr->e_ident[j] != ELFMAG[j]) { 7577656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Bad ELF " 7587656SSherry.Moore@Sun.COM "signature"); 7597656SSherry.Moore@Sun.COM goto err_out; 7607656SSherry.Moore@Sun.COM } 7617656SSherry.Moore@Sun.COM } 7627656SSherry.Moore@Sun.COM 7637656SSherry.Moore@Sun.COM if (ehdr->e_ident[EI_CLASS] == ELFCLASS32 && 7647656SSherry.Moore@Sun.COM ehdr->e_ident[EI_DATA] == ELFDATA2LSB && 7657656SSherry.Moore@Sun.COM ehdr->e_machine == EM_386) { 7667656SSherry.Moore@Sun.COM 7677656SSherry.Moore@Sun.COM if (fastboot_elf32_find_loadables((void *)va, 7687656SSherry.Moore@Sun.COM fsize, &fb->fb_sections[0], 7697656SSherry.Moore@Sun.COM &fb->fb_sectcnt, &dboot_start_offset) < 0) { 7707656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: ELF32 " 7717656SSherry.Moore@Sun.COM "program section failure"); 7727656SSherry.Moore@Sun.COM goto err_out; 7737656SSherry.Moore@Sun.COM } 7747656SSherry.Moore@Sun.COM 7757656SSherry.Moore@Sun.COM if (fb->fb_sectcnt == 0) { 7767656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: No ELF32 " 7777656SSherry.Moore@Sun.COM "program sections found"); 7787656SSherry.Moore@Sun.COM goto err_out; 7797656SSherry.Moore@Sun.COM } 7807656SSherry.Moore@Sun.COM 7817656SSherry.Moore@Sun.COM if (is_failsafe) { 7827656SSherry.Moore@Sun.COM /* Failsafe boot_archive */ 7837656SSherry.Moore@Sun.COM bcopy(BOOTARCHIVE_FAILSAFE, 7847656SSherry.Moore@Sun.COM &fastboot_filename 7857656SSherry.Moore@Sun.COM [FASTBOOT_NAME_BOOTARCHIVE] 7867656SSherry.Moore@Sun.COM [bootpath_len], 7877656SSherry.Moore@Sun.COM sizeof (BOOTARCHIVE_FAILSAFE)); 7887656SSherry.Moore@Sun.COM } else { 7897656SSherry.Moore@Sun.COM bcopy(BOOTARCHIVE32, 7907656SSherry.Moore@Sun.COM &fastboot_filename 7917656SSherry.Moore@Sun.COM [FASTBOOT_NAME_BOOTARCHIVE] 7927656SSherry.Moore@Sun.COM [bootpath_len], 7937656SSherry.Moore@Sun.COM sizeof (BOOTARCHIVE32)); 7947656SSherry.Moore@Sun.COM } 7957656SSherry.Moore@Sun.COM 7967656SSherry.Moore@Sun.COM } else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64 && 7977656SSherry.Moore@Sun.COM ehdr->e_ident[EI_DATA] == ELFDATA2LSB && 7987656SSherry.Moore@Sun.COM ehdr->e_machine == EM_AMD64) { 7997656SSherry.Moore@Sun.COM 8007656SSherry.Moore@Sun.COM if (fastboot_elf64_find_dboot_load_offset( 8017656SSherry.Moore@Sun.COM (void *)va, fsize, &dboot_start_offset) 8027656SSherry.Moore@Sun.COM != 0) { 8037656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Couldn't " 8047656SSherry.Moore@Sun.COM "find ELF64 dboot entry offset"); 8057656SSherry.Moore@Sun.COM goto err_out; 8067656SSherry.Moore@Sun.COM } 8077656SSherry.Moore@Sun.COM 8087656SSherry.Moore@Sun.COM if ((x86_feature & X86_64) == 0 || 8097656SSherry.Moore@Sun.COM newkernel.fi_has_pae == 0) { 8107656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Cannot " 8117656SSherry.Moore@Sun.COM "reboot to %s: " 8127656SSherry.Moore@Sun.COM "not a 64-bit capable system", 8137656SSherry.Moore@Sun.COM kern_bootfile); 8147656SSherry.Moore@Sun.COM goto err_out; 8157656SSherry.Moore@Sun.COM } 8167656SSherry.Moore@Sun.COM 8177656SSherry.Moore@Sun.COM bcopy(BOOTARCHIVE64, 8187656SSherry.Moore@Sun.COM &fastboot_filename 8197656SSherry.Moore@Sun.COM [FASTBOOT_NAME_BOOTARCHIVE][bootpath_len], 8207656SSherry.Moore@Sun.COM sizeof (BOOTARCHIVE64)); 8217656SSherry.Moore@Sun.COM } else { 8227656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Unknown ELF type"); 8237656SSherry.Moore@Sun.COM goto err_out; 8247656SSherry.Moore@Sun.COM } 8257656SSherry.Moore@Sun.COM 8267656SSherry.Moore@Sun.COM fb->fb_dest_pa = DBOOT_ENTRY_ADDRESS - 8277656SSherry.Moore@Sun.COM dboot_start_offset; 8287656SSherry.Moore@Sun.COM 8297656SSherry.Moore@Sun.COM fb->fb_next_pa = DBOOT_ENTRY_ADDRESS + fsize_roundup; 8307656SSherry.Moore@Sun.COM } else { 8317656SSherry.Moore@Sun.COM fb->fb_dest_pa = newkernel.fi_files[i - 1].fb_next_pa; 8327656SSherry.Moore@Sun.COM fb->fb_next_pa = fb->fb_dest_pa + fsize_roundup; 8337656SSherry.Moore@Sun.COM } 8347656SSherry.Moore@Sun.COM 8357656SSherry.Moore@Sun.COM kobj_close_file(file); 8367656SSherry.Moore@Sun.COM 8377656SSherry.Moore@Sun.COM } 8387656SSherry.Moore@Sun.COM 839*7750SSherry.Moore@Sun.COM /* 840*7750SSherry.Moore@Sun.COM * Set fb_va to fake_va 841*7750SSherry.Moore@Sun.COM */ 842*7750SSherry.Moore@Sun.COM for (i = 0; i < FASTBOOT_MAX_FILES_MAP; i++) { 843*7750SSherry.Moore@Sun.COM newkernel.fi_files[i].fb_va = fake_va; 844*7750SSherry.Moore@Sun.COM 845*7750SSherry.Moore@Sun.COM } 8467656SSherry.Moore@Sun.COM 8477656SSherry.Moore@Sun.COM /* 8487656SSherry.Moore@Sun.COM * Add the function that will switch us to 32-bit protected mode 8497656SSherry.Moore@Sun.COM */ 8507656SSherry.Moore@Sun.COM fb = &newkernel.fi_files[FASTBOOT_SWTCH]; 8517656SSherry.Moore@Sun.COM fb->fb_va = fb->fb_dest_pa = FASTBOOT_SWTCH_PA; 8527656SSherry.Moore@Sun.COM fb->fb_size = PAGESIZE; 8537656SSherry.Moore@Sun.COM 8547656SSherry.Moore@Sun.COM /* 8557656SSherry.Moore@Sun.COM * Map in FASTBOOT_SWTCH_PA 8567656SSherry.Moore@Sun.COM */ 8577656SSherry.Moore@Sun.COM hat_devload(kas.a_hat, (caddr_t)fb->fb_va, MMU_PAGESIZE, 8587656SSherry.Moore@Sun.COM mmu_btop(fb->fb_dest_pa), 8597656SSherry.Moore@Sun.COM PROT_READ | PROT_WRITE | PROT_EXEC, HAT_LOAD_NOCONSIST); 8607656SSherry.Moore@Sun.COM 8617656SSherry.Moore@Sun.COM bcopy((void *)fb_swtch_image, (void *)fb->fb_va, fb->fb_size); 8627656SSherry.Moore@Sun.COM 8637656SSherry.Moore@Sun.COM /* 8647656SSherry.Moore@Sun.COM * Build the new multiboot_info structure 8657656SSherry.Moore@Sun.COM */ 866*7750SSherry.Moore@Sun.COM if (fastboot_build_mbi(bootargs, &newkernel) != 0) { 8677656SSherry.Moore@Sun.COM goto err_out; 8687656SSherry.Moore@Sun.COM } 8697656SSherry.Moore@Sun.COM 8707656SSherry.Moore@Sun.COM /* 8717656SSherry.Moore@Sun.COM * Build page table for low 1G physical memory. Use big pages. 8727656SSherry.Moore@Sun.COM * Allocate 4 pages for the page tables. 8737656SSherry.Moore@Sun.COM * 1 page for Page-Directory-Pointer Table 8747656SSherry.Moore@Sun.COM * 2 page for Page Directory 8757656SSherry.Moore@Sun.COM * 1 page for Page Table. 8767656SSherry.Moore@Sun.COM * The page table entry will be rewritten to map the physical 8777656SSherry.Moore@Sun.COM * address as we do the copying. 8787656SSherry.Moore@Sun.COM */ 8797656SSherry.Moore@Sun.COM if (newkernel.fi_has_pae) { 8807656SSherry.Moore@Sun.COM size_t size = MMU_PAGESIZE * 4; 8817656SSherry.Moore@Sun.COM 8827656SSherry.Moore@Sun.COM if ((newkernel.fi_pagetable_va = (uintptr_t) 8837656SSherry.Moore@Sun.COM contig_alloc(size, &fastboot_below_1G_dma_attr, 8847656SSherry.Moore@Sun.COM PAGESIZE, 0)) == NULL) { 8857656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, 8867656SSherry.Moore@Sun.COM (uint64_t)size, "1G"); 8877656SSherry.Moore@Sun.COM goto err_out; 8887656SSherry.Moore@Sun.COM } 8897656SSherry.Moore@Sun.COM 8907656SSherry.Moore@Sun.COM bzero((void *)(newkernel.fi_pagetable_va), size); 8917656SSherry.Moore@Sun.COM 8927656SSherry.Moore@Sun.COM newkernel.fi_pagetable_pa = 8937656SSherry.Moore@Sun.COM mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, 8947656SSherry.Moore@Sun.COM (caddr_t)newkernel.fi_pagetable_va)); 8957656SSherry.Moore@Sun.COM 8967656SSherry.Moore@Sun.COM newkernel.fi_last_table_pa = newkernel.fi_pagetable_pa + 8977656SSherry.Moore@Sun.COM MMU_PAGESIZE * 3; 8987656SSherry.Moore@Sun.COM 8997656SSherry.Moore@Sun.COM newkernel.fi_next_table_va = newkernel.fi_pagetable_va + 9007656SSherry.Moore@Sun.COM MMU_PAGESIZE; 9017656SSherry.Moore@Sun.COM newkernel.fi_next_table_pa = newkernel.fi_pagetable_pa + 9027656SSherry.Moore@Sun.COM MMU_PAGESIZE; 9037656SSherry.Moore@Sun.COM 9047656SSherry.Moore@Sun.COM fastboot_build_pagetables(&newkernel); 9057656SSherry.Moore@Sun.COM } 9067656SSherry.Moore@Sun.COM 9077656SSherry.Moore@Sun.COM 9087656SSherry.Moore@Sun.COM /* Mark it as valid */ 9097656SSherry.Moore@Sun.COM newkernel.fi_valid = 1; 9107656SSherry.Moore@Sun.COM newkernel.fi_magic = FASTBOOT_MAGIC; 9117656SSherry.Moore@Sun.COM 9127656SSherry.Moore@Sun.COM return; 9137656SSherry.Moore@Sun.COM 9147656SSherry.Moore@Sun.COM err_out: 9157656SSherry.Moore@Sun.COM newkernel.fi_valid = 0; 9167656SSherry.Moore@Sun.COM } 9177656SSherry.Moore@Sun.COM 918*7750SSherry.Moore@Sun.COM /* 919*7750SSherry.Moore@Sun.COM * Jump to the fast reboot switcher. This function never returns. 920*7750SSherry.Moore@Sun.COM */ 9217656SSherry.Moore@Sun.COM void 9227656SSherry.Moore@Sun.COM fast_reboot() 9237656SSherry.Moore@Sun.COM { 9247656SSherry.Moore@Sun.COM void (*fastboot_func)(fastboot_info_t *); 9257656SSherry.Moore@Sun.COM 9267656SSherry.Moore@Sun.COM fastboot_func = (void (*)())(newkernel.fi_files[FASTBOOT_SWTCH].fb_va); 9277656SSherry.Moore@Sun.COM (*fastboot_func)(&newkernel); 9287656SSherry.Moore@Sun.COM } 929