1*7656SSherry.Moore@Sun.COM /* 2*7656SSherry.Moore@Sun.COM * CDDL HEADER START 3*7656SSherry.Moore@Sun.COM * 4*7656SSherry.Moore@Sun.COM * The contents of this file are subject to the terms of the 5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License"). 6*7656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License. 7*7656SSherry.Moore@Sun.COM * 8*7656SSherry.Moore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7656SSherry.Moore@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*7656SSherry.Moore@Sun.COM * See the License for the specific language governing permissions 11*7656SSherry.Moore@Sun.COM * and limitations under the License. 12*7656SSherry.Moore@Sun.COM * 13*7656SSherry.Moore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*7656SSherry.Moore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7656SSherry.Moore@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*7656SSherry.Moore@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*7656SSherry.Moore@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*7656SSherry.Moore@Sun.COM * 19*7656SSherry.Moore@Sun.COM * CDDL HEADER END 20*7656SSherry.Moore@Sun.COM */ 21*7656SSherry.Moore@Sun.COM 22*7656SSherry.Moore@Sun.COM /* 23*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*7656SSherry.Moore@Sun.COM * Use is subject to license terms. 25*7656SSherry.Moore@Sun.COM */ 26*7656SSherry.Moore@Sun.COM 27*7656SSherry.Moore@Sun.COM 28*7656SSherry.Moore@Sun.COM #include <sys/types.h> 29*7656SSherry.Moore@Sun.COM #include <sys/param.h> 30*7656SSherry.Moore@Sun.COM #include <sys/segments.h> 31*7656SSherry.Moore@Sun.COM #include <sys/sysmacros.h> 32*7656SSherry.Moore@Sun.COM #include <sys/vm.h> 33*7656SSherry.Moore@Sun.COM 34*7656SSherry.Moore@Sun.COM #include <sys/proc.h> 35*7656SSherry.Moore@Sun.COM #include <sys/buf.h> 36*7656SSherry.Moore@Sun.COM #include <sys/kmem.h> 37*7656SSherry.Moore@Sun.COM 38*7656SSherry.Moore@Sun.COM #include <sys/reboot.h> 39*7656SSherry.Moore@Sun.COM #include <sys/uadmin.h> 40*7656SSherry.Moore@Sun.COM 41*7656SSherry.Moore@Sun.COM #include <sys/cred.h> 42*7656SSherry.Moore@Sun.COM #include <sys/vnode.h> 43*7656SSherry.Moore@Sun.COM #include <sys/file.h> 44*7656SSherry.Moore@Sun.COM 45*7656SSherry.Moore@Sun.COM #include <sys/cmn_err.h> 46*7656SSherry.Moore@Sun.COM #include <sys/dumphdr.h> 47*7656SSherry.Moore@Sun.COM #include <sys/bootconf.h> 48*7656SSherry.Moore@Sun.COM #include <sys/ddidmareq.h> 49*7656SSherry.Moore@Sun.COM #include <sys/varargs.h> 50*7656SSherry.Moore@Sun.COM #include <sys/promif.h> 51*7656SSherry.Moore@Sun.COM #include <sys/modctl.h> 52*7656SSherry.Moore@Sun.COM 53*7656SSherry.Moore@Sun.COM #include <vm/hat.h> 54*7656SSherry.Moore@Sun.COM #include <vm/as.h> 55*7656SSherry.Moore@Sun.COM #include <vm/page.h> 56*7656SSherry.Moore@Sun.COM #include <vm/seg.h> 57*7656SSherry.Moore@Sun.COM #include <vm/hat_i86.h> 58*7656SSherry.Moore@Sun.COM #include <sys/vm_machparam.h> 59*7656SSherry.Moore@Sun.COM #include <sys/archsystm.h> 60*7656SSherry.Moore@Sun.COM #include <sys/machsystm.h> 61*7656SSherry.Moore@Sun.COM #include <sys/mman.h> 62*7656SSherry.Moore@Sun.COM #include <sys/x86_archext.h> 63*7656SSherry.Moore@Sun.COM 64*7656SSherry.Moore@Sun.COM #include <sys/fastboot.h> 65*7656SSherry.Moore@Sun.COM #include <sys/machelf.h> 66*7656SSherry.Moore@Sun.COM #include <sys/kobj.h> 67*7656SSherry.Moore@Sun.COM #include <sys/multiboot.h> 68*7656SSherry.Moore@Sun.COM 69*7656SSherry.Moore@Sun.COM fastboot_info_t newkernel = { 0 }; 70*7656SSherry.Moore@Sun.COM static char fastboot_filename[2][OBP_MAXPATHLEN] = { { 0 }, { 0 }}; 71*7656SSherry.Moore@Sun.COM static x86pte_t ptp_bits = PT_VALID | PT_REF | PT_USER | PT_WRITABLE; 72*7656SSherry.Moore@Sun.COM static x86pte_t pte_bits = 73*7656SSherry.Moore@Sun.COM PT_VALID | PT_REF | PT_MOD | PT_NOCONSIST | PT_WRITABLE; 74*7656SSherry.Moore@Sun.COM static uint_t fastboot_shift_amt_pae[] = {12, 21, 30, 39}; 75*7656SSherry.Moore@Sun.COM 76*7656SSherry.Moore@Sun.COM 77*7656SSherry.Moore@Sun.COM int fastboot_debug = 0; 78*7656SSherry.Moore@Sun.COM int fastboot_contig = 0; 79*7656SSherry.Moore@Sun.COM 80*7656SSherry.Moore@Sun.COM /* 81*7656SSherry.Moore@Sun.COM * Fake starting va for new kernel and boot archive. 82*7656SSherry.Moore@Sun.COM */ 83*7656SSherry.Moore@Sun.COM static uintptr_t fake_va = FASTBOOT_FAKE_VA; 84*7656SSherry.Moore@Sun.COM 85*7656SSherry.Moore@Sun.COM /* 86*7656SSherry.Moore@Sun.COM * Below 1G for page tables as we are using 2G as the fake virtual address for 87*7656SSherry.Moore@Sun.COM * the new kernel and boot archive. 88*7656SSherry.Moore@Sun.COM */ 89*7656SSherry.Moore@Sun.COM static ddi_dma_attr_t fastboot_below_1G_dma_attr = { 90*7656SSherry.Moore@Sun.COM DMA_ATTR_V0, 91*7656SSherry.Moore@Sun.COM 0x0000000008000000ULL, /* dma_attr_addr_lo: 128MB */ 92*7656SSherry.Moore@Sun.COM 0x000000003FFFFFFFULL, /* dma_attr_addr_hi: 1G */ 93*7656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_count_max */ 94*7656SSherry.Moore@Sun.COM 0x0000000000001000ULL, /* dma_attr_align: 4KB */ 95*7656SSherry.Moore@Sun.COM 1, /* dma_attr_burstsize */ 96*7656SSherry.Moore@Sun.COM 1, /* dma_attr_minxfer */ 97*7656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_maxxfer */ 98*7656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_seg */ 99*7656SSherry.Moore@Sun.COM 1, /* dma_attr_sgllen */ 100*7656SSherry.Moore@Sun.COM 0x1000ULL, /* dma_attr_granular */ 101*7656SSherry.Moore@Sun.COM 0, /* dma_attr_flags */ 102*7656SSherry.Moore@Sun.COM }; 103*7656SSherry.Moore@Sun.COM 104*7656SSherry.Moore@Sun.COM static ddi_dma_attr_t fastboot_dma_attr = { 105*7656SSherry.Moore@Sun.COM DMA_ATTR_V0, 106*7656SSherry.Moore@Sun.COM 0x0000000008000000ULL, /* dma_attr_addr_lo: 128MB */ 107*7656SSherry.Moore@Sun.COM 0x0000000FFFFFFFFFULL, /* dma_attr_addr_hi: 64GB */ 108*7656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_count_max */ 109*7656SSherry.Moore@Sun.COM 0x0000000000001000ULL, /* dma_attr_align: 4KB */ 110*7656SSherry.Moore@Sun.COM 1, /* dma_attr_burstsize */ 111*7656SSherry.Moore@Sun.COM 1, /* dma_attr_minxfer */ 112*7656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_maxxfer */ 113*7656SSherry.Moore@Sun.COM 0x00000000FFFFFFFFULL, /* dma_attr_seg */ 114*7656SSherry.Moore@Sun.COM 1, /* dma_attr_sgllen */ 115*7656SSherry.Moore@Sun.COM 0x1000ULL, /* dma_attr_granular */ 116*7656SSherry.Moore@Sun.COM 0, /* dma_attr_flags */ 117*7656SSherry.Moore@Sun.COM }; 118*7656SSherry.Moore@Sun.COM 119*7656SSherry.Moore@Sun.COM /* 120*7656SSherry.Moore@Sun.COM * Various information saved from the previous boot to reconstruct 121*7656SSherry.Moore@Sun.COM * multiboot_info. 122*7656SSherry.Moore@Sun.COM */ 123*7656SSherry.Moore@Sun.COM extern multiboot_info_t saved_mbi; 124*7656SSherry.Moore@Sun.COM extern mb_memory_map_t saved_mmap[FASTBOOT_SAVED_MMAP_COUNT]; 125*7656SSherry.Moore@Sun.COM extern struct sol_netinfo saved_drives[FASTBOOT_SAVED_DRIVES_COUNT]; 126*7656SSherry.Moore@Sun.COM extern char saved_cmdline[FASTBOOT_SAVED_CMDLINE_LEN]; 127*7656SSherry.Moore@Sun.COM extern int saved_cmdline_len; 128*7656SSherry.Moore@Sun.COM 129*7656SSherry.Moore@Sun.COM extern void* contig_alloc(size_t size, ddi_dma_attr_t *attr, 130*7656SSherry.Moore@Sun.COM uintptr_t align, int cansleep); 131*7656SSherry.Moore@Sun.COM 132*7656SSherry.Moore@Sun.COM /* PRINTLIKE */ 133*7656SSherry.Moore@Sun.COM extern void vprintf(const char *, va_list); 134*7656SSherry.Moore@Sun.COM 135*7656SSherry.Moore@Sun.COM 136*7656SSherry.Moore@Sun.COM /* 137*7656SSherry.Moore@Sun.COM * Need to be able to get boot_archives from other places 138*7656SSherry.Moore@Sun.COM */ 139*7656SSherry.Moore@Sun.COM #define BOOTARCHIVE64 "/platform/i86pc/amd64/boot_archive" 140*7656SSherry.Moore@Sun.COM #define BOOTARCHIVE32 "/platform/i86pc/boot_archive" 141*7656SSherry.Moore@Sun.COM #define BOOTARCHIVE_FAILSAFE "/boot/x86.miniroot-safe" 142*7656SSherry.Moore@Sun.COM #define FAILSAFE_BOOTFILE "/boot/platform/i86pc/kernel/unix" 143*7656SSherry.Moore@Sun.COM 144*7656SSherry.Moore@Sun.COM static uint_t fastboot_vatoindex(fastboot_info_t *, uintptr_t, int); 145*7656SSherry.Moore@Sun.COM static void fastboot_map_with_size(fastboot_info_t *, uintptr_t, 146*7656SSherry.Moore@Sun.COM paddr_t, size_t, int); 147*7656SSherry.Moore@Sun.COM static void fastboot_build_pagetables(fastboot_info_t *); 148*7656SSherry.Moore@Sun.COM static int fastboot_build_mbi(char *, fastboot_info_t *); 149*7656SSherry.Moore@Sun.COM 150*7656SSherry.Moore@Sun.COM static const char fastboot_enomem_msg[] = "Fastboot: Couldn't allocate 0x%" 151*7656SSherry.Moore@Sun.COM PRIx64" bytes below %s to do fast reboot"; 152*7656SSherry.Moore@Sun.COM 153*7656SSherry.Moore@Sun.COM static void 154*7656SSherry.Moore@Sun.COM dprintf(char *fmt, ...) 155*7656SSherry.Moore@Sun.COM { 156*7656SSherry.Moore@Sun.COM va_list adx; 157*7656SSherry.Moore@Sun.COM 158*7656SSherry.Moore@Sun.COM if (!fastboot_debug) 159*7656SSherry.Moore@Sun.COM return; 160*7656SSherry.Moore@Sun.COM 161*7656SSherry.Moore@Sun.COM va_start(adx, fmt); 162*7656SSherry.Moore@Sun.COM vprintf(fmt, adx); 163*7656SSherry.Moore@Sun.COM va_end(adx); 164*7656SSherry.Moore@Sun.COM } 165*7656SSherry.Moore@Sun.COM 166*7656SSherry.Moore@Sun.COM 167*7656SSherry.Moore@Sun.COM /* 168*7656SSherry.Moore@Sun.COM * Return the index corresponding to a virt address at a given page table level. 169*7656SSherry.Moore@Sun.COM */ 170*7656SSherry.Moore@Sun.COM static uint_t 171*7656SSherry.Moore@Sun.COM fastboot_vatoindex(fastboot_info_t *nk, uintptr_t va, int level) 172*7656SSherry.Moore@Sun.COM { 173*7656SSherry.Moore@Sun.COM return ((va >> nk->fi_shift_amt[level]) & (nk->fi_ptes_per_table - 1)); 174*7656SSherry.Moore@Sun.COM } 175*7656SSherry.Moore@Sun.COM 176*7656SSherry.Moore@Sun.COM 177*7656SSherry.Moore@Sun.COM /* 178*7656SSherry.Moore@Sun.COM * Add mapping from vstart to pstart for the specified size. 179*7656SSherry.Moore@Sun.COM * Only handles 2 level. Must use 2M pages. vstart, pstart 180*7656SSherry.Moore@Sun.COM * and size should all have been aligned at 2M boundaries. 181*7656SSherry.Moore@Sun.COM */ 182*7656SSherry.Moore@Sun.COM static void 183*7656SSherry.Moore@Sun.COM fastboot_map_with_size(fastboot_info_t *nk, uintptr_t vstart, paddr_t pstart, 184*7656SSherry.Moore@Sun.COM size_t size, int level) 185*7656SSherry.Moore@Sun.COM { 186*7656SSherry.Moore@Sun.COM x86pte_t pteval, *table; 187*7656SSherry.Moore@Sun.COM uintptr_t vaddr; 188*7656SSherry.Moore@Sun.COM paddr_t paddr; 189*7656SSherry.Moore@Sun.COM int index, l; 190*7656SSherry.Moore@Sun.COM 191*7656SSherry.Moore@Sun.COM table = (x86pte_t *)(nk->fi_pagetable_va); 192*7656SSherry.Moore@Sun.COM 193*7656SSherry.Moore@Sun.COM for (l = nk->fi_top_level; l >= level; l--) { 194*7656SSherry.Moore@Sun.COM 195*7656SSherry.Moore@Sun.COM index = fastboot_vatoindex(nk, vstart, l); 196*7656SSherry.Moore@Sun.COM 197*7656SSherry.Moore@Sun.COM if (l == level) { 198*7656SSherry.Moore@Sun.COM /* 199*7656SSherry.Moore@Sun.COM * Last level. Program the page table entries. 200*7656SSherry.Moore@Sun.COM */ 201*7656SSherry.Moore@Sun.COM for (vaddr = vstart, paddr = pstart; 202*7656SSherry.Moore@Sun.COM vaddr < vstart + size; 203*7656SSherry.Moore@Sun.COM vaddr += (1ULL << nk->fi_shift_amt[l]), 204*7656SSherry.Moore@Sun.COM paddr += (1ULL << nk->fi_shift_amt[l])) { 205*7656SSherry.Moore@Sun.COM 206*7656SSherry.Moore@Sun.COM uint_t index = fastboot_vatoindex(nk, vaddr, l); 207*7656SSherry.Moore@Sun.COM 208*7656SSherry.Moore@Sun.COM if (l > 0) 209*7656SSherry.Moore@Sun.COM pteval = paddr | pte_bits | PT_PAGESIZE; 210*7656SSherry.Moore@Sun.COM else 211*7656SSherry.Moore@Sun.COM pteval = paddr | pte_bits; 212*7656SSherry.Moore@Sun.COM 213*7656SSherry.Moore@Sun.COM table[index] = pteval; 214*7656SSherry.Moore@Sun.COM } 215*7656SSherry.Moore@Sun.COM } else if (table[index] & PT_VALID) { 216*7656SSherry.Moore@Sun.COM if (l == level) 217*7656SSherry.Moore@Sun.COM break; 218*7656SSherry.Moore@Sun.COM 219*7656SSherry.Moore@Sun.COM table = (x86pte_t *) 220*7656SSherry.Moore@Sun.COM ((uintptr_t)(((paddr_t)table[index] & MMU_PAGEMASK) 221*7656SSherry.Moore@Sun.COM - nk->fi_pagetable_pa) + nk->fi_pagetable_va); 222*7656SSherry.Moore@Sun.COM } else { 223*7656SSherry.Moore@Sun.COM /* 224*7656SSherry.Moore@Sun.COM * Intermediate levels. Program with either valid 225*7656SSherry.Moore@Sun.COM * bit or PTP bits. 226*7656SSherry.Moore@Sun.COM */ 227*7656SSherry.Moore@Sun.COM if (l == nk->fi_top_level) { 228*7656SSherry.Moore@Sun.COM table[index] = nk->fi_next_table_pa | PT_VALID; 229*7656SSherry.Moore@Sun.COM } else { 230*7656SSherry.Moore@Sun.COM table[index] = nk->fi_next_table_pa | ptp_bits; 231*7656SSherry.Moore@Sun.COM } 232*7656SSherry.Moore@Sun.COM table = (x86pte_t *)(nk->fi_next_table_va); 233*7656SSherry.Moore@Sun.COM nk->fi_next_table_va += MMU_PAGESIZE; 234*7656SSherry.Moore@Sun.COM nk->fi_next_table_pa += MMU_PAGESIZE; 235*7656SSherry.Moore@Sun.COM } 236*7656SSherry.Moore@Sun.COM } 237*7656SSherry.Moore@Sun.COM } 238*7656SSherry.Moore@Sun.COM 239*7656SSherry.Moore@Sun.COM /* 240*7656SSherry.Moore@Sun.COM * Build page tables for the lower 1G of physical memory using 2M 241*7656SSherry.Moore@Sun.COM * pages, and prepare page tables for mapping new kernel and boot 242*7656SSherry.Moore@Sun.COM * archive pages using 4K pages. 243*7656SSherry.Moore@Sun.COM */ 244*7656SSherry.Moore@Sun.COM static void 245*7656SSherry.Moore@Sun.COM fastboot_build_pagetables(fastboot_info_t *nk) 246*7656SSherry.Moore@Sun.COM { 247*7656SSherry.Moore@Sun.COM /* 248*7656SSherry.Moore@Sun.COM * Map lower 1G physical memory. Use large pages. 249*7656SSherry.Moore@Sun.COM */ 250*7656SSherry.Moore@Sun.COM fastboot_map_with_size(nk, 0, 0, ONE_GIG, 1); 251*7656SSherry.Moore@Sun.COM 252*7656SSherry.Moore@Sun.COM /* 253*7656SSherry.Moore@Sun.COM * Map one 4K page to get the middle page tables set up. 254*7656SSherry.Moore@Sun.COM */ 255*7656SSherry.Moore@Sun.COM fake_va = P2ALIGN_TYPED(fake_va, nk->fi_lpagesize, uintptr_t); 256*7656SSherry.Moore@Sun.COM fastboot_map_with_size(nk, fake_va, 257*7656SSherry.Moore@Sun.COM nk->fi_files[0].fb_pte_list_va[0] & MMU_PAGEMASK, PAGESIZE, 0); 258*7656SSherry.Moore@Sun.COM } 259*7656SSherry.Moore@Sun.COM 260*7656SSherry.Moore@Sun.COM 261*7656SSherry.Moore@Sun.COM /* 262*7656SSherry.Moore@Sun.COM * Sanity check. Look for dboot offset. 263*7656SSherry.Moore@Sun.COM */ 264*7656SSherry.Moore@Sun.COM static int 265*7656SSherry.Moore@Sun.COM fastboot_elf64_find_dboot_load_offset(void *img, off_t imgsz, uint32_t *offp) 266*7656SSherry.Moore@Sun.COM { 267*7656SSherry.Moore@Sun.COM Elf64_Ehdr *ehdr = (Elf64_Ehdr *)img; 268*7656SSherry.Moore@Sun.COM Elf64_Phdr *phdr; 269*7656SSherry.Moore@Sun.COM uint8_t *phdrbase; 270*7656SSherry.Moore@Sun.COM int i; 271*7656SSherry.Moore@Sun.COM 272*7656SSherry.Moore@Sun.COM if ((ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize) >= imgsz) 273*7656SSherry.Moore@Sun.COM return (-1); 274*7656SSherry.Moore@Sun.COM 275*7656SSherry.Moore@Sun.COM phdrbase = (uint8_t *)img + ehdr->e_phoff; 276*7656SSherry.Moore@Sun.COM 277*7656SSherry.Moore@Sun.COM for (i = 0; i < ehdr->e_phnum; i++) { 278*7656SSherry.Moore@Sun.COM phdr = (Elf64_Phdr *)(phdrbase + ehdr->e_phentsize * i); 279*7656SSherry.Moore@Sun.COM 280*7656SSherry.Moore@Sun.COM if (phdr->p_type == PT_LOAD) { 281*7656SSherry.Moore@Sun.COM if (phdr->p_vaddr == phdr->p_paddr && 282*7656SSherry.Moore@Sun.COM phdr->p_vaddr == DBOOT_ENTRY_ADDRESS) { 283*7656SSherry.Moore@Sun.COM ASSERT(phdr->p_offset <= UINT32_MAX); 284*7656SSherry.Moore@Sun.COM *offp = (uint32_t)phdr->p_offset; 285*7656SSherry.Moore@Sun.COM return (0); 286*7656SSherry.Moore@Sun.COM } 287*7656SSherry.Moore@Sun.COM } 288*7656SSherry.Moore@Sun.COM } 289*7656SSherry.Moore@Sun.COM 290*7656SSherry.Moore@Sun.COM return (-1); 291*7656SSherry.Moore@Sun.COM } 292*7656SSherry.Moore@Sun.COM 293*7656SSherry.Moore@Sun.COM 294*7656SSherry.Moore@Sun.COM /* 295*7656SSherry.Moore@Sun.COM * Initialize text and data section information for 32-bit kernel. 296*7656SSherry.Moore@Sun.COM */ 297*7656SSherry.Moore@Sun.COM static int 298*7656SSherry.Moore@Sun.COM fastboot_elf32_find_loadables(void *img, off_t imgsz, fastboot_section_t *sectp, 299*7656SSherry.Moore@Sun.COM int *sectcntp, uint32_t *offp) 300*7656SSherry.Moore@Sun.COM { 301*7656SSherry.Moore@Sun.COM Elf32_Ehdr *ehdr = (Elf32_Ehdr *)img; 302*7656SSherry.Moore@Sun.COM Elf32_Phdr *phdr; 303*7656SSherry.Moore@Sun.COM uint8_t *phdrbase; 304*7656SSherry.Moore@Sun.COM int i; 305*7656SSherry.Moore@Sun.COM int used_sections = 0; 306*7656SSherry.Moore@Sun.COM 307*7656SSherry.Moore@Sun.COM 308*7656SSherry.Moore@Sun.COM if ((ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize) >= imgsz) 309*7656SSherry.Moore@Sun.COM return (-1); 310*7656SSherry.Moore@Sun.COM 311*7656SSherry.Moore@Sun.COM phdrbase = (uint8_t *)img + ehdr->e_phoff; 312*7656SSherry.Moore@Sun.COM 313*7656SSherry.Moore@Sun.COM for (i = 0; i < ehdr->e_phnum; i++) { 314*7656SSherry.Moore@Sun.COM phdr = (Elf32_Phdr *)(phdrbase + ehdr->e_phentsize * i); 315*7656SSherry.Moore@Sun.COM 316*7656SSherry.Moore@Sun.COM if (phdr->p_type == PT_INTERP) 317*7656SSherry.Moore@Sun.COM return (-1); 318*7656SSherry.Moore@Sun.COM 319*7656SSherry.Moore@Sun.COM if (phdr->p_type != PT_LOAD) 320*7656SSherry.Moore@Sun.COM continue; 321*7656SSherry.Moore@Sun.COM 322*7656SSherry.Moore@Sun.COM if (phdr->p_vaddr == phdr->p_paddr && 323*7656SSherry.Moore@Sun.COM phdr->p_paddr == DBOOT_ENTRY_ADDRESS) { 324*7656SSherry.Moore@Sun.COM *offp = (uint32_t)phdr->p_offset; 325*7656SSherry.Moore@Sun.COM } else { 326*7656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_offset = phdr->p_offset; 327*7656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_paddr = phdr->p_paddr; 328*7656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_size = phdr->p_filesz; 329*7656SSherry.Moore@Sun.COM sectp[used_sections].fb_sec_bss_size = 330*7656SSherry.Moore@Sun.COM (phdr->p_filesz < phdr->p_memsz) ? 331*7656SSherry.Moore@Sun.COM (phdr->p_memsz - phdr->p_filesz) : 0; 332*7656SSherry.Moore@Sun.COM 333*7656SSherry.Moore@Sun.COM used_sections++; 334*7656SSherry.Moore@Sun.COM } 335*7656SSherry.Moore@Sun.COM 336*7656SSherry.Moore@Sun.COM } 337*7656SSherry.Moore@Sun.COM 338*7656SSherry.Moore@Sun.COM *sectcntp = used_sections; 339*7656SSherry.Moore@Sun.COM return (0); 340*7656SSherry.Moore@Sun.COM } 341*7656SSherry.Moore@Sun.COM 342*7656SSherry.Moore@Sun.COM /* 343*7656SSherry.Moore@Sun.COM * Create multiboot info structure 344*7656SSherry.Moore@Sun.COM */ 345*7656SSherry.Moore@Sun.COM static int 346*7656SSherry.Moore@Sun.COM fastboot_build_mbi(char *mdep, fastboot_info_t *nk) 347*7656SSherry.Moore@Sun.COM { 348*7656SSherry.Moore@Sun.COM mb_module_t *mbp; 349*7656SSherry.Moore@Sun.COM uintptr_t next_addr; 350*7656SSherry.Moore@Sun.COM uintptr_t new_mbi_pa; 351*7656SSherry.Moore@Sun.COM size_t size; 352*7656SSherry.Moore@Sun.COM void *buf = NULL; 353*7656SSherry.Moore@Sun.COM size_t arglen; 354*7656SSherry.Moore@Sun.COM char bootargs[OBP_MAXPATHLEN]; 355*7656SSherry.Moore@Sun.COM 356*7656SSherry.Moore@Sun.COM bzero(bootargs, OBP_MAXPATHLEN); 357*7656SSherry.Moore@Sun.COM 358*7656SSherry.Moore@Sun.COM if (mdep != NULL) { 359*7656SSherry.Moore@Sun.COM arglen = strlen(mdep) + 1; 360*7656SSherry.Moore@Sun.COM } else { 361*7656SSherry.Moore@Sun.COM arglen = saved_cmdline_len; 362*7656SSherry.Moore@Sun.COM } 363*7656SSherry.Moore@Sun.COM 364*7656SSherry.Moore@Sun.COM size = PAGESIZE + P2ROUNDUP(arglen, PAGESIZE); 365*7656SSherry.Moore@Sun.COM buf = contig_alloc(size, &fastboot_below_1G_dma_attr, PAGESIZE, 0); 366*7656SSherry.Moore@Sun.COM if (buf == NULL) { 367*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, (uint64_t)size, "1G"); 368*7656SSherry.Moore@Sun.COM return (-1); 369*7656SSherry.Moore@Sun.COM } 370*7656SSherry.Moore@Sun.COM 371*7656SSherry.Moore@Sun.COM bzero(buf, size); 372*7656SSherry.Moore@Sun.COM 373*7656SSherry.Moore@Sun.COM new_mbi_pa = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, (caddr_t)buf)); 374*7656SSherry.Moore@Sun.COM 375*7656SSherry.Moore@Sun.COM hat_devload(kas.a_hat, (caddr_t)new_mbi_pa, size, 376*7656SSherry.Moore@Sun.COM mmu_btop(new_mbi_pa), PROT_READ | PROT_WRITE, HAT_LOAD_NOCONSIST); 377*7656SSherry.Moore@Sun.COM 378*7656SSherry.Moore@Sun.COM nk->fi_new_mbi_pa = (paddr_t)new_mbi_pa; 379*7656SSherry.Moore@Sun.COM 380*7656SSherry.Moore@Sun.COM bcopy(&saved_mbi, (void *)new_mbi_pa, sizeof (multiboot_info_t)); 381*7656SSherry.Moore@Sun.COM 382*7656SSherry.Moore@Sun.COM next_addr = new_mbi_pa + sizeof (multiboot_info_t); 383*7656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->mods_addr = next_addr; 384*7656SSherry.Moore@Sun.COM mbp = (mb_module_t *)(uintptr_t)next_addr; 385*7656SSherry.Moore@Sun.COM mbp->mod_start = newkernel.fi_files[FASTBOOT_BOOTARCHIVE].fb_dest_pa; 386*7656SSherry.Moore@Sun.COM mbp->mod_end = newkernel.fi_files[FASTBOOT_BOOTARCHIVE].fb_next_pa; 387*7656SSherry.Moore@Sun.COM 388*7656SSherry.Moore@Sun.COM next_addr += sizeof (mb_module_t); 389*7656SSherry.Moore@Sun.COM bcopy(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE], (void *)next_addr, 390*7656SSherry.Moore@Sun.COM strlen(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE])); 391*7656SSherry.Moore@Sun.COM 392*7656SSherry.Moore@Sun.COM mbp->mod_name = next_addr; 393*7656SSherry.Moore@Sun.COM mbp->reserved = 0; 394*7656SSherry.Moore@Sun.COM next_addr += strlen(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE]); 395*7656SSherry.Moore@Sun.COM *(char *)next_addr = '\0'; 396*7656SSherry.Moore@Sun.COM next_addr++; 397*7656SSherry.Moore@Sun.COM next_addr = P2ROUNDUP_TYPED(next_addr, 16, uintptr_t); 398*7656SSherry.Moore@Sun.COM 399*7656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->mmap_addr = next_addr; 400*7656SSherry.Moore@Sun.COM bcopy((void *)(uintptr_t)saved_mmap, (void *)next_addr, 401*7656SSherry.Moore@Sun.COM saved_mbi.mmap_length); 402*7656SSherry.Moore@Sun.COM next_addr += saved_mbi.mmap_length; 403*7656SSherry.Moore@Sun.COM 404*7656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->drives_addr = next_addr; 405*7656SSherry.Moore@Sun.COM bcopy((void *)(uintptr_t)saved_drives, (void *)next_addr, 406*7656SSherry.Moore@Sun.COM saved_mbi.drives_length); 407*7656SSherry.Moore@Sun.COM next_addr += saved_mbi.drives_length; 408*7656SSherry.Moore@Sun.COM 409*7656SSherry.Moore@Sun.COM ((multiboot_info_t *)new_mbi_pa)->cmdline = next_addr; 410*7656SSherry.Moore@Sun.COM 411*7656SSherry.Moore@Sun.COM if (mdep != NULL) { 412*7656SSherry.Moore@Sun.COM bcopy(mdep, (void *)(uintptr_t) 413*7656SSherry.Moore@Sun.COM (((multiboot_info_t *)new_mbi_pa)->cmdline), (arglen - 1)); 414*7656SSherry.Moore@Sun.COM } else { 415*7656SSherry.Moore@Sun.COM bcopy((void *)saved_cmdline, (void *)next_addr, (arglen - 1)); 416*7656SSherry.Moore@Sun.COM } 417*7656SSherry.Moore@Sun.COM /* Terminate the string */ 418*7656SSherry.Moore@Sun.COM ((char *)(intptr_t)next_addr)[arglen - 1] = '\0'; 419*7656SSherry.Moore@Sun.COM 420*7656SSherry.Moore@Sun.COM return (0); 421*7656SSherry.Moore@Sun.COM } 422*7656SSherry.Moore@Sun.COM 423*7656SSherry.Moore@Sun.COM 424*7656SSherry.Moore@Sun.COM void 425*7656SSherry.Moore@Sun.COM load_kernel(char *mdep) 426*7656SSherry.Moore@Sun.COM { 427*7656SSherry.Moore@Sun.COM struct _buf *file; 428*7656SSherry.Moore@Sun.COM void *buf = NULL; 429*7656SSherry.Moore@Sun.COM uintptr_t va; 430*7656SSherry.Moore@Sun.COM int i, j; 431*7656SSherry.Moore@Sun.COM fastboot_file_t *fb; 432*7656SSherry.Moore@Sun.COM uint32_t dboot_start_offset; 433*7656SSherry.Moore@Sun.COM Ehdr *ehdr; 434*7656SSherry.Moore@Sun.COM char kern_bootpath[OBP_MAXPATHLEN]; 435*7656SSherry.Moore@Sun.COM char bootargs[OBP_MAXPATHLEN]; 436*7656SSherry.Moore@Sun.COM extern uintptr_t postbootkernelbase; 437*7656SSherry.Moore@Sun.COM extern char fb_swtch_image[]; 438*7656SSherry.Moore@Sun.COM int bootpath_len = 0; 439*7656SSherry.Moore@Sun.COM int is_failsafe = 0; 440*7656SSherry.Moore@Sun.COM uintptr_t next_pa = 0; /* next available physical addr */ 441*7656SSherry.Moore@Sun.COM 442*7656SSherry.Moore@Sun.COM ASSERT(fastreboot_capable); 443*7656SSherry.Moore@Sun.COM 444*7656SSherry.Moore@Sun.COM postbootkernelbase = 0; 445*7656SSherry.Moore@Sun.COM 446*7656SSherry.Moore@Sun.COM if (x86_feature & X86_PAE) { 447*7656SSherry.Moore@Sun.COM newkernel.fi_has_pae = 1; 448*7656SSherry.Moore@Sun.COM newkernel.fi_shift_amt = fastboot_shift_amt_pae; 449*7656SSherry.Moore@Sun.COM newkernel.fi_ptes_per_table = 512; 450*7656SSherry.Moore@Sun.COM newkernel.fi_lpagesize = (2 << 20); /* 2M */ 451*7656SSherry.Moore@Sun.COM newkernel.fi_top_level = 2; 452*7656SSherry.Moore@Sun.COM } 453*7656SSherry.Moore@Sun.COM 454*7656SSherry.Moore@Sun.COM bzero(kern_bootpath, OBP_MAXPATHLEN); 455*7656SSherry.Moore@Sun.COM bzero(bootargs, OBP_MAXPATHLEN); 456*7656SSherry.Moore@Sun.COM 457*7656SSherry.Moore@Sun.COM /* 458*7656SSherry.Moore@Sun.COM * If mdep is not NULL, it comes in the format of 459*7656SSherry.Moore@Sun.COM * mountpoint unix args 460*7656SSherry.Moore@Sun.COM */ 461*7656SSherry.Moore@Sun.COM if (mdep != NULL) { 462*7656SSherry.Moore@Sun.COM if (mdep[0] != '-') { 463*7656SSherry.Moore@Sun.COM /* First get the root argument */ 464*7656SSherry.Moore@Sun.COM i = 0; 465*7656SSherry.Moore@Sun.COM while (mdep[i] != '\0' && mdep[i] != ' ') { 466*7656SSherry.Moore@Sun.COM i++; 467*7656SSherry.Moore@Sun.COM } 468*7656SSherry.Moore@Sun.COM 469*7656SSherry.Moore@Sun.COM if (i < 4 || strncmp(&mdep[i-4], "unix", 4) != 0) { 470*7656SSherry.Moore@Sun.COM /* mount point */ 471*7656SSherry.Moore@Sun.COM bcopy(mdep, kern_bootpath, i); 472*7656SSherry.Moore@Sun.COM kern_bootpath[i] = '\0'; 473*7656SSherry.Moore@Sun.COM bootpath_len = i; 474*7656SSherry.Moore@Sun.COM 475*7656SSherry.Moore@Sun.COM /* 476*7656SSherry.Moore@Sun.COM * Get the next argument. It should be unix as 477*7656SSherry.Moore@Sun.COM * we have validated in in halt.c. 478*7656SSherry.Moore@Sun.COM */ 479*7656SSherry.Moore@Sun.COM if (strlen(mdep) > i) { 480*7656SSherry.Moore@Sun.COM mdep += (i + 1); 481*7656SSherry.Moore@Sun.COM i = 0; 482*7656SSherry.Moore@Sun.COM while (mdep[i] != '\0' && 483*7656SSherry.Moore@Sun.COM mdep[i] != ' ') { 484*7656SSherry.Moore@Sun.COM i++; 485*7656SSherry.Moore@Sun.COM } 486*7656SSherry.Moore@Sun.COM } 487*7656SSherry.Moore@Sun.COM 488*7656SSherry.Moore@Sun.COM } 489*7656SSherry.Moore@Sun.COM bcopy(mdep, kern_bootfile, i); 490*7656SSherry.Moore@Sun.COM kern_bootfile[i] = '\0'; 491*7656SSherry.Moore@Sun.COM } else { 492*7656SSherry.Moore@Sun.COM int off = strlen(kern_bootfile); 493*7656SSherry.Moore@Sun.COM bcopy(kern_bootfile, bootargs, off); 494*7656SSherry.Moore@Sun.COM bcopy(" ", &bootargs[off++], 1); 495*7656SSherry.Moore@Sun.COM bcopy(mdep, &bootargs[off], strlen(mdep)); 496*7656SSherry.Moore@Sun.COM off += strlen(mdep); 497*7656SSherry.Moore@Sun.COM bootargs[off] = '\0'; 498*7656SSherry.Moore@Sun.COM mdep = bootargs; 499*7656SSherry.Moore@Sun.COM } 500*7656SSherry.Moore@Sun.COM } 501*7656SSherry.Moore@Sun.COM 502*7656SSherry.Moore@Sun.COM /* 503*7656SSherry.Moore@Sun.COM * Make sure we get the null character 504*7656SSherry.Moore@Sun.COM */ 505*7656SSherry.Moore@Sun.COM bcopy(kern_bootpath, fastboot_filename[FASTBOOT_NAME_UNIX], 506*7656SSherry.Moore@Sun.COM bootpath_len); 507*7656SSherry.Moore@Sun.COM bcopy(kern_bootfile, 508*7656SSherry.Moore@Sun.COM &fastboot_filename[FASTBOOT_NAME_UNIX][bootpath_len], 509*7656SSherry.Moore@Sun.COM strlen(kern_bootfile) + 1); 510*7656SSherry.Moore@Sun.COM 511*7656SSherry.Moore@Sun.COM bcopy(kern_bootpath, fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE], 512*7656SSherry.Moore@Sun.COM bootpath_len); 513*7656SSherry.Moore@Sun.COM 514*7656SSherry.Moore@Sun.COM if (bcmp(kern_bootfile, FAILSAFE_BOOTFILE, 515*7656SSherry.Moore@Sun.COM (sizeof (FAILSAFE_BOOTFILE) - 1)) == 0) { 516*7656SSherry.Moore@Sun.COM is_failsafe = 1; 517*7656SSherry.Moore@Sun.COM } 518*7656SSherry.Moore@Sun.COM 519*7656SSherry.Moore@Sun.COM /* 520*7656SSherry.Moore@Sun.COM * Read in unix and boot_archive 521*7656SSherry.Moore@Sun.COM */ 522*7656SSherry.Moore@Sun.COM for (i = 0; i < FASTBOOT_MAX_FILES_MAP; i++) { 523*7656SSherry.Moore@Sun.COM uint64_t fsize; 524*7656SSherry.Moore@Sun.COM size_t fsize_roundup, pt_size; 525*7656SSherry.Moore@Sun.COM int page_index; 526*7656SSherry.Moore@Sun.COM uintptr_t offset; 527*7656SSherry.Moore@Sun.COM int pt_entry_count; 528*7656SSherry.Moore@Sun.COM ddi_dma_attr_t dma_attr = fastboot_dma_attr; 529*7656SSherry.Moore@Sun.COM 530*7656SSherry.Moore@Sun.COM dprintf("fastboot_filename[%d] = %s\n", 531*7656SSherry.Moore@Sun.COM i, fastboot_filename[i]); 532*7656SSherry.Moore@Sun.COM 533*7656SSherry.Moore@Sun.COM if ((file = kobj_open_file(fastboot_filename[i])) == 534*7656SSherry.Moore@Sun.COM (struct _buf *)-1) { 535*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Couldn't open %s", 536*7656SSherry.Moore@Sun.COM fastboot_filename[i]); 537*7656SSherry.Moore@Sun.COM goto err_out; 538*7656SSherry.Moore@Sun.COM } 539*7656SSherry.Moore@Sun.COM 540*7656SSherry.Moore@Sun.COM if (kobj_get_filesize(file, &fsize) != 0) { 541*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, 542*7656SSherry.Moore@Sun.COM "Fastboot: Couldn't get filesize for %s", 543*7656SSherry.Moore@Sun.COM fastboot_filename[i]); 544*7656SSherry.Moore@Sun.COM goto err_out; 545*7656SSherry.Moore@Sun.COM } 546*7656SSherry.Moore@Sun.COM 547*7656SSherry.Moore@Sun.COM if (i == FASTBOOT_BOOTARCHIVE && is_failsafe) { 548*7656SSherry.Moore@Sun.COM /* Adjust low memory for failsafe mode */ 549*7656SSherry.Moore@Sun.COM fastboot_below_1G_dma_attr.dma_attr_addr_lo = 550*7656SSherry.Moore@Sun.COM dma_attr.dma_attr_addr_lo = 551*7656SSherry.Moore@Sun.COM P2ROUNDUP_TYPED(fsize, PAGESIZE, uint64_t) + 552*7656SSherry.Moore@Sun.COM next_pa; 553*7656SSherry.Moore@Sun.COM } 554*7656SSherry.Moore@Sun.COM 555*7656SSherry.Moore@Sun.COM if (!fastboot_contig) 556*7656SSherry.Moore@Sun.COM dma_attr.dma_attr_sgllen = (fsize / PAGESIZE) + 557*7656SSherry.Moore@Sun.COM (((fsize % PAGESIZE) == 0) ? 0 : 1); 558*7656SSherry.Moore@Sun.COM 559*7656SSherry.Moore@Sun.COM if ((buf = contig_alloc(fsize, &dma_attr, PAGESIZE, 0)) 560*7656SSherry.Moore@Sun.COM == NULL) { 561*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, fsize, 562*7656SSherry.Moore@Sun.COM "64G"); 563*7656SSherry.Moore@Sun.COM goto err_out; 564*7656SSherry.Moore@Sun.COM } 565*7656SSherry.Moore@Sun.COM 566*7656SSherry.Moore@Sun.COM va = P2ROUNDUP_TYPED((uintptr_t)buf, PAGESIZE, uintptr_t); 567*7656SSherry.Moore@Sun.COM 568*7656SSherry.Moore@Sun.COM if (kobj_read_file(file, (char *)va, fsize, 0) < 0) { 569*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Couldn't read %s", 570*7656SSherry.Moore@Sun.COM fastboot_filename[i]); 571*7656SSherry.Moore@Sun.COM goto err_out; 572*7656SSherry.Moore@Sun.COM } 573*7656SSherry.Moore@Sun.COM 574*7656SSherry.Moore@Sun.COM fb = &newkernel.fi_files[i]; 575*7656SSherry.Moore@Sun.COM fb->fb_va = va; 576*7656SSherry.Moore@Sun.COM fb->fb_size = fsize; 577*7656SSherry.Moore@Sun.COM fb->fb_sectcnt = 0; 578*7656SSherry.Moore@Sun.COM 579*7656SSherry.Moore@Sun.COM fsize_roundup = P2ROUNDUP_TYPED(fb->fb_size, PAGESIZE, size_t); 580*7656SSherry.Moore@Sun.COM 581*7656SSherry.Moore@Sun.COM /* 582*7656SSherry.Moore@Sun.COM * Allocate one extra page table entry for terminating 583*7656SSherry.Moore@Sun.COM * the list. 584*7656SSherry.Moore@Sun.COM */ 585*7656SSherry.Moore@Sun.COM pt_entry_count = (fsize_roundup >> PAGESHIFT) + 1; 586*7656SSherry.Moore@Sun.COM pt_size = P2ROUNDUP(pt_entry_count * 8, PAGESIZE); 587*7656SSherry.Moore@Sun.COM 588*7656SSherry.Moore@Sun.COM if ((fb->fb_pte_list_va = 589*7656SSherry.Moore@Sun.COM (x86pte_t *)contig_alloc(pt_size, 590*7656SSherry.Moore@Sun.COM &fastboot_below_1G_dma_attr, PAGESIZE, 0)) == NULL) { 591*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, 592*7656SSherry.Moore@Sun.COM (uint64_t)pt_size, "1G"); 593*7656SSherry.Moore@Sun.COM goto err_out; 594*7656SSherry.Moore@Sun.COM } 595*7656SSherry.Moore@Sun.COM 596*7656SSherry.Moore@Sun.COM bzero((void *)(fb->fb_pte_list_va), pt_size); 597*7656SSherry.Moore@Sun.COM 598*7656SSherry.Moore@Sun.COM fb->fb_pte_list_pa = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, 599*7656SSherry.Moore@Sun.COM (caddr_t)fb->fb_pte_list_va)); 600*7656SSherry.Moore@Sun.COM 601*7656SSherry.Moore@Sun.COM for (page_index = 0, offset = 0; offset < fb->fb_size; 602*7656SSherry.Moore@Sun.COM offset += PAGESIZE) { 603*7656SSherry.Moore@Sun.COM uint64_t paddr; 604*7656SSherry.Moore@Sun.COM 605*7656SSherry.Moore@Sun.COM paddr = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, 606*7656SSherry.Moore@Sun.COM (caddr_t)fb->fb_va + offset)); 607*7656SSherry.Moore@Sun.COM 608*7656SSherry.Moore@Sun.COM ASSERT(paddr >= fastboot_dma_attr.dma_attr_addr_lo); 609*7656SSherry.Moore@Sun.COM 610*7656SSherry.Moore@Sun.COM /* 611*7656SSherry.Moore@Sun.COM * Include the pte_bits so we don't have to make 612*7656SSherry.Moore@Sun.COM * it in assembly. 613*7656SSherry.Moore@Sun.COM */ 614*7656SSherry.Moore@Sun.COM fb->fb_pte_list_va[page_index++] = (x86pte_t) 615*7656SSherry.Moore@Sun.COM (paddr | pte_bits); 616*7656SSherry.Moore@Sun.COM } 617*7656SSherry.Moore@Sun.COM 618*7656SSherry.Moore@Sun.COM fb->fb_pte_list_va[page_index] = FASTBOOT_TERMINATE; 619*7656SSherry.Moore@Sun.COM 620*7656SSherry.Moore@Sun.COM if (i == FASTBOOT_UNIX) { 621*7656SSherry.Moore@Sun.COM ehdr = (Ehdr *)va; 622*7656SSherry.Moore@Sun.COM 623*7656SSherry.Moore@Sun.COM /* 624*7656SSherry.Moore@Sun.COM * Sanity checks: 625*7656SSherry.Moore@Sun.COM */ 626*7656SSherry.Moore@Sun.COM for (j = 0; j < SELFMAG; j++) { 627*7656SSherry.Moore@Sun.COM if (ehdr->e_ident[j] != ELFMAG[j]) { 628*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Bad ELF " 629*7656SSherry.Moore@Sun.COM "signature"); 630*7656SSherry.Moore@Sun.COM goto err_out; 631*7656SSherry.Moore@Sun.COM } 632*7656SSherry.Moore@Sun.COM } 633*7656SSherry.Moore@Sun.COM 634*7656SSherry.Moore@Sun.COM if (ehdr->e_ident[EI_CLASS] == ELFCLASS32 && 635*7656SSherry.Moore@Sun.COM ehdr->e_ident[EI_DATA] == ELFDATA2LSB && 636*7656SSherry.Moore@Sun.COM ehdr->e_machine == EM_386) { 637*7656SSherry.Moore@Sun.COM 638*7656SSherry.Moore@Sun.COM if (fastboot_elf32_find_loadables((void *)va, 639*7656SSherry.Moore@Sun.COM fsize, &fb->fb_sections[0], 640*7656SSherry.Moore@Sun.COM &fb->fb_sectcnt, &dboot_start_offset) < 0) { 641*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: ELF32 " 642*7656SSherry.Moore@Sun.COM "program section failure"); 643*7656SSherry.Moore@Sun.COM goto err_out; 644*7656SSherry.Moore@Sun.COM } 645*7656SSherry.Moore@Sun.COM 646*7656SSherry.Moore@Sun.COM if (fb->fb_sectcnt == 0) { 647*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: No ELF32 " 648*7656SSherry.Moore@Sun.COM "program sections found"); 649*7656SSherry.Moore@Sun.COM goto err_out; 650*7656SSherry.Moore@Sun.COM } 651*7656SSherry.Moore@Sun.COM 652*7656SSherry.Moore@Sun.COM if (is_failsafe) { 653*7656SSherry.Moore@Sun.COM /* Failsafe boot_archive */ 654*7656SSherry.Moore@Sun.COM bcopy(BOOTARCHIVE_FAILSAFE, 655*7656SSherry.Moore@Sun.COM &fastboot_filename 656*7656SSherry.Moore@Sun.COM [FASTBOOT_NAME_BOOTARCHIVE] 657*7656SSherry.Moore@Sun.COM [bootpath_len], 658*7656SSherry.Moore@Sun.COM sizeof (BOOTARCHIVE_FAILSAFE)); 659*7656SSherry.Moore@Sun.COM } else { 660*7656SSherry.Moore@Sun.COM bcopy(BOOTARCHIVE32, 661*7656SSherry.Moore@Sun.COM &fastboot_filename 662*7656SSherry.Moore@Sun.COM [FASTBOOT_NAME_BOOTARCHIVE] 663*7656SSherry.Moore@Sun.COM [bootpath_len], 664*7656SSherry.Moore@Sun.COM sizeof (BOOTARCHIVE32)); 665*7656SSherry.Moore@Sun.COM } 666*7656SSherry.Moore@Sun.COM 667*7656SSherry.Moore@Sun.COM } else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64 && 668*7656SSherry.Moore@Sun.COM ehdr->e_ident[EI_DATA] == ELFDATA2LSB && 669*7656SSherry.Moore@Sun.COM ehdr->e_machine == EM_AMD64) { 670*7656SSherry.Moore@Sun.COM 671*7656SSherry.Moore@Sun.COM if (fastboot_elf64_find_dboot_load_offset( 672*7656SSherry.Moore@Sun.COM (void *)va, fsize, &dboot_start_offset) 673*7656SSherry.Moore@Sun.COM != 0) { 674*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Couldn't " 675*7656SSherry.Moore@Sun.COM "find ELF64 dboot entry offset"); 676*7656SSherry.Moore@Sun.COM goto err_out; 677*7656SSherry.Moore@Sun.COM } 678*7656SSherry.Moore@Sun.COM 679*7656SSherry.Moore@Sun.COM if ((x86_feature & X86_64) == 0 || 680*7656SSherry.Moore@Sun.COM newkernel.fi_has_pae == 0) { 681*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Cannot " 682*7656SSherry.Moore@Sun.COM "reboot to %s: " 683*7656SSherry.Moore@Sun.COM "not a 64-bit capable system", 684*7656SSherry.Moore@Sun.COM kern_bootfile); 685*7656SSherry.Moore@Sun.COM goto err_out; 686*7656SSherry.Moore@Sun.COM } 687*7656SSherry.Moore@Sun.COM 688*7656SSherry.Moore@Sun.COM bcopy(BOOTARCHIVE64, 689*7656SSherry.Moore@Sun.COM &fastboot_filename 690*7656SSherry.Moore@Sun.COM [FASTBOOT_NAME_BOOTARCHIVE][bootpath_len], 691*7656SSherry.Moore@Sun.COM sizeof (BOOTARCHIVE64)); 692*7656SSherry.Moore@Sun.COM } else { 693*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "Fastboot: Unknown ELF type"); 694*7656SSherry.Moore@Sun.COM goto err_out; 695*7656SSherry.Moore@Sun.COM } 696*7656SSherry.Moore@Sun.COM 697*7656SSherry.Moore@Sun.COM fb->fb_dest_pa = DBOOT_ENTRY_ADDRESS - 698*7656SSherry.Moore@Sun.COM dboot_start_offset; 699*7656SSherry.Moore@Sun.COM 700*7656SSherry.Moore@Sun.COM fb->fb_next_pa = DBOOT_ENTRY_ADDRESS + fsize_roundup; 701*7656SSherry.Moore@Sun.COM } else { 702*7656SSherry.Moore@Sun.COM fb->fb_dest_pa = newkernel.fi_files[i - 1].fb_next_pa; 703*7656SSherry.Moore@Sun.COM fb->fb_next_pa = fb->fb_dest_pa + fsize_roundup; 704*7656SSherry.Moore@Sun.COM } 705*7656SSherry.Moore@Sun.COM 706*7656SSherry.Moore@Sun.COM next_pa = fb->fb_next_pa; 707*7656SSherry.Moore@Sun.COM 708*7656SSherry.Moore@Sun.COM kobj_close_file(file); 709*7656SSherry.Moore@Sun.COM 710*7656SSherry.Moore@Sun.COM /* 711*7656SSherry.Moore@Sun.COM * Set fb_va to fake_va 712*7656SSherry.Moore@Sun.COM */ 713*7656SSherry.Moore@Sun.COM fb->fb_va = fake_va; 714*7656SSherry.Moore@Sun.COM } 715*7656SSherry.Moore@Sun.COM 716*7656SSherry.Moore@Sun.COM 717*7656SSherry.Moore@Sun.COM /* 718*7656SSherry.Moore@Sun.COM * Add the function that will switch us to 32-bit protected mode 719*7656SSherry.Moore@Sun.COM */ 720*7656SSherry.Moore@Sun.COM fb = &newkernel.fi_files[FASTBOOT_SWTCH]; 721*7656SSherry.Moore@Sun.COM fb->fb_va = fb->fb_dest_pa = FASTBOOT_SWTCH_PA; 722*7656SSherry.Moore@Sun.COM fb->fb_size = PAGESIZE; 723*7656SSherry.Moore@Sun.COM 724*7656SSherry.Moore@Sun.COM /* 725*7656SSherry.Moore@Sun.COM * Map in FASTBOOT_SWTCH_PA 726*7656SSherry.Moore@Sun.COM */ 727*7656SSherry.Moore@Sun.COM hat_devload(kas.a_hat, (caddr_t)fb->fb_va, MMU_PAGESIZE, 728*7656SSherry.Moore@Sun.COM mmu_btop(fb->fb_dest_pa), 729*7656SSherry.Moore@Sun.COM PROT_READ | PROT_WRITE | PROT_EXEC, HAT_LOAD_NOCONSIST); 730*7656SSherry.Moore@Sun.COM 731*7656SSherry.Moore@Sun.COM bcopy((void *)fb_swtch_image, (void *)fb->fb_va, fb->fb_size); 732*7656SSherry.Moore@Sun.COM 733*7656SSherry.Moore@Sun.COM /* 734*7656SSherry.Moore@Sun.COM * Build the new multiboot_info structure 735*7656SSherry.Moore@Sun.COM */ 736*7656SSherry.Moore@Sun.COM if (fastboot_build_mbi(mdep, &newkernel) != 0) { 737*7656SSherry.Moore@Sun.COM goto err_out; 738*7656SSherry.Moore@Sun.COM } 739*7656SSherry.Moore@Sun.COM 740*7656SSherry.Moore@Sun.COM /* 741*7656SSherry.Moore@Sun.COM * Build page table for low 1G physical memory. Use big pages. 742*7656SSherry.Moore@Sun.COM * Allocate 4 pages for the page tables. 743*7656SSherry.Moore@Sun.COM * 1 page for Page-Directory-Pointer Table 744*7656SSherry.Moore@Sun.COM * 2 page for Page Directory 745*7656SSherry.Moore@Sun.COM * 1 page for Page Table. 746*7656SSherry.Moore@Sun.COM * The page table entry will be rewritten to map the physical 747*7656SSherry.Moore@Sun.COM * address as we do the copying. 748*7656SSherry.Moore@Sun.COM */ 749*7656SSherry.Moore@Sun.COM if (newkernel.fi_has_pae) { 750*7656SSherry.Moore@Sun.COM size_t size = MMU_PAGESIZE * 4; 751*7656SSherry.Moore@Sun.COM 752*7656SSherry.Moore@Sun.COM if ((newkernel.fi_pagetable_va = (uintptr_t) 753*7656SSherry.Moore@Sun.COM contig_alloc(size, &fastboot_below_1G_dma_attr, 754*7656SSherry.Moore@Sun.COM PAGESIZE, 0)) == NULL) { 755*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, fastboot_enomem_msg, 756*7656SSherry.Moore@Sun.COM (uint64_t)size, "1G"); 757*7656SSherry.Moore@Sun.COM goto err_out; 758*7656SSherry.Moore@Sun.COM } 759*7656SSherry.Moore@Sun.COM 760*7656SSherry.Moore@Sun.COM bzero((void *)(newkernel.fi_pagetable_va), size); 761*7656SSherry.Moore@Sun.COM 762*7656SSherry.Moore@Sun.COM newkernel.fi_pagetable_pa = 763*7656SSherry.Moore@Sun.COM mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, 764*7656SSherry.Moore@Sun.COM (caddr_t)newkernel.fi_pagetable_va)); 765*7656SSherry.Moore@Sun.COM 766*7656SSherry.Moore@Sun.COM newkernel.fi_last_table_pa = newkernel.fi_pagetable_pa + 767*7656SSherry.Moore@Sun.COM MMU_PAGESIZE * 3; 768*7656SSherry.Moore@Sun.COM 769*7656SSherry.Moore@Sun.COM newkernel.fi_next_table_va = newkernel.fi_pagetable_va + 770*7656SSherry.Moore@Sun.COM MMU_PAGESIZE; 771*7656SSherry.Moore@Sun.COM newkernel.fi_next_table_pa = newkernel.fi_pagetable_pa + 772*7656SSherry.Moore@Sun.COM MMU_PAGESIZE; 773*7656SSherry.Moore@Sun.COM 774*7656SSherry.Moore@Sun.COM fastboot_build_pagetables(&newkernel); 775*7656SSherry.Moore@Sun.COM } 776*7656SSherry.Moore@Sun.COM 777*7656SSherry.Moore@Sun.COM 778*7656SSherry.Moore@Sun.COM /* Mark it as valid */ 779*7656SSherry.Moore@Sun.COM newkernel.fi_valid = 1; 780*7656SSherry.Moore@Sun.COM newkernel.fi_magic = FASTBOOT_MAGIC; 781*7656SSherry.Moore@Sun.COM 782*7656SSherry.Moore@Sun.COM return; 783*7656SSherry.Moore@Sun.COM 784*7656SSherry.Moore@Sun.COM err_out: 785*7656SSherry.Moore@Sun.COM /* XXX Do we need to free up the memory we allocated? */ 786*7656SSherry.Moore@Sun.COM 787*7656SSherry.Moore@Sun.COM newkernel.fi_valid = 0; 788*7656SSherry.Moore@Sun.COM } 789*7656SSherry.Moore@Sun.COM 790*7656SSherry.Moore@Sun.COM 791*7656SSherry.Moore@Sun.COM void 792*7656SSherry.Moore@Sun.COM fast_reboot() 793*7656SSherry.Moore@Sun.COM { 794*7656SSherry.Moore@Sun.COM void (*fastboot_func)(fastboot_info_t *); 795*7656SSherry.Moore@Sun.COM 796*7656SSherry.Moore@Sun.COM fastboot_func = (void (*)())(newkernel.fi_files[FASTBOOT_SWTCH].fb_va); 797*7656SSherry.Moore@Sun.COM (*fastboot_func)(&newkernel); 798*7656SSherry.Moore@Sun.COM } 799