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 277750SSherry.Moore@Sun.COM /* 287750SSherry.Moore@Sun.COM * This file contains the functions for performing Fast Reboot -- a 297750SSherry.Moore@Sun.COM * reboot which bypasses the firmware and bootloader, considerably 307750SSherry.Moore@Sun.COM * reducing downtime. 317750SSherry.Moore@Sun.COM * 327750SSherry.Moore@Sun.COM * load_kernel(): This function is invoked by mdpreboot() in the reboot 337750SSherry.Moore@Sun.COM * path. It loads the new kernel and boot archive into memory, builds 347750SSherry.Moore@Sun.COM * the data structure containing sufficient information about the new 357750SSherry.Moore@Sun.COM * kernel and boot archive to be passed to the fast reboot switcher 367750SSherry.Moore@Sun.COM * (see fb_swtch_src.s for details). When invoked the switcher relocates 377750SSherry.Moore@Sun.COM * the new kernel and boot archive to physically contiguous low memory, 387750SSherry.Moore@Sun.COM * similar to where the boot loader would have loaded them, and jumps to 397750SSherry.Moore@Sun.COM * the new kernel. 407750SSherry.Moore@Sun.COM * 417750SSherry.Moore@Sun.COM * The physical addresses of the memory allocated for the new kernel, boot 427750SSherry.Moore@Sun.COM * archive and their page tables must be above where the boot archive ends 437750SSherry.Moore@Sun.COM * after it has been relocated by the switcher, otherwise the new files 447750SSherry.Moore@Sun.COM * and their page tables could be overridden during relocation. 457750SSherry.Moore@Sun.COM * 467750SSherry.Moore@Sun.COM * fast_reboot(): This function is invoked by mdboot() once it's determined 477750SSherry.Moore@Sun.COM * that the system is capable of fast reboot. It jumps to the fast reboot 487750SSherry.Moore@Sun.COM * switcher with the data structure built by load_kernel() as the argument. 497750SSherry.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 927750SSherry.Moore@Sun.COM /* 937750SSherry.Moore@Sun.COM * Data structure containing necessary information for the fast reboot 947750SSherry.Moore@Sun.COM * switcher to jump to the new kernel. 957750SSherry.Moore@Sun.COM */ 967656SSherry.Moore@Sun.COM fastboot_info_t newkernel = { 0 }; 977750SSherry.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 */ 134*8151SKonstantin.Ananyev@Sun.COM #ifdef __amd64 135*8151SKonstantin.Ananyev@Sun.COM 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_addr_hi: 2^64B */ 136*8151SKonstantin.Ananyev@Sun.COM #else 1377656SSherry.Moore@Sun.COM 0x0000000FFFFFFFFFULL, /* dma_attr_addr_hi: 64GB */ 138*8151SKonstantin.Ananyev@Sun.COM #endif /* __amd64 */ 1397656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_count_max */ 1407656SSherry.Moore@Sun.COM 0x0000000000001000ULL, /* dma_attr_align: 4KB */ 1417656SSherry.Moore@Sun.COM 1, /* dma_attr_burstsize */ 1427656SSherry.Moore@Sun.COM 1, /* dma_attr_minxfer */ 1437656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_maxxfer */ 1447656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_seg */ 1457656SSherry.Moore@Sun.COM 1, /* dma_attr_sgllen */ 1467656SSherry.Moore@Sun.COM 0x1000ULL, /* dma_attr_granular */ 1477656SSherry.Moore@Sun.COM 0, /* dma_attr_flags */ 1487656SSherry.Moore@Sun.COM }; 1497656SSherry.Moore@Sun.COM 1507656SSherry.Moore@Sun.COM /* 1517656SSherry.Moore@Sun.COM * Various information saved from the previous boot to reconstruct 1527656SSherry.Moore@Sun.COM * multiboot_info. 1537656SSherry.Moore@Sun.COM */ 1547656SSherry.Moore@Sun.COM extern multiboot_info_t saved_mbi; 1557656SSherry.Moore@Sun.COM extern mb_memory_map_t saved_mmap[FASTBOOT_SAVED_MMAP_COUNT]; 1567656SSherry.Moore@Sun.COM extern struct sol_netinfo saved_drives[FASTBOOT_SAVED_DRIVES_COUNT]; 1577656SSherry.Moore@Sun.COM extern char saved_cmdline[FASTBOOT_SAVED_CMDLINE_LEN]; 1587656SSherry.Moore@Sun.COM extern int saved_cmdline_len; 1597656SSherry.Moore@Sun.COM 1607656SSherry.Moore@Sun.COM extern void* contig_alloc(size_t size, ddi_dma_attr_t *attr, 1617656SSherry.Moore@Sun.COM uintptr_t align, int cansleep); 1627750SSherry.Moore@Sun.COM extern void contig_free(void *addr, size_t size); 1637750SSherry.Moore@Sun.COM 1647656SSherry.Moore@Sun.COM 1657656SSherry.Moore@Sun.COM /* PRINTLIKE */ 1667656SSherry.Moore@Sun.COM extern void vprintf(const char *, va_list); 1677656SSherry.Moore@Sun.COM 1687656SSherry.Moore@Sun.COM 1697656SSherry.Moore@Sun.COM /* 1707656SSherry.Moore@Sun.COM * Need to be able to get boot_archives from other places 1717656SSherry.Moore@Sun.COM */ 1727656SSherry.Moore@Sun.COM #define BOOTARCHIVE64 "/platform/i86pc/amd64/boot_archive" 1737656SSherry.Moore@Sun.COM #define BOOTARCHIVE32 "/platform/i86pc/boot_archive" 1747656SSherry.Moore@Sun.COM #define BOOTARCHIVE_FAILSAFE "/boot/x86.miniroot-safe" 1757656SSherry.Moore@Sun.COM #define FAILSAFE_BOOTFILE "/boot/platform/i86pc/kernel/unix" 1767656SSherry.Moore@Sun.COM 1777656SSherry.Moore@Sun.COM static uint_t fastboot_vatoindex(fastboot_info_t *, uintptr_t, int); 1787656SSherry.Moore@Sun.COM static void fastboot_map_with_size(fastboot_info_t *, uintptr_t, 1797656SSherry.Moore@Sun.COM paddr_t, size_t, int); 1807656SSherry.Moore@Sun.COM static void fastboot_build_pagetables(fastboot_info_t *); 1817656SSherry.Moore@Sun.COM static int fastboot_build_mbi(char *, fastboot_info_t *); 1827656SSherry.Moore@Sun.COM 1837656SSherry.Moore@Sun.COM static const char fastboot_enomem_msg[] = "Fastboot: Couldn't allocate 0x%" 1847656SSherry.Moore@Sun.COM PRIx64" bytes below %s to do fast reboot"; 1857656SSherry.Moore@Sun.COM 1867656SSherry.Moore@Sun.COM static void 1877656SSherry.Moore@Sun.COM dprintf(char *fmt, ...) 1887656SSherry.Moore@Sun.COM { 1897656SSherry.Moore@Sun.COM va_list adx; 1907656SSherry.Moore@Sun.COM 1917656SSherry.Moore@Sun.COM if (!fastboot_debug) 1927656SSherry.Moore@Sun.COM return; 1937656SSherry.Moore@Sun.COM 1947656SSherry.Moore@Sun.COM va_start(adx, fmt); 1957656SSherry.Moore@Sun.COM vprintf(fmt, adx); 1967656SSherry.Moore@Sun.COM va_end(adx); 1977656SSherry.Moore@Sun.COM } 1987656SSherry.Moore@Sun.COM 1997656SSherry.Moore@Sun.COM 2007656SSherry.Moore@Sun.COM /* 2017656SSherry.Moore@Sun.COM * Return the index corresponding to a virt address at a given page table level. 2027656SSherry.Moore@Sun.COM */ 2037656SSherry.Moore@Sun.COM static uint_t 2047656SSherry.Moore@Sun.COM fastboot_vatoindex(fastboot_info_t *nk, uintptr_t va, int level) 2057656SSherry.Moore@Sun.COM { 2067656SSherry.Moore@Sun.COM return ((va >> nk->fi_shift_amt[level]) & (nk->fi_ptes_per_table - 1)); 2077656SSherry.Moore@Sun.COM } 2087656SSherry.Moore@Sun.COM 2097656SSherry.Moore@Sun.COM 2107656SSherry.Moore@Sun.COM /* 2117656SSherry.Moore@Sun.COM * Add mapping from vstart to pstart for the specified size. 212*8151SKonstantin.Ananyev@Sun.COM * vstart, pstart and size should all have been aligned at 2M boundaries. 2137656SSherry.Moore@Sun.COM */ 2147656SSherry.Moore@Sun.COM static void 2157656SSherry.Moore@Sun.COM fastboot_map_with_size(fastboot_info_t *nk, uintptr_t vstart, paddr_t pstart, 2167656SSherry.Moore@Sun.COM size_t size, int level) 2177656SSherry.Moore@Sun.COM { 2187656SSherry.Moore@Sun.COM x86pte_t pteval, *table; 2197656SSherry.Moore@Sun.COM uintptr_t vaddr; 2207656SSherry.Moore@Sun.COM paddr_t paddr; 2217656SSherry.Moore@Sun.COM int index, l; 2227656SSherry.Moore@Sun.COM 2237656SSherry.Moore@Sun.COM table = (x86pte_t *)(nk->fi_pagetable_va); 2247656SSherry.Moore@Sun.COM 2257656SSherry.Moore@Sun.COM for (l = nk->fi_top_level; l >= level; l--) { 2267656SSherry.Moore@Sun.COM 2277656SSherry.Moore@Sun.COM index = fastboot_vatoindex(nk, vstart, l); 2287656SSherry.Moore@Sun.COM 2297656SSherry.Moore@Sun.COM if (l == level) { 2307656SSherry.Moore@Sun.COM /* 2317656SSherry.Moore@Sun.COM * Last level. Program the page table entries. 2327656SSherry.Moore@Sun.COM */ 2337656SSherry.Moore@Sun.COM for (vaddr = vstart, paddr = pstart; 2347656SSherry.Moore@Sun.COM vaddr < vstart + size; 2357656SSherry.Moore@Sun.COM vaddr += (1ULL << nk->fi_shift_amt[l]), 2367656SSherry.Moore@Sun.COM paddr += (1ULL << nk->fi_shift_amt[l])) { 2377656SSherry.Moore@Sun.COM 2387656SSherry.Moore@Sun.COM uint_t index = fastboot_vatoindex(nk, vaddr, l); 2397656SSherry.Moore@Sun.COM 2407656SSherry.Moore@Sun.COM if (l > 0) 2417656SSherry.Moore@Sun.COM pteval = paddr | pte_bits | PT_PAGESIZE; 2427656SSherry.Moore@Sun.COM else 2437656SSherry.Moore@Sun.COM pteval = paddr | pte_bits; 2447656SSherry.Moore@Sun.COM 2457656SSherry.Moore@Sun.COM table[index] = pteval; 2467656SSherry.Moore@Sun.COM } 2477656SSherry.Moore@Sun.COM } else if (table[index] & PT_VALID) { 2487656SSherry.Moore@Sun.COM 2497656SSherry.Moore@Sun.COM table = (x86pte_t *) 2507656SSherry.Moore@Sun.COM ((uintptr_t)(((paddr_t)table[index] & MMU_PAGEMASK) 2517656SSherry.Moore@Sun.COM - nk->fi_pagetable_pa) + nk->fi_pagetable_va); 2527656SSherry.Moore@Sun.COM } else { 2537656SSherry.Moore@Sun.COM /* 254*8151SKonstantin.Ananyev@Sun.COM * Intermediate levels. 255*8151SKonstantin.Ananyev@Sun.COM * Program with either valid bit or PTP bits. 2567656SSherry.Moore@Sun.COM */ 2577656SSherry.Moore@Sun.COM if (l == nk->fi_top_level) { 258*8151SKonstantin.Ananyev@Sun.COM #ifdef __amd64 259*8151SKonstantin.Ananyev@Sun.COM ASSERT(nk->fi_top_level == 3); 260*8151SKonstantin.Ananyev@Sun.COM table[index] = nk->fi_next_table_pa | ptp_bits; 261*8151SKonstantin.Ananyev@Sun.COM #else 2627656SSherry.Moore@Sun.COM table[index] = nk->fi_next_table_pa | PT_VALID; 263*8151SKonstantin.Ananyev@Sun.COM #endif /* __amd64 */ 2647656SSherry.Moore@Sun.COM } else { 2657656SSherry.Moore@Sun.COM table[index] = nk->fi_next_table_pa | ptp_bits; 2667656SSherry.Moore@Sun.COM } 2677656SSherry.Moore@Sun.COM table = (x86pte_t *)(nk->fi_next_table_va); 2687656SSherry.Moore@Sun.COM nk->fi_next_table_va += MMU_PAGESIZE; 2697656SSherry.Moore@Sun.COM nk->fi_next_table_pa += MMU_PAGESIZE; 2707656SSherry.Moore@Sun.COM } 2717656SSherry.Moore@Sun.COM } 2727656SSherry.Moore@Sun.COM } 2737656SSherry.Moore@Sun.COM 2747656SSherry.Moore@Sun.COM /* 2757656SSherry.Moore@Sun.COM * Build page tables for the lower 1G of physical memory using 2M 2767656SSherry.Moore@Sun.COM * pages, and prepare page tables for mapping new kernel and boot 2777656SSherry.Moore@Sun.COM * archive pages using 4K pages. 2787656SSherry.Moore@Sun.COM */ 2797656SSherry.Moore@Sun.COM static void 2807656SSherry.Moore@Sun.COM fastboot_build_pagetables(fastboot_info_t *nk) 2817656SSherry.Moore@Sun.COM { 2827656SSherry.Moore@Sun.COM /* 2837656SSherry.Moore@Sun.COM * Map lower 1G physical memory. Use large pages. 2847656SSherry.Moore@Sun.COM */ 2857656SSherry.Moore@Sun.COM fastboot_map_with_size(nk, 0, 0, ONE_GIG, 1); 2867656SSherry.Moore@Sun.COM 2877656SSherry.Moore@Sun.COM /* 2887656SSherry.Moore@Sun.COM * Map one 4K page to get the middle page tables set up. 2897656SSherry.Moore@Sun.COM */ 2907656SSherry.Moore@Sun.COM fake_va = P2ALIGN_TYPED(fake_va, nk->fi_lpagesize, uintptr_t); 2917656SSherry.Moore@Sun.COM fastboot_map_with_size(nk, fake_va, 2927656SSherry.Moore@Sun.COM nk->fi_files[0].fb_pte_list_va[0] & MMU_PAGEMASK, PAGESIZE, 0); 2937656SSherry.Moore@Sun.COM } 2947656SSherry.Moore@Sun.COM 2957656SSherry.Moore@Sun.COM 2967656SSherry.Moore@Sun.COM /* 2977656SSherry.Moore@Sun.COM * Sanity check. Look for dboot offset. 2987656SSherry.Moore@Sun.COM */ 2997656SSherry.Moore@Sun.COM static int 3007656SSherry.Moore@Sun.COM fastboot_elf64_find_dboot_load_offset(void *img, off_t imgsz, uint32_t *offp) 3017656SSherry.Moore@Sun.COM { 3027656SSherry.Moore@Sun.COM Elf64_Ehdr *ehdr = (Elf64_Ehdr *)img; 3037656SSherry.Moore@Sun.COM Elf64_Phdr *phdr; 3047656SSherry.Moore@Sun.COM uint8_t *phdrbase; 3057656SSherry.Moore@Sun.COM int i; 3067656SSherry.Moore@Sun.COM 3077656SSherry.Moore@Sun.COM if ((ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize) >= imgsz) 3087656SSherry.Moore@Sun.COM return (-1); 3097656SSherry.Moore@Sun.COM 3107656SSherry.Moore@Sun.COM phdrbase = (uint8_t *)img + ehdr->e_phoff; 3117656SSherry.Moore@Sun.COM 3127656SSherry.Moore@Sun.COM for (i = 0; i < ehdr->e_phnum; i++) { 3137656SSherry.Moore@Sun.COM phdr = (Elf64_Phdr *)(phdrbase + ehdr->e_phentsize * i); 3147656SSherry.Moore@Sun.COM 3157656SSherry.Moore@Sun.COM if (phdr->p_type == PT_LOAD) { 3167656SSherry.Moore@Sun.COM if (phdr->p_vaddr == phdr->p_paddr && 3177656SSherry.Moore@Sun.COM phdr->p_vaddr == DBOOT_ENTRY_ADDRESS) { 3187656SSherry.Moore@Sun.COM ASSERT(phdr->p_offset <= UINT32_MAX); 3197656SSherry.Moore@Sun.COM *offp = (uint32_t)phdr->p_offset; 3207656SSherry.Moore@Sun.COM return (0); 3217656SSherry.Moore@Sun.COM } 3227656SSherry.Moore@Sun.COM } 3237656SSherry.Moore@Sun.COM } 3247656SSherry.Moore@Sun.COM 3257656SSherry.Moore@Sun.COM return (-1); 3267656SSherry.Moore@Sun.COM } 3277656SSherry.Moore@Sun.COM 3287656SSherry.Moore@Sun.COM 3297656SSherry.Moore@Sun.COM /* 3307656SSherry.Moore@Sun.COM * Initialize text and data section information for 32-bit kernel. 331*8151SKonstantin.Ananyev@Sun.COM * sectcntp - is both input/output parameter. 332*8151SKonstantin.Ananyev@Sun.COM * On entry, *sectcntp contains maximum allowable number of sections; 333*8151SKonstantin.Ananyev@Sun.COM * on return, it contains the actual number of sections filled. 3347656SSherry.Moore@Sun.COM */ 3357656SSherry.Moore@Sun.COM static int 3367656SSherry.Moore@Sun.COM fastboot_elf32_find_loadables(void *img, off_t imgsz, fastboot_section_t *sectp, 3377656SSherry.Moore@Sun.COM int *sectcntp, uint32_t *offp) 3387656SSherry.Moore@Sun.COM { 3397656SSherry.Moore@Sun.COM Elf32_Ehdr *ehdr = (Elf32_Ehdr *)img; 3407656SSherry.Moore@Sun.COM Elf32_Phdr *phdr; 3417656SSherry.Moore@Sun.COM uint8_t *phdrbase; 3427656SSherry.Moore@Sun.COM int i; 3437656SSherry.Moore@Sun.COM int used_sections = 0; 344*8151SKonstantin.Ananyev@Sun.COM const int max_sectcnt = *sectcntp; 3457656SSherry.Moore@Sun.COM 3467656SSherry.Moore@Sun.COM if ((ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize) >= imgsz) 3477656SSherry.Moore@Sun.COM return (-1); 3487656SSherry.Moore@Sun.COM 3497656SSherry.Moore@Sun.COM phdrbase = (uint8_t *)img + ehdr->e_phoff; 3507656SSherry.Moore@Sun.COM 3517656SSherry.Moore@Sun.COM for (i = 0; i < ehdr->e_phnum; i++) { 3527656SSherry.Moore@Sun.COM phdr = (Elf32_Phdr *)(phdrbase + ehdr->e_phentsize * i); 3537656SSherry.Moore@Sun.COM 3547656SSherry.Moore@Sun.COM if (phdr->p_type == PT_INTERP) 3557656SSherry.Moore@Sun.COM return (-1); 3567656SSherry.Moore@Sun.COM 3577656SSherry.Moore@Sun.COM if (phdr->p_type != PT_LOAD) 3587656SSherry.Moore@Sun.COM continue; 3597656SSherry.Moore@Sun.COM 3607656SSherry.Moore@Sun.COM if (phdr->p_vaddr == phdr->p_paddr && 3617656SSherry.Moore@Sun.COM phdr->p_paddr == DBOOT_ENTRY_ADDRESS) { 3627656SSherry.Moore@Sun.COM *offp = (uint32_t)phdr->p_offset; 3637656SSherry.Moore@Sun.COM } else { 364*8151SKonstantin.Ananyev@Sun.COM if (max_sectcnt <= used_sections) 365*8151SKonstantin.Ananyev@Sun.COM return (-1); 366*8151SKonstantin.Ananyev@Sun.COM 3677656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_offset = phdr->p_offset; 3687656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_paddr = phdr->p_paddr; 3697656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_size = phdr->p_filesz; 3707656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_bss_size = 3717656SSherry.Moore@Sun.COM (phdr->p_filesz < phdr->p_memsz) ? 3727656SSherry.Moore@Sun.COM (phdr->p_memsz - phdr->p_filesz) : 0; 3737656SSherry.Moore@Sun.COM 374*8151SKonstantin.Ananyev@Sun.COM /* Extra sanity check for the input object file */ 375*8151SKonstantin.Ananyev@Sun.COM if (sectp[used_sections].fb_sec_paddr + 376*8151SKonstantin.Ananyev@Sun.COM sectp[used_sections].fb_sec_size + 377*8151SKonstantin.Ananyev@Sun.COM sectp[used_sections].fb_sec_bss_size >= 378*8151SKonstantin.Ananyev@Sun.COM DBOOT_ENTRY_ADDRESS) 379*8151SKonstantin.Ananyev@Sun.COM return (-1); 380*8151SKonstantin.Ananyev@Sun.COM 3817656SSherry.Moore@Sun.COM used_sections++; 3827656SSherry.Moore@Sun.COM } 3837656SSherry.Moore@Sun.COM } 3847656SSherry.Moore@Sun.COM 3857656SSherry.Moore@Sun.COM *sectcntp = used_sections; 3867656SSherry.Moore@Sun.COM return (0); 3877656SSherry.Moore@Sun.COM } 3887656SSherry.Moore@Sun.COM 3897656SSherry.Moore@Sun.COM /* 3907656SSherry.Moore@Sun.COM * Create multiboot info structure 3917656SSherry.Moore@Sun.COM */ 3927656SSherry.Moore@Sun.COM static int 3937656SSherry.Moore@Sun.COM fastboot_build_mbi(char *mdep, fastboot_info_t *nk) 3947656SSherry.Moore@Sun.COM { 3957656SSherry.Moore@Sun.COM mb_module_t *mbp; 3967656SSherry.Moore@Sun.COM uintptr_t next_addr; 3977656SSherry.Moore@Sun.COM uintptr_t new_mbi_pa; 3987656SSherry.Moore@Sun.COM size_t size; 3997656SSherry.Moore@Sun.COM void *buf = NULL; 4007656SSherry.Moore@Sun.COM size_t arglen; 4017656SSherry.Moore@Sun.COM char bootargs[OBP_MAXPATHLEN]; 4027656SSherry.Moore@Sun.COM 4037656SSherry.Moore@Sun.COM bzero(bootargs, OBP_MAXPATHLEN); 4047656SSherry.Moore@Sun.COM 4057750SSherry.Moore@Sun.COM if (mdep != NULL && strlen(mdep) != 0) { 4067656SSherry.Moore@Sun.COM arglen = strlen(mdep) + 1; 4077656SSherry.Moore@Sun.COM } else { 4087656SSherry.Moore@Sun.COM arglen = saved_cmdline_len; 4097656SSherry.Moore@Sun.COM } 4107656SSherry.Moore@Sun.COM 4117656SSherry.Moore@Sun.COM size = PAGESIZE + P2ROUNDUP(arglen, PAGESIZE); 4127656SSherry.Moore@Sun.COM buf = contig_alloc(size, &fastboot_below_1G_dma_attr, PAGESIZE, 0); 4137656SSherry.Moore@Sun.COM if (buf == NULL) { 4147656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, (uint64_t)size, "1G"); 4157656SSherry.Moore@Sun.COM return (-1); 4167656SSherry.Moore@Sun.COM } 4177656SSherry.Moore@Sun.COM 4187656SSherry.Moore@Sun.COM bzero(buf, size); 4197656SSherry.Moore@Sun.COM 4207656SSherry.Moore@Sun.COM new_mbi_pa = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, (caddr_t)buf)); 4217656SSherry.Moore@Sun.COM 4227656SSherry.Moore@Sun.COM hat_devload(kas.a_hat, (caddr_t)new_mbi_pa, size, 4237656SSherry.Moore@Sun.COM mmu_btop(new_mbi_pa), PROT_READ | PROT_WRITE, HAT_LOAD_NOCONSIST); 4247656SSherry.Moore@Sun.COM 4257656SSherry.Moore@Sun.COM nk->fi_new_mbi_pa = (paddr_t)new_mbi_pa; 4267656SSherry.Moore@Sun.COM 4277656SSherry.Moore@Sun.COM bcopy(&saved_mbi, (void *)new_mbi_pa, sizeof (multiboot_info_t)); 4287656SSherry.Moore@Sun.COM 4297656SSherry.Moore@Sun.COM next_addr = new_mbi_pa + sizeof (multiboot_info_t); 4307656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->mods_addr = next_addr; 4317656SSherry.Moore@Sun.COM mbp = (mb_module_t *)(uintptr_t)next_addr; 4327656SSherry.Moore@Sun.COM mbp->mod_start = newkernel.fi_files[FASTBOOT_BOOTARCHIVE].fb_dest_pa; 4337656SSherry.Moore@Sun.COM mbp->mod_end = newkernel.fi_files[FASTBOOT_BOOTARCHIVE].fb_next_pa; 4347656SSherry.Moore@Sun.COM 4357656SSherry.Moore@Sun.COM next_addr += sizeof (mb_module_t); 4367656SSherry.Moore@Sun.COM bcopy(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE], (void *)next_addr, 4377656SSherry.Moore@Sun.COM strlen(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE])); 4387656SSherry.Moore@Sun.COM 4397656SSherry.Moore@Sun.COM mbp->mod_name = next_addr; 4407656SSherry.Moore@Sun.COM mbp->reserved = 0; 4417656SSherry.Moore@Sun.COM next_addr += strlen(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE]); 4427656SSherry.Moore@Sun.COM *(char *)next_addr = '\0'; 4437656SSherry.Moore@Sun.COM next_addr++; 4447656SSherry.Moore@Sun.COM next_addr = P2ROUNDUP_TYPED(next_addr, 16, uintptr_t); 4457656SSherry.Moore@Sun.COM 4467656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->mmap_addr = next_addr; 4477656SSherry.Moore@Sun.COM bcopy((void *)(uintptr_t)saved_mmap, (void *)next_addr, 4487656SSherry.Moore@Sun.COM saved_mbi.mmap_length); 4497656SSherry.Moore@Sun.COM next_addr += saved_mbi.mmap_length; 4507656SSherry.Moore@Sun.COM 4517656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->drives_addr = next_addr; 4527656SSherry.Moore@Sun.COM bcopy((void *)(uintptr_t)saved_drives, (void *)next_addr, 4537656SSherry.Moore@Sun.COM saved_mbi.drives_length); 4547656SSherry.Moore@Sun.COM next_addr += saved_mbi.drives_length; 4557656SSherry.Moore@Sun.COM 4567656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->cmdline = next_addr; 4577656SSherry.Moore@Sun.COM 4587750SSherry.Moore@Sun.COM if (mdep != NULL && strlen(mdep) != 0) { 4597656SSherry.Moore@Sun.COM bcopy(mdep, (void *)(uintptr_t) 4607656SSherry.Moore@Sun.COM (((multiboot_info_t *)new_mbi_pa)->cmdline), (arglen - 1)); 4617656SSherry.Moore@Sun.COM } else { 4627656SSherry.Moore@Sun.COM bcopy((void *)saved_cmdline, (void *)next_addr, (arglen - 1)); 4637656SSherry.Moore@Sun.COM } 4647656SSherry.Moore@Sun.COM /* Terminate the string */ 4657656SSherry.Moore@Sun.COM ((char *)(intptr_t)next_addr)[arglen - 1] = '\0'; 4667656SSherry.Moore@Sun.COM 4677656SSherry.Moore@Sun.COM return (0); 4687656SSherry.Moore@Sun.COM } 4697656SSherry.Moore@Sun.COM 4707750SSherry.Moore@Sun.COM /* 4717750SSherry.Moore@Sun.COM * Initialize HAT related fields 4727750SSherry.Moore@Sun.COM */ 4737750SSherry.Moore@Sun.COM static void 4747750SSherry.Moore@Sun.COM fastboot_init_fields(fastboot_info_t *nk) 4757656SSherry.Moore@Sun.COM { 4767750SSherry.Moore@Sun.COM if (x86_feature & X86_PAE) { 4777750SSherry.Moore@Sun.COM nk->fi_has_pae = 1; 4787750SSherry.Moore@Sun.COM nk->fi_shift_amt = fastboot_shift_amt_pae; 4797750SSherry.Moore@Sun.COM nk->fi_ptes_per_table = 512; 4807750SSherry.Moore@Sun.COM nk->fi_lpagesize = (2 << 20); /* 2M */ 481*8151SKonstantin.Ananyev@Sun.COM #ifdef __amd64 482*8151SKonstantin.Ananyev@Sun.COM nk->fi_top_level = 3; 483*8151SKonstantin.Ananyev@Sun.COM #else 4847750SSherry.Moore@Sun.COM nk->fi_top_level = 2; 485*8151SKonstantin.Ananyev@Sun.COM #endif /* __amd64 */ 4867750SSherry.Moore@Sun.COM } 4877750SSherry.Moore@Sun.COM } 4887656SSherry.Moore@Sun.COM 4897750SSherry.Moore@Sun.COM /* 4907750SSherry.Moore@Sun.COM * Process boot argument 4917750SSherry.Moore@Sun.COM */ 4927750SSherry.Moore@Sun.COM static void 4937750SSherry.Moore@Sun.COM fastboot_parse_mdep(char *mdep, char *kern_bootpath, int *bootpath_len, 4947750SSherry.Moore@Sun.COM char *bootargs) 4957750SSherry.Moore@Sun.COM { 4967750SSherry.Moore@Sun.COM int i; 4977656SSherry.Moore@Sun.COM 4987656SSherry.Moore@Sun.COM /* 4997656SSherry.Moore@Sun.COM * If mdep is not NULL, it comes in the format of 5007656SSherry.Moore@Sun.COM * mountpoint unix args 5017656SSherry.Moore@Sun.COM */ 5027750SSherry.Moore@Sun.COM if (mdep != NULL && strlen(mdep) != 0) { 5037656SSherry.Moore@Sun.COM if (mdep[0] != '-') { 5047656SSherry.Moore@Sun.COM /* First get the root argument */ 5057656SSherry.Moore@Sun.COM i = 0; 5067656SSherry.Moore@Sun.COM while (mdep[i] != '\0' && mdep[i] != ' ') { 5077656SSherry.Moore@Sun.COM i++; 5087656SSherry.Moore@Sun.COM } 5097656SSherry.Moore@Sun.COM 5107656SSherry.Moore@Sun.COM if (i < 4 || strncmp(&mdep[i-4], "unix", 4) != 0) { 5117656SSherry.Moore@Sun.COM /* mount point */ 5127656SSherry.Moore@Sun.COM bcopy(mdep, kern_bootpath, i); 5137656SSherry.Moore@Sun.COM kern_bootpath[i] = '\0'; 5147750SSherry.Moore@Sun.COM *bootpath_len = i; 5157656SSherry.Moore@Sun.COM 5167656SSherry.Moore@Sun.COM /* 5177656SSherry.Moore@Sun.COM * Get the next argument. It should be unix as 5187656SSherry.Moore@Sun.COM * we have validated in in halt.c. 5197656SSherry.Moore@Sun.COM */ 5207656SSherry.Moore@Sun.COM if (strlen(mdep) > i) { 5217656SSherry.Moore@Sun.COM mdep += (i + 1); 5227656SSherry.Moore@Sun.COM i = 0; 5237656SSherry.Moore@Sun.COM while (mdep[i] != '\0' && 5247656SSherry.Moore@Sun.COM mdep[i] != ' ') { 5257656SSherry.Moore@Sun.COM i++; 5267656SSherry.Moore@Sun.COM } 5277656SSherry.Moore@Sun.COM } 5287656SSherry.Moore@Sun.COM 5297656SSherry.Moore@Sun.COM } 5307656SSherry.Moore@Sun.COM bcopy(mdep, kern_bootfile, i); 5317656SSherry.Moore@Sun.COM kern_bootfile[i] = '\0'; 5327750SSherry.Moore@Sun.COM bcopy(mdep, bootargs, strlen(mdep)); 5337656SSherry.Moore@Sun.COM } else { 5347656SSherry.Moore@Sun.COM int off = strlen(kern_bootfile); 5357656SSherry.Moore@Sun.COM bcopy(kern_bootfile, bootargs, off); 5367656SSherry.Moore@Sun.COM bcopy(" ", &bootargs[off++], 1); 5377656SSherry.Moore@Sun.COM bcopy(mdep, &bootargs[off], strlen(mdep)); 5387656SSherry.Moore@Sun.COM off += strlen(mdep); 5397656SSherry.Moore@Sun.COM bootargs[off] = '\0'; 5407656SSherry.Moore@Sun.COM } 5417656SSherry.Moore@Sun.COM } 5427750SSherry.Moore@Sun.COM } 5437750SSherry.Moore@Sun.COM 5447750SSherry.Moore@Sun.COM /* 5457750SSherry.Moore@Sun.COM * Free up the memory we have allocated for this file 5467750SSherry.Moore@Sun.COM */ 5477750SSherry.Moore@Sun.COM static void 5487750SSherry.Moore@Sun.COM fastboot_free_file(fastboot_file_t *fb) 5497750SSherry.Moore@Sun.COM { 5507750SSherry.Moore@Sun.COM size_t fsize_roundup, pt_size; 5517750SSherry.Moore@Sun.COM int pt_entry_count; 5527750SSherry.Moore@Sun.COM 5537750SSherry.Moore@Sun.COM fsize_roundup = P2ROUNDUP_TYPED(fb->fb_size, PAGESIZE, size_t); 5547750SSherry.Moore@Sun.COM contig_free((void *)fb->fb_va, fsize_roundup); 5557750SSherry.Moore@Sun.COM 5567750SSherry.Moore@Sun.COM pt_entry_count = (fsize_roundup >> PAGESHIFT) + 1; 5577750SSherry.Moore@Sun.COM pt_size = P2ROUNDUP(pt_entry_count * 8, PAGESIZE); 5587750SSherry.Moore@Sun.COM contig_free((void *)fb->fb_pte_list_va, pt_size); 5597750SSherry.Moore@Sun.COM } 5607750SSherry.Moore@Sun.COM 5617750SSherry.Moore@Sun.COM /* 5627750SSherry.Moore@Sun.COM * This function performs the following tasks: 5637750SSherry.Moore@Sun.COM * - Read the sizes of the new kernel and boot archive. 5647750SSherry.Moore@Sun.COM * - Allocate memory for the new kernel and boot archive. 5657750SSherry.Moore@Sun.COM * - Allocate memory for page tables necessary for mapping the memory 5667750SSherry.Moore@Sun.COM * allocated for the files. 5677750SSherry.Moore@Sun.COM * - Read the new kernel and boot archive into memory. 5687750SSherry.Moore@Sun.COM * - Map in the fast reboot switcher. 5697750SSherry.Moore@Sun.COM * - Load the fast reboot switcher to FASTBOOT_SWTCH_PA. 5707750SSherry.Moore@Sun.COM * - Build the new multiboot_info structure 5717750SSherry.Moore@Sun.COM * - Build page tables for the low 1G of physical memory. 5727750SSherry.Moore@Sun.COM * - Mark the data structure as valid if all steps have succeeded. 5737750SSherry.Moore@Sun.COM */ 5747750SSherry.Moore@Sun.COM void 5757750SSherry.Moore@Sun.COM load_kernel(char *mdep) 5767750SSherry.Moore@Sun.COM { 5777750SSherry.Moore@Sun.COM void *buf = NULL; 5787750SSherry.Moore@Sun.COM int i; 5797750SSherry.Moore@Sun.COM fastboot_file_t *fb; 5807750SSherry.Moore@Sun.COM uint32_t dboot_start_offset; 5817750SSherry.Moore@Sun.COM char kern_bootpath[OBP_MAXPATHLEN]; 5827750SSherry.Moore@Sun.COM char bootargs[OBP_MAXPATHLEN]; 5837750SSherry.Moore@Sun.COM extern uintptr_t postbootkernelbase; 5847750SSherry.Moore@Sun.COM extern char fb_swtch_image[]; 5857750SSherry.Moore@Sun.COM int bootpath_len = 0; 5867750SSherry.Moore@Sun.COM int is_failsafe = 0; 5877750SSherry.Moore@Sun.COM int is_retry = 0; 5887750SSherry.Moore@Sun.COM uint64_t end_addr; 5897750SSherry.Moore@Sun.COM 5907750SSherry.Moore@Sun.COM ASSERT(fastreboot_capable); 5917750SSherry.Moore@Sun.COM 5927750SSherry.Moore@Sun.COM postbootkernelbase = 0; 5937750SSherry.Moore@Sun.COM 5947750SSherry.Moore@Sun.COM /* 5957750SSherry.Moore@Sun.COM * Initialize various HAT related fields in the data structure 5967750SSherry.Moore@Sun.COM */ 5977750SSherry.Moore@Sun.COM fastboot_init_fields(&newkernel); 5987750SSherry.Moore@Sun.COM 5997750SSherry.Moore@Sun.COM bzero(kern_bootpath, OBP_MAXPATHLEN); 6007750SSherry.Moore@Sun.COM 6017750SSherry.Moore@Sun.COM /* 6027750SSherry.Moore@Sun.COM * Process the boot argument 6037750SSherry.Moore@Sun.COM */ 6047750SSherry.Moore@Sun.COM bzero(bootargs, OBP_MAXPATHLEN); 6057750SSherry.Moore@Sun.COM fastboot_parse_mdep(mdep, kern_bootpath, &bootpath_len, bootargs); 6067656SSherry.Moore@Sun.COM 6077656SSherry.Moore@Sun.COM /* 6087656SSherry.Moore@Sun.COM * Make sure we get the null character 6097656SSherry.Moore@Sun.COM */ 6107656SSherry.Moore@Sun.COM bcopy(kern_bootpath, fastboot_filename[FASTBOOT_NAME_UNIX], 6117656SSherry.Moore@Sun.COM bootpath_len); 6127656SSherry.Moore@Sun.COM bcopy(kern_bootfile, 6137656SSherry.Moore@Sun.COM &fastboot_filename[FASTBOOT_NAME_UNIX][bootpath_len], 6147656SSherry.Moore@Sun.COM strlen(kern_bootfile) + 1); 6157656SSherry.Moore@Sun.COM 6167656SSherry.Moore@Sun.COM bcopy(kern_bootpath, fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE], 6177656SSherry.Moore@Sun.COM bootpath_len); 6187656SSherry.Moore@Sun.COM 6197656SSherry.Moore@Sun.COM if (bcmp(kern_bootfile, FAILSAFE_BOOTFILE, 6207656SSherry.Moore@Sun.COM (sizeof (FAILSAFE_BOOTFILE) - 1)) == 0) { 6217656SSherry.Moore@Sun.COM is_failsafe = 1; 6227656SSherry.Moore@Sun.COM } 6237656SSherry.Moore@Sun.COM 6247750SSherry.Moore@Sun.COM load_kernel_retry: 6257656SSherry.Moore@Sun.COM /* 6267656SSherry.Moore@Sun.COM * Read in unix and boot_archive 6277656SSherry.Moore@Sun.COM */ 6287750SSherry.Moore@Sun.COM end_addr = DBOOT_ENTRY_ADDRESS; 6297656SSherry.Moore@Sun.COM for (i = 0; i < FASTBOOT_MAX_FILES_MAP; i++) { 6307750SSherry.Moore@Sun.COM struct _buf *file; 6317750SSherry.Moore@Sun.COM uintptr_t va; 6327750SSherry.Moore@Sun.COM uint64_t fsize; 6337750SSherry.Moore@Sun.COM size_t fsize_roundup, pt_size; 6347750SSherry.Moore@Sun.COM int page_index; 6357750SSherry.Moore@Sun.COM uintptr_t offset; 6367750SSherry.Moore@Sun.COM int pt_entry_count; 6377656SSherry.Moore@Sun.COM ddi_dma_attr_t dma_attr = fastboot_dma_attr; 6387656SSherry.Moore@Sun.COM 6397750SSherry.Moore@Sun.COM 6407656SSherry.Moore@Sun.COM dprintf("fastboot_filename[%d] = %s\n", 6417656SSherry.Moore@Sun.COM i, fastboot_filename[i]); 6427656SSherry.Moore@Sun.COM 6437656SSherry.Moore@Sun.COM if ((file = kobj_open_file(fastboot_filename[i])) == 6447656SSherry.Moore@Sun.COM (struct _buf *)-1) { 6457656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Couldn't open %s", 6467656SSherry.Moore@Sun.COM fastboot_filename[i]); 6477656SSherry.Moore@Sun.COM goto err_out; 6487656SSherry.Moore@Sun.COM } 6497656SSherry.Moore@Sun.COM 6507656SSherry.Moore@Sun.COM if (kobj_get_filesize(file, &fsize) != 0) { 6517656SSherry.Moore@Sun.COM cmn_err(CE_WARN, 6527656SSherry.Moore@Sun.COM "Fastboot: Couldn't get filesize for %s", 6537656SSherry.Moore@Sun.COM fastboot_filename[i]); 6547656SSherry.Moore@Sun.COM goto err_out; 6557656SSherry.Moore@Sun.COM } 6567656SSherry.Moore@Sun.COM 6577750SSherry.Moore@Sun.COM fsize_roundup = P2ROUNDUP_TYPED(fsize, PAGESIZE, size_t); 6587750SSherry.Moore@Sun.COM 6597750SSherry.Moore@Sun.COM /* 6607750SSherry.Moore@Sun.COM * Where the files end in physical memory after being 6617750SSherry.Moore@Sun.COM * relocated by the fast boot switcher. 6627750SSherry.Moore@Sun.COM */ 6637750SSherry.Moore@Sun.COM end_addr += fsize_roundup; 6647750SSherry.Moore@Sun.COM if (end_addr > fastboot_below_1G_dma_attr.dma_attr_addr_hi) { 6657750SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: boot archive is too big"); 6667750SSherry.Moore@Sun.COM goto err_out; 6677656SSherry.Moore@Sun.COM } 6687656SSherry.Moore@Sun.COM 6697750SSherry.Moore@Sun.COM /* 6707750SSherry.Moore@Sun.COM * Adjust dma_attr_addr_lo so that the new kernel and boot 6717750SSherry.Moore@Sun.COM * archive will not be overridden during relocation. 6727750SSherry.Moore@Sun.COM */ 6737750SSherry.Moore@Sun.COM if (end_addr > fastboot_dma_attr.dma_attr_addr_lo || 6747750SSherry.Moore@Sun.COM end_addr > fastboot_below_1G_dma_attr.dma_attr_addr_lo) { 6757750SSherry.Moore@Sun.COM 6767750SSherry.Moore@Sun.COM if (is_retry) { 6777750SSherry.Moore@Sun.COM /* 6787750SSherry.Moore@Sun.COM * If we have already tried and didn't succeed, 6797750SSherry.Moore@Sun.COM * just give up. 6807750SSherry.Moore@Sun.COM */ 6817750SSherry.Moore@Sun.COM cmn_err(CE_WARN, 6827750SSherry.Moore@Sun.COM "Fastboot: boot archive is too big"); 6837750SSherry.Moore@Sun.COM goto err_out; 6847750SSherry.Moore@Sun.COM } else { 6857750SSherry.Moore@Sun.COM int j; 6867750SSherry.Moore@Sun.COM 6877750SSherry.Moore@Sun.COM /* Set the flag so we don't keep retrying */ 6887750SSherry.Moore@Sun.COM is_retry++; 6897750SSherry.Moore@Sun.COM 6907750SSherry.Moore@Sun.COM /* Adjust dma_attr_addr_lo */ 6917750SSherry.Moore@Sun.COM fastboot_dma_attr.dma_attr_addr_lo = end_addr; 6927750SSherry.Moore@Sun.COM fastboot_below_1G_dma_attr.dma_attr_addr_lo = 6937750SSherry.Moore@Sun.COM end_addr; 6947750SSherry.Moore@Sun.COM 6957750SSherry.Moore@Sun.COM /* 6967750SSherry.Moore@Sun.COM * Free the memory we have already allocated 6977750SSherry.Moore@Sun.COM * whose physical addresses might not fit 6987750SSherry.Moore@Sun.COM * the new lo and hi constraints. 6997750SSherry.Moore@Sun.COM */ 7007750SSherry.Moore@Sun.COM for (j = 0; j < i; j++) 7017750SSherry.Moore@Sun.COM fastboot_free_file( 7027750SSherry.Moore@Sun.COM &newkernel.fi_files[j]); 7037750SSherry.Moore@Sun.COM goto load_kernel_retry; 7047750SSherry.Moore@Sun.COM } 7057750SSherry.Moore@Sun.COM } 7067750SSherry.Moore@Sun.COM 7077750SSherry.Moore@Sun.COM 7087656SSherry.Moore@Sun.COM if (!fastboot_contig) 7097656SSherry.Moore@Sun.COM dma_attr.dma_attr_sgllen = (fsize / PAGESIZE) + 7107656SSherry.Moore@Sun.COM (((fsize % PAGESIZE) == 0) ? 0 : 1); 7117656SSherry.Moore@Sun.COM 7127656SSherry.Moore@Sun.COM if ((buf = contig_alloc(fsize, &dma_attr, PAGESIZE, 0)) 7137656SSherry.Moore@Sun.COM == NULL) { 7147750SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, fsize, "64G"); 7157656SSherry.Moore@Sun.COM goto err_out; 7167656SSherry.Moore@Sun.COM } 7177656SSherry.Moore@Sun.COM 7187656SSherry.Moore@Sun.COM va = P2ROUNDUP_TYPED((uintptr_t)buf, PAGESIZE, uintptr_t); 7197656SSherry.Moore@Sun.COM 7207656SSherry.Moore@Sun.COM if (kobj_read_file(file, (char *)va, fsize, 0) < 0) { 7217656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Couldn't read %s", 7227656SSherry.Moore@Sun.COM fastboot_filename[i]); 7237656SSherry.Moore@Sun.COM goto err_out; 7247656SSherry.Moore@Sun.COM } 7257656SSherry.Moore@Sun.COM 7267656SSherry.Moore@Sun.COM fb = &newkernel.fi_files[i]; 7277656SSherry.Moore@Sun.COM fb->fb_va = va; 7287656SSherry.Moore@Sun.COM fb->fb_size = fsize; 7297656SSherry.Moore@Sun.COM fb->fb_sectcnt = 0; 7307656SSherry.Moore@Sun.COM 7317656SSherry.Moore@Sun.COM /* 7327656SSherry.Moore@Sun.COM * Allocate one extra page table entry for terminating 7337656SSherry.Moore@Sun.COM * the list. 7347656SSherry.Moore@Sun.COM */ 7357656SSherry.Moore@Sun.COM pt_entry_count = (fsize_roundup >> PAGESHIFT) + 1; 7367656SSherry.Moore@Sun.COM pt_size = P2ROUNDUP(pt_entry_count * 8, PAGESIZE); 7377656SSherry.Moore@Sun.COM 7387656SSherry.Moore@Sun.COM if ((fb->fb_pte_list_va = 7397656SSherry.Moore@Sun.COM (x86pte_t *)contig_alloc(pt_size, 7407656SSherry.Moore@Sun.COM &fastboot_below_1G_dma_attr, PAGESIZE, 0)) == NULL) { 7417656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, 7427656SSherry.Moore@Sun.COM (uint64_t)pt_size, "1G"); 7437656SSherry.Moore@Sun.COM goto err_out; 7447656SSherry.Moore@Sun.COM } 7457656SSherry.Moore@Sun.COM 7467656SSherry.Moore@Sun.COM bzero((void *)(fb->fb_pte_list_va), pt_size); 7477656SSherry.Moore@Sun.COM 7487656SSherry.Moore@Sun.COM fb->fb_pte_list_pa = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, 7497656SSherry.Moore@Sun.COM (caddr_t)fb->fb_pte_list_va)); 7507656SSherry.Moore@Sun.COM 7517656SSherry.Moore@Sun.COM for (page_index = 0, offset = 0; offset < fb->fb_size; 7527656SSherry.Moore@Sun.COM offset += PAGESIZE) { 7537656SSherry.Moore@Sun.COM uint64_t paddr; 7547656SSherry.Moore@Sun.COM 7557656SSherry.Moore@Sun.COM paddr = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, 7567656SSherry.Moore@Sun.COM (caddr_t)fb->fb_va + offset)); 7577656SSherry.Moore@Sun.COM 7587656SSherry.Moore@Sun.COM ASSERT(paddr >= fastboot_dma_attr.dma_attr_addr_lo); 7597656SSherry.Moore@Sun.COM 7607656SSherry.Moore@Sun.COM /* 7617656SSherry.Moore@Sun.COM * Include the pte_bits so we don't have to make 7627656SSherry.Moore@Sun.COM * it in assembly. 7637656SSherry.Moore@Sun.COM */ 7647656SSherry.Moore@Sun.COM fb->fb_pte_list_va[page_index++] = (x86pte_t) 7657656SSherry.Moore@Sun.COM (paddr | pte_bits); 7667656SSherry.Moore@Sun.COM } 7677656SSherry.Moore@Sun.COM 7687656SSherry.Moore@Sun.COM fb->fb_pte_list_va[page_index] = FASTBOOT_TERMINATE; 7697656SSherry.Moore@Sun.COM 7707656SSherry.Moore@Sun.COM if (i == FASTBOOT_UNIX) { 7717750SSherry.Moore@Sun.COM Ehdr *ehdr = (Ehdr *)va; 7727750SSherry.Moore@Sun.COM int j; 7737656SSherry.Moore@Sun.COM 7747656SSherry.Moore@Sun.COM /* 7757656SSherry.Moore@Sun.COM * Sanity checks: 7767656SSherry.Moore@Sun.COM */ 7777656SSherry.Moore@Sun.COM for (j = 0; j < SELFMAG; j++) { 7787656SSherry.Moore@Sun.COM if (ehdr->e_ident[j] != ELFMAG[j]) { 7797656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Bad ELF " 7807656SSherry.Moore@Sun.COM "signature"); 7817656SSherry.Moore@Sun.COM goto err_out; 7827656SSherry.Moore@Sun.COM } 7837656SSherry.Moore@Sun.COM } 7847656SSherry.Moore@Sun.COM 7857656SSherry.Moore@Sun.COM if (ehdr->e_ident[EI_CLASS] == ELFCLASS32 && 7867656SSherry.Moore@Sun.COM ehdr->e_ident[EI_DATA] == ELFDATA2LSB && 7877656SSherry.Moore@Sun.COM ehdr->e_machine == EM_386) { 7887656SSherry.Moore@Sun.COM 789*8151SKonstantin.Ananyev@Sun.COM fb->fb_sectcnt = sizeof (fb->fb_sections) / 790*8151SKonstantin.Ananyev@Sun.COM sizeof (fb->fb_sections[0]); 791*8151SKonstantin.Ananyev@Sun.COM 7927656SSherry.Moore@Sun.COM if (fastboot_elf32_find_loadables((void *)va, 7937656SSherry.Moore@Sun.COM fsize, &fb->fb_sections[0], 7947656SSherry.Moore@Sun.COM &fb->fb_sectcnt, &dboot_start_offset) < 0) { 7957656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: ELF32 " 7967656SSherry.Moore@Sun.COM "program section failure"); 7977656SSherry.Moore@Sun.COM goto err_out; 7987656SSherry.Moore@Sun.COM } 7997656SSherry.Moore@Sun.COM 8007656SSherry.Moore@Sun.COM if (fb->fb_sectcnt == 0) { 8017656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: No ELF32 " 8027656SSherry.Moore@Sun.COM "program sections found"); 8037656SSherry.Moore@Sun.COM goto err_out; 8047656SSherry.Moore@Sun.COM } 8057656SSherry.Moore@Sun.COM 8067656SSherry.Moore@Sun.COM if (is_failsafe) { 8077656SSherry.Moore@Sun.COM /* Failsafe boot_archive */ 8087656SSherry.Moore@Sun.COM bcopy(BOOTARCHIVE_FAILSAFE, 8097656SSherry.Moore@Sun.COM &fastboot_filename 8107656SSherry.Moore@Sun.COM [FASTBOOT_NAME_BOOTARCHIVE] 8117656SSherry.Moore@Sun.COM [bootpath_len], 8127656SSherry.Moore@Sun.COM sizeof (BOOTARCHIVE_FAILSAFE)); 8137656SSherry.Moore@Sun.COM } else { 8147656SSherry.Moore@Sun.COM bcopy(BOOTARCHIVE32, 8157656SSherry.Moore@Sun.COM &fastboot_filename 8167656SSherry.Moore@Sun.COM [FASTBOOT_NAME_BOOTARCHIVE] 8177656SSherry.Moore@Sun.COM [bootpath_len], 8187656SSherry.Moore@Sun.COM sizeof (BOOTARCHIVE32)); 8197656SSherry.Moore@Sun.COM } 8207656SSherry.Moore@Sun.COM 8217656SSherry.Moore@Sun.COM } else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64 && 8227656SSherry.Moore@Sun.COM ehdr->e_ident[EI_DATA] == ELFDATA2LSB && 8237656SSherry.Moore@Sun.COM ehdr->e_machine == EM_AMD64) { 8247656SSherry.Moore@Sun.COM 8257656SSherry.Moore@Sun.COM if (fastboot_elf64_find_dboot_load_offset( 8267656SSherry.Moore@Sun.COM (void *)va, fsize, &dboot_start_offset) 8277656SSherry.Moore@Sun.COM != 0) { 8287656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Couldn't " 8297656SSherry.Moore@Sun.COM "find ELF64 dboot entry offset"); 8307656SSherry.Moore@Sun.COM goto err_out; 8317656SSherry.Moore@Sun.COM } 8327656SSherry.Moore@Sun.COM 8337656SSherry.Moore@Sun.COM if ((x86_feature & X86_64) == 0 || 834*8151SKonstantin.Ananyev@Sun.COM (x86_feature & X86_PAE) == 0) { 8357656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Cannot " 8367656SSherry.Moore@Sun.COM "reboot to %s: " 8377656SSherry.Moore@Sun.COM "not a 64-bit capable system", 8387656SSherry.Moore@Sun.COM kern_bootfile); 8397656SSherry.Moore@Sun.COM goto err_out; 8407656SSherry.Moore@Sun.COM } 8417656SSherry.Moore@Sun.COM 8427656SSherry.Moore@Sun.COM bcopy(BOOTARCHIVE64, 8437656SSherry.Moore@Sun.COM &fastboot_filename 8447656SSherry.Moore@Sun.COM [FASTBOOT_NAME_BOOTARCHIVE][bootpath_len], 8457656SSherry.Moore@Sun.COM sizeof (BOOTARCHIVE64)); 8467656SSherry.Moore@Sun.COM } else { 8477656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Unknown ELF type"); 8487656SSherry.Moore@Sun.COM goto err_out; 8497656SSherry.Moore@Sun.COM } 8507656SSherry.Moore@Sun.COM 8517656SSherry.Moore@Sun.COM fb->fb_dest_pa = DBOOT_ENTRY_ADDRESS - 8527656SSherry.Moore@Sun.COM dboot_start_offset; 8537656SSherry.Moore@Sun.COM 8547656SSherry.Moore@Sun.COM fb->fb_next_pa = DBOOT_ENTRY_ADDRESS + fsize_roundup; 8557656SSherry.Moore@Sun.COM } else { 8567656SSherry.Moore@Sun.COM fb->fb_dest_pa = newkernel.fi_files[i - 1].fb_next_pa; 8577656SSherry.Moore@Sun.COM fb->fb_next_pa = fb->fb_dest_pa + fsize_roundup; 8587656SSherry.Moore@Sun.COM } 8597656SSherry.Moore@Sun.COM 8607656SSherry.Moore@Sun.COM kobj_close_file(file); 8617656SSherry.Moore@Sun.COM 8627656SSherry.Moore@Sun.COM } 8637656SSherry.Moore@Sun.COM 8647750SSherry.Moore@Sun.COM /* 8657750SSherry.Moore@Sun.COM * Set fb_va to fake_va 8667750SSherry.Moore@Sun.COM */ 8677750SSherry.Moore@Sun.COM for (i = 0; i < FASTBOOT_MAX_FILES_MAP; i++) { 8687750SSherry.Moore@Sun.COM newkernel.fi_files[i].fb_va = fake_va; 8697750SSherry.Moore@Sun.COM 8707750SSherry.Moore@Sun.COM } 8717656SSherry.Moore@Sun.COM 8727656SSherry.Moore@Sun.COM /* 8737656SSherry.Moore@Sun.COM * Add the function that will switch us to 32-bit protected mode 8747656SSherry.Moore@Sun.COM */ 8757656SSherry.Moore@Sun.COM fb = &newkernel.fi_files[FASTBOOT_SWTCH]; 8767656SSherry.Moore@Sun.COM fb->fb_va = fb->fb_dest_pa = FASTBOOT_SWTCH_PA; 877*8151SKonstantin.Ananyev@Sun.COM fb->fb_size = MMU_PAGESIZE; 8787656SSherry.Moore@Sun.COM 8797656SSherry.Moore@Sun.COM /* 8807656SSherry.Moore@Sun.COM * Map in FASTBOOT_SWTCH_PA 8817656SSherry.Moore@Sun.COM */ 8827656SSherry.Moore@Sun.COM hat_devload(kas.a_hat, (caddr_t)fb->fb_va, MMU_PAGESIZE, 8837656SSherry.Moore@Sun.COM mmu_btop(fb->fb_dest_pa), 8847656SSherry.Moore@Sun.COM PROT_READ | PROT_WRITE | PROT_EXEC, HAT_LOAD_NOCONSIST); 8857656SSherry.Moore@Sun.COM 8867656SSherry.Moore@Sun.COM bcopy((void *)fb_swtch_image, (void *)fb->fb_va, fb->fb_size); 8877656SSherry.Moore@Sun.COM 8887656SSherry.Moore@Sun.COM /* 8897656SSherry.Moore@Sun.COM * Build the new multiboot_info structure 8907656SSherry.Moore@Sun.COM */ 8917750SSherry.Moore@Sun.COM if (fastboot_build_mbi(bootargs, &newkernel) != 0) { 8927656SSherry.Moore@Sun.COM goto err_out; 8937656SSherry.Moore@Sun.COM } 8947656SSherry.Moore@Sun.COM 8957656SSherry.Moore@Sun.COM /* 8967656SSherry.Moore@Sun.COM * Build page table for low 1G physical memory. Use big pages. 897*8151SKonstantin.Ananyev@Sun.COM * Allocate 4 (5 for amd64) pages for the page tables. 898*8151SKonstantin.Ananyev@Sun.COM * 1 page for PML4 (amd64) 8997656SSherry.Moore@Sun.COM * 1 page for Page-Directory-Pointer Table 900*8151SKonstantin.Ananyev@Sun.COM * 2 pages for Page Directory 9017656SSherry.Moore@Sun.COM * 1 page for Page Table. 9027656SSherry.Moore@Sun.COM * The page table entry will be rewritten to map the physical 9037656SSherry.Moore@Sun.COM * address as we do the copying. 9047656SSherry.Moore@Sun.COM */ 9057656SSherry.Moore@Sun.COM if (newkernel.fi_has_pae) { 906*8151SKonstantin.Ananyev@Sun.COM #ifdef __amd64 907*8151SKonstantin.Ananyev@Sun.COM size_t size = MMU_PAGESIZE * 5; 908*8151SKonstantin.Ananyev@Sun.COM #else 9097656SSherry.Moore@Sun.COM size_t size = MMU_PAGESIZE * 4; 910*8151SKonstantin.Ananyev@Sun.COM #endif /* __amd64 */ 9117656SSherry.Moore@Sun.COM 9127656SSherry.Moore@Sun.COM if ((newkernel.fi_pagetable_va = (uintptr_t) 9137656SSherry.Moore@Sun.COM contig_alloc(size, &fastboot_below_1G_dma_attr, 914*8151SKonstantin.Ananyev@Sun.COM MMU_PAGESIZE, 0)) == NULL) { 9157656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, 9167656SSherry.Moore@Sun.COM (uint64_t)size, "1G"); 9177656SSherry.Moore@Sun.COM goto err_out; 9187656SSherry.Moore@Sun.COM } 9197656SSherry.Moore@Sun.COM 9207656SSherry.Moore@Sun.COM bzero((void *)(newkernel.fi_pagetable_va), size); 9217656SSherry.Moore@Sun.COM 9227656SSherry.Moore@Sun.COM newkernel.fi_pagetable_pa = 9237656SSherry.Moore@Sun.COM mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, 9247656SSherry.Moore@Sun.COM (caddr_t)newkernel.fi_pagetable_va)); 9257656SSherry.Moore@Sun.COM 9267656SSherry.Moore@Sun.COM newkernel.fi_last_table_pa = newkernel.fi_pagetable_pa + 927*8151SKonstantin.Ananyev@Sun.COM size - MMU_PAGESIZE; 9287656SSherry.Moore@Sun.COM 9297656SSherry.Moore@Sun.COM newkernel.fi_next_table_va = newkernel.fi_pagetable_va + 9307656SSherry.Moore@Sun.COM MMU_PAGESIZE; 9317656SSherry.Moore@Sun.COM newkernel.fi_next_table_pa = newkernel.fi_pagetable_pa + 9327656SSherry.Moore@Sun.COM MMU_PAGESIZE; 9337656SSherry.Moore@Sun.COM 9347656SSherry.Moore@Sun.COM fastboot_build_pagetables(&newkernel); 9357656SSherry.Moore@Sun.COM } 9367656SSherry.Moore@Sun.COM 9377656SSherry.Moore@Sun.COM 9387656SSherry.Moore@Sun.COM /* Mark it as valid */ 9397656SSherry.Moore@Sun.COM newkernel.fi_valid = 1; 9407656SSherry.Moore@Sun.COM newkernel.fi_magic = FASTBOOT_MAGIC; 9417656SSherry.Moore@Sun.COM 9427656SSherry.Moore@Sun.COM return; 9437656SSherry.Moore@Sun.COM 9447656SSherry.Moore@Sun.COM err_out: 9457656SSherry.Moore@Sun.COM newkernel.fi_valid = 0; 9467656SSherry.Moore@Sun.COM } 9477656SSherry.Moore@Sun.COM 9487750SSherry.Moore@Sun.COM /* 9497750SSherry.Moore@Sun.COM * Jump to the fast reboot switcher. This function never returns. 9507750SSherry.Moore@Sun.COM */ 9517656SSherry.Moore@Sun.COM void 9527656SSherry.Moore@Sun.COM fast_reboot() 9537656SSherry.Moore@Sun.COM { 9547656SSherry.Moore@Sun.COM void (*fastboot_func)(fastboot_info_t *); 9557656SSherry.Moore@Sun.COM 9567656SSherry.Moore@Sun.COM fastboot_func = (void (*)())(newkernel.fi_files[FASTBOOT_SWTCH].fb_va); 9577656SSherry.Moore@Sun.COM (*fastboot_func)(&newkernel); 9587656SSherry.Moore@Sun.COM } 959