17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5986fd29aSsetje * Common Development and Distribution License (the "License"). 6986fd29aSsetje * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*ca622e3aSsvemuri * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Definitions of interfaces that provide services from the secondary 307c478bd9Sstevel@tonic-gate * boot program to its clients (primarily Solaris, krtld, kmdb and their 317c478bd9Sstevel@tonic-gate * successors.) This interface replaces the bootops (BOP) implementation 327c478bd9Sstevel@tonic-gate * as the interface to be called by boot clients. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <sys/types.h> 37986fd29aSsetje #include <sys/systm.h> 387c478bd9Sstevel@tonic-gate #include <sys/reboot.h> 397c478bd9Sstevel@tonic-gate #include <sys/param.h> 407c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 417c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h> 42986fd29aSsetje #include <sys/promimpl.h> 43986fd29aSsetje #include <sys/prom_plat.h> 447c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 457c478bd9Sstevel@tonic-gate #include <sys/bootstat.h> 46986fd29aSsetje #include <sys/kobj_impl.h> 477c478bd9Sstevel@tonic-gate 48986fd29aSsetje struct bootops *bootops; 49986fd29aSsetje struct bootops kbootops; 50986fd29aSsetje 51986fd29aSsetje pnode_t chosennode; 52986fd29aSsetje 53986fd29aSsetje #define FAKE_ROOT (pnode_t)1 54986fd29aSsetje 55986fd29aSsetje struct fakeprop { 56986fd29aSsetje char *bootname; 57986fd29aSsetje pnode_t promnode; 58986fd29aSsetje char *promname; 59986fd29aSsetje } fakeprops[] = { 60986fd29aSsetje { "mfg-name", FAKE_ROOT, "name" }, 61986fd29aSsetje { NULL, 0, NULL } 62986fd29aSsetje }; 63986fd29aSsetje 64986fd29aSsetje static void 65986fd29aSsetje fakelook_init(void) 667c478bd9Sstevel@tonic-gate { 67986fd29aSsetje struct fakeprop *fpp = fakeprops; 68986fd29aSsetje 69986fd29aSsetje while (fpp->bootname != NULL) { 70986fd29aSsetje switch (fpp->promnode) { 71986fd29aSsetje case FAKE_ROOT: 72986fd29aSsetje fpp->promnode = prom_rootnode(); 73986fd29aSsetje break; 74986fd29aSsetje } 75986fd29aSsetje fpp++; 76986fd29aSsetje } 777c478bd9Sstevel@tonic-gate } 787c478bd9Sstevel@tonic-gate 79986fd29aSsetje static struct fakeprop * 80986fd29aSsetje fakelook(const char *prop) 81986fd29aSsetje { 82986fd29aSsetje struct fakeprop *fpp = fakeprops; 83986fd29aSsetje 84986fd29aSsetje while (fpp->bootname != NULL) { 85986fd29aSsetje if (strcmp(prop, fpp->bootname) == 0) 86986fd29aSsetje return (fpp); 87986fd29aSsetje fpp++; 88986fd29aSsetje } 89986fd29aSsetje return (NULL); 90986fd29aSsetje } 91986fd29aSsetje 92986fd29aSsetje ihandle_t bfs_ih = OBP_BADNODE; 93986fd29aSsetje ihandle_t afs_ih = OBP_BADNODE; 94986fd29aSsetje 95986fd29aSsetje void 96986fd29aSsetje bop_init(void) 97986fd29aSsetje { 98986fd29aSsetje chosennode = prom_chosennode(); 99986fd29aSsetje 100986fd29aSsetje fakelook_init(); 101986fd29aSsetje 102986fd29aSsetje /* fake bootops - it needs to point to non-NULL */ 103986fd29aSsetje bootops = &kbootops; 104986fd29aSsetje } 105986fd29aSsetje 106986fd29aSsetje #define MAXPROMFD 16 107986fd29aSsetje 108986fd29aSsetje static ihandle_t prom_ihs[MAXPROMFD]; 109986fd29aSsetje int filter_etc = 1; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* 1127c478bd9Sstevel@tonic-gate * Implementation of the "open" boot service. 1137c478bd9Sstevel@tonic-gate */ 114986fd29aSsetje /*ARGSUSED*/ 1157c478bd9Sstevel@tonic-gate int 116986fd29aSsetje bop_open(const char *name, int flags) 1177c478bd9Sstevel@tonic-gate { 118986fd29aSsetje int fd = -1, layered; 119986fd29aSsetje ihandle_t ih; 1207c478bd9Sstevel@tonic-gate 121986fd29aSsetje /* 122986fd29aSsetje * Only look underneath archive for /etc files 123986fd29aSsetje */ 124986fd29aSsetje layered = filter_etc ? 125986fd29aSsetje strncmp(name, "/etc", sizeof ("/etc") - 1) == 0 : 1; 1267c478bd9Sstevel@tonic-gate 127986fd29aSsetje if (afs_ih != OBP_BADNODE) { 128986fd29aSsetje ih = afs_ih; 129986fd29aSsetje fd = prom_fopen(ih, (char *)name); 130986fd29aSsetje if (fd == -1 && !layered) 131986fd29aSsetje return (BOOT_SVC_FAIL); 132986fd29aSsetje } 133986fd29aSsetje if (fd == -1 && bfs_ih != OBP_BADNODE) { 134986fd29aSsetje ih = bfs_ih; 135986fd29aSsetje fd = prom_fopen(ih, (char *)name); 136986fd29aSsetje } 137986fd29aSsetje if (fd == -1) 138986fd29aSsetje return (BOOT_SVC_FAIL); 139986fd29aSsetje ASSERT(fd < MAXPROMFD); 140986fd29aSsetje ASSERT(prom_ihs[fd] == 0); 141986fd29aSsetje prom_ihs[fd] = ih; 142986fd29aSsetje return (fd); 143986fd29aSsetje } 144986fd29aSsetje 145986fd29aSsetje static void 146986fd29aSsetje spinner(void) 147986fd29aSsetje { 148986fd29aSsetje static int pos; 149986fd29aSsetje static char ind[] = "|/-\\"; /* that's entertainment? */ 150986fd29aSsetje static int blks_read; 151986fd29aSsetje 152986fd29aSsetje if ((blks_read++ & 0x3) == 0) 153986fd29aSsetje prom_printf("%c\b", ind[pos++ & 3]); 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* 1577c478bd9Sstevel@tonic-gate * Implementation of the "read" boot service. 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate int 160986fd29aSsetje bop_read(int fd, caddr_t buf, size_t size) 1617c478bd9Sstevel@tonic-gate { 162986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 163986fd29aSsetje spinner(); 164986fd29aSsetje return (prom_fread(prom_ihs[fd], fd, buf, size)); 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Implementation of the "seek" boot service. 1697c478bd9Sstevel@tonic-gate */ 1707c478bd9Sstevel@tonic-gate int 171986fd29aSsetje bop_seek(int fd, off_t off) 1727c478bd9Sstevel@tonic-gate { 173986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 174986fd29aSsetje return (prom_fseek(prom_ihs[fd], fd, off)); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate * Implementation of the "close" boot service. 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate int 181986fd29aSsetje bop_close(int fd) 1827c478bd9Sstevel@tonic-gate { 183986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 184986fd29aSsetje prom_fclose(prom_ihs[fd], fd); 185986fd29aSsetje prom_ihs[fd] = 0; 186986fd29aSsetje return (0); 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* 190986fd29aSsetje * Simple temp memory allocator 1917c478bd9Sstevel@tonic-gate * 192986fd29aSsetje * >PAGESIZE allocations are gotten directly from prom at bighand 193986fd29aSsetje * smaller ones are satisfied from littlehand, which does a 194986fd29aSsetje * 1 page bighand allocation when it runs out of memory 195986fd29aSsetje */ 196986fd29aSsetje static caddr_t bighand = (caddr_t)BOOTTMPBASE; 197986fd29aSsetje static caddr_t littlehand = (caddr_t)BOOTTMPBASE; 198986fd29aSsetje 199986fd29aSsetje #define NTMPALLOC 128 200986fd29aSsetje 201986fd29aSsetje static caddr_t temp_base[NTMPALLOC]; 202986fd29aSsetje static size_t temp_size[NTMPALLOC]; 203986fd29aSsetje static int temp_indx; 204986fd29aSsetje 205986fd29aSsetje #if defined(C_OBP) 206986fd29aSsetje void cobp_free_mem(caddr_t, size_t); 207986fd29aSsetje #endif /* C_OBP */ 208986fd29aSsetje 209986fd29aSsetje 210986fd29aSsetje /* 211986fd29aSsetje * temporary memory storage until bop_tmp_freeall is called 212986fd29aSsetje * (after the kernel heap is initialized) 2137c478bd9Sstevel@tonic-gate */ 2147c478bd9Sstevel@tonic-gate caddr_t 215986fd29aSsetje bop_temp_alloc(size_t size, int align) 2167c478bd9Sstevel@tonic-gate { 217986fd29aSsetje caddr_t ret; 2187c478bd9Sstevel@tonic-gate 219986fd29aSsetje /* 220986fd29aSsetje * OBP allocs 10MB to boot, which is where virthint = 0 221986fd29aSsetje * memory was allocated from. Without boot, we allocate 222986fd29aSsetje * from BOOTTMPBASE and free when we're ready to take 223986fd29aSsetje * the machine from OBP 224986fd29aSsetje */ 225986fd29aSsetje if (size < PAGESIZE) { 226986fd29aSsetje size_t left = 227986fd29aSsetje ALIGN(littlehand, PAGESIZE) - (uintptr_t)littlehand; 2287c478bd9Sstevel@tonic-gate 229986fd29aSsetje size = roundup(size, MAX(align, 8)); 230986fd29aSsetje if (size <= left) { 231986fd29aSsetje ret = littlehand; 232986fd29aSsetje littlehand += size; 233986fd29aSsetje return (ret); 234986fd29aSsetje } 235986fd29aSsetje littlehand = bighand + size; 236986fd29aSsetje } 237986fd29aSsetje size = roundup(size, PAGESIZE); 238986fd29aSsetje ret = prom_alloc(bighand, size, align); 239986fd29aSsetje if (ret == NULL) 240986fd29aSsetje prom_panic("boot temp overflow"); 241986fd29aSsetje bighand += size; 242986fd29aSsetje 243986fd29aSsetje /* log it for bop_fini() */ 244986fd29aSsetje temp_base[temp_indx] = ret; 245986fd29aSsetje temp_size[temp_indx] = size; 246986fd29aSsetje if (++temp_indx == NTMPALLOC) 247986fd29aSsetje prom_panic("out of bop temp space"); 248986fd29aSsetje 249986fd29aSsetje return (ret); 250986fd29aSsetje } 251986fd29aSsetje 252986fd29aSsetje void 253986fd29aSsetje bop_temp_freeall(void) 254986fd29aSsetje { 255986fd29aSsetje int i; 256986fd29aSsetje 257986fd29aSsetje /* 258986fd29aSsetje * We have to call prom_free() with the same args 259986fd29aSsetje * as we used in prom_alloc() 260986fd29aSsetje */ 261986fd29aSsetje for (i = 0; i < NTMPALLOC; i++) { 262986fd29aSsetje if (temp_base[i] == NULL) 263986fd29aSsetje break; 264986fd29aSsetje #if !defined(C_OBP) 265986fd29aSsetje prom_free(temp_base[i], temp_size[i]); 266986fd29aSsetje #else /* !C_OBP */ 267986fd29aSsetje cobp_free_mem(temp_base[i], temp_size[i]); 268986fd29aSsetje #endif /* !C_OBP */ 269986fd29aSsetje } 270986fd29aSsetje } 271986fd29aSsetje 272986fd29aSsetje 273986fd29aSsetje /* 274986fd29aSsetje * Implementation of the "alloc" boot service. 275986fd29aSsetje */ 276986fd29aSsetje caddr_t 277986fd29aSsetje bop_alloc(caddr_t virthint, size_t size, int align) 278986fd29aSsetje { 279986fd29aSsetje if (virthint == NULL) 280986fd29aSsetje return (bop_temp_alloc(size, align)); 281986fd29aSsetje return (prom_alloc(virthint, size, align)); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 284*ca622e3aSsvemuri 285*ca622e3aSsvemuri /* 286*ca622e3aSsvemuri * Similar to bop_alloc functionality except that 287*ca622e3aSsvemuri * it will try to breakup into PAGESIZE chunk allocations 288*ca622e3aSsvemuri * if the original single chunk request failed. 289*ca622e3aSsvemuri * This routine does not guarantee physical contig 290*ca622e3aSsvemuri * allocation. 291*ca622e3aSsvemuri */ 292*ca622e3aSsvemuri caddr_t 293*ca622e3aSsvemuri bop_alloc_chunk(caddr_t virthint, size_t size, int align) 294*ca622e3aSsvemuri { 295*ca622e3aSsvemuri caddr_t ret; 296*ca622e3aSsvemuri size_t chunksz; 297*ca622e3aSsvemuri 298*ca622e3aSsvemuri if (virthint == NULL) 299*ca622e3aSsvemuri return (bop_temp_alloc(size, align)); 300*ca622e3aSsvemuri 301*ca622e3aSsvemuri if ((ret = prom_alloc(virthint, size, align))) 302*ca622e3aSsvemuri return (ret); 303*ca622e3aSsvemuri 304*ca622e3aSsvemuri /* 305*ca622e3aSsvemuri * Normal request to prom_alloc has failed. 306*ca622e3aSsvemuri * We will attempt to satisfy the request by allocating 307*ca622e3aSsvemuri * smaller chunks resulting in allocation that 308*ca622e3aSsvemuri * will be virtually contiguous but potentially 309*ca622e3aSsvemuri * not physically contiguous. There are additional 310*ca622e3aSsvemuri * requirements before we want to do this: 311*ca622e3aSsvemuri * 1. virthirt must be PAGESIZE aligned. 312*ca622e3aSsvemuri * 2. align must not be greater than PAGESIZE 313*ca622e3aSsvemuri * 3. size request must be at least PAGESIZE 314*ca622e3aSsvemuri * Otherwise, we will revert back to the original 315*ca622e3aSsvemuri * bop_alloc behavior i.e. return failure. 316*ca622e3aSsvemuri */ 317*ca622e3aSsvemuri if (P2PHASE_TYPED(virthint, PAGESIZE, size_t) != 0 || 318*ca622e3aSsvemuri align > PAGESIZE || size < PAGESIZE) 319*ca622e3aSsvemuri return (ret); 320*ca622e3aSsvemuri 321*ca622e3aSsvemuri /* 322*ca622e3aSsvemuri * Now we will break up the allocation 323*ca622e3aSsvemuri * request in smaller chunks that are 324*ca622e3aSsvemuri * always PAGESIZE aligned. 325*ca622e3aSsvemuri */ 326*ca622e3aSsvemuri ret = virthint; 327*ca622e3aSsvemuri chunksz = P2ALIGN((size >> 1), PAGESIZE); 328*ca622e3aSsvemuri chunksz = MAX(chunksz, PAGESIZE); 329*ca622e3aSsvemuri 330*ca622e3aSsvemuri while (size) { 331*ca622e3aSsvemuri do { 332*ca622e3aSsvemuri /*LINTED E_FUNC_SET_NOT_USED*/ 333*ca622e3aSsvemuri caddr_t res; 334*ca622e3aSsvemuri if ((res = prom_alloc(virthint, chunksz, 335*ca622e3aSsvemuri PAGESIZE))) { 336*ca622e3aSsvemuri ASSERT(virthint == res); 337*ca622e3aSsvemuri break; 338*ca622e3aSsvemuri } 339*ca622e3aSsvemuri 340*ca622e3aSsvemuri chunksz >>= 1; 341*ca622e3aSsvemuri chunksz = P2ALIGN(chunksz, PAGESIZE); 342*ca622e3aSsvemuri } while (chunksz >= PAGESIZE); 343*ca622e3aSsvemuri 344*ca622e3aSsvemuri if (chunksz < PAGESIZE) 345*ca622e3aSsvemuri /* Can't really happen.. */ 346*ca622e3aSsvemuri prom_panic("bop_alloc_chunk failed"); 347*ca622e3aSsvemuri 348*ca622e3aSsvemuri virthint += chunksz; 349*ca622e3aSsvemuri size -= chunksz; 350*ca622e3aSsvemuri if (size < chunksz) 351*ca622e3aSsvemuri chunksz = size; 352*ca622e3aSsvemuri } 353*ca622e3aSsvemuri return (ret); 354*ca622e3aSsvemuri } 355*ca622e3aSsvemuri 356*ca622e3aSsvemuri 3577c478bd9Sstevel@tonic-gate /* 3587c478bd9Sstevel@tonic-gate * Implementation of the "alloc_virt" boot service 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate caddr_t 361986fd29aSsetje bop_alloc_virt(caddr_t virt, size_t size) 3627c478bd9Sstevel@tonic-gate { 363986fd29aSsetje return (prom_claim_virt(size, virt)); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * Implementation of the "free" boot service. 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3707c478bd9Sstevel@tonic-gate void 371986fd29aSsetje bop_free(caddr_t virt, size_t size) 3727c478bd9Sstevel@tonic-gate { 373986fd29aSsetje prom_free(virt, size); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* 3797c478bd9Sstevel@tonic-gate * Implementation of the "getproplen" boot service. 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3827c478bd9Sstevel@tonic-gate int 383986fd29aSsetje bop_getproplen(const char *name) 3847c478bd9Sstevel@tonic-gate { 385986fd29aSsetje struct fakeprop *fpp; 386986fd29aSsetje pnode_t node; 387986fd29aSsetje char *prop; 3887c478bd9Sstevel@tonic-gate 389986fd29aSsetje fpp = fakelook(name); 390986fd29aSsetje if (fpp != NULL) { 391986fd29aSsetje node = fpp->promnode; 392986fd29aSsetje prop = fpp->promname; 393986fd29aSsetje } else { 394986fd29aSsetje node = chosennode; 395986fd29aSsetje prop = (char *)name; 396986fd29aSsetje } 397986fd29aSsetje return (prom_getproplen(node, prop)); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * Implementation of the "getprop" boot service. 4027c478bd9Sstevel@tonic-gate */ 4037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4047c478bd9Sstevel@tonic-gate int 405986fd29aSsetje bop_getprop(const char *name, void *value) 4067c478bd9Sstevel@tonic-gate { 407986fd29aSsetje struct fakeprop *fpp; 408986fd29aSsetje pnode_t node; 409986fd29aSsetje char *prop; 4107c478bd9Sstevel@tonic-gate 411986fd29aSsetje fpp = fakelook(name); 412986fd29aSsetje if (fpp != NULL) { 413986fd29aSsetje node = fpp->promnode; 414986fd29aSsetje prop = fpp->promname; 415986fd29aSsetje } else { 416986fd29aSsetje node = chosennode; 417986fd29aSsetje prop = (char *)name; 418986fd29aSsetje } 419986fd29aSsetje return (prom_getprop(node, prop, value)); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* 423986fd29aSsetje * Implementation of the "print" boot service. 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4267c478bd9Sstevel@tonic-gate void 427986fd29aSsetje bop_printf(void *ops, const char *fmt, ...) 4287c478bd9Sstevel@tonic-gate { 429986fd29aSsetje va_list adx; 4307c478bd9Sstevel@tonic-gate 431986fd29aSsetje va_start(adx, fmt); 432986fd29aSsetje prom_vprintf(fmt, adx); 433986fd29aSsetje va_end(adx); 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* 437986fd29aSsetje * Special routine for kmdb 4387c478bd9Sstevel@tonic-gate */ 4397c478bd9Sstevel@tonic-gate void 440986fd29aSsetje bop_putsarg(const char *fmt, char *arg) 4417c478bd9Sstevel@tonic-gate { 442986fd29aSsetje prom_printf(fmt, arg); 443986fd29aSsetje } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* 446986fd29aSsetje * panic for krtld only 4477c478bd9Sstevel@tonic-gate */ 448986fd29aSsetje void 449986fd29aSsetje bop_panic(const char *s) 450986fd29aSsetje { 451986fd29aSsetje prom_panic((char *)s); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Implementation of the "mount" boot service. 4567c478bd9Sstevel@tonic-gate * 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4597c478bd9Sstevel@tonic-gate int 460986fd29aSsetje bop_mountroot(void) 4617c478bd9Sstevel@tonic-gate { 462986fd29aSsetje (void) prom_getprop(chosennode, "bootfs", (caddr_t)&bfs_ih); 463986fd29aSsetje (void) prom_getprop(chosennode, "archfs", (caddr_t)&afs_ih); 464986fd29aSsetje return ((bfs_ih == -1 && afs_ih == -1) ? BOOT_SVC_FAIL : BOOT_SVC_OK); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * Implementation of the "unmountroot" boot service. 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4717c478bd9Sstevel@tonic-gate int 472986fd29aSsetje bop_unmountroot(void) 4737c478bd9Sstevel@tonic-gate { 4747c478bd9Sstevel@tonic-gate 475986fd29aSsetje if (bfs_ih != OBP_BADNODE) { 476986fd29aSsetje (void) prom_close(bfs_ih); 477986fd29aSsetje bfs_ih = OBP_BADNODE; 4787c478bd9Sstevel@tonic-gate } 479986fd29aSsetje if (afs_ih != OBP_BADNODE) { 480986fd29aSsetje (void) prom_close(afs_ih); 481986fd29aSsetje afs_ih = OBP_BADNODE; 482986fd29aSsetje } 483986fd29aSsetje return (BOOT_SVC_OK); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * Implementation of the "fstat" boot service. 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate int 490986fd29aSsetje bop_fstat(int fd, struct bootstat *st) 4917c478bd9Sstevel@tonic-gate { 492986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 493986fd29aSsetje return (prom_fsize(prom_ihs[fd], fd, (size_t *)&st->st_size)); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate 496986fd29aSsetje int 497986fd29aSsetje boot_compinfo(int fd, struct compinfo *cb) 498986fd29aSsetje { 499986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 500986fd29aSsetje return (prom_compinfo(prom_ihs[fd], fd, 501986fd29aSsetje &cb->iscmp, &cb->fsize, &cb->blksize)); 502986fd29aSsetje } 503986fd29aSsetje 504986fd29aSsetje void 505986fd29aSsetje bop_free_archive(void) 506986fd29aSsetje { 507986fd29aSsetje char archive[OBP_MAXPATHLEN]; 508986fd29aSsetje pnode_t arph; 509986fd29aSsetje uint32_t arbase, arsize, alloc_size; 510986fd29aSsetje 511986fd29aSsetje /* 512986fd29aSsetje * If the ramdisk will eventually be root, or we weren't 513986fd29aSsetje * booted via the archive, then nothing to do here 514986fd29aSsetje */ 515986fd29aSsetje if (root_is_ramdisk == B_TRUE || 516986fd29aSsetje prom_getprop(chosennode, "bootarchive", archive) == -1) 517986fd29aSsetje return; 518986fd29aSsetje arph = prom_finddevice(archive); 519986fd29aSsetje if (arph == -1 || 520986fd29aSsetje prom_getprop(arph, OBP_ALLOCSIZE, (caddr_t)&alloc_size) == -1 || 521986fd29aSsetje prom_getprop(arph, OBP_SIZE, (caddr_t)&arsize) == -1 || 522986fd29aSsetje prom_getprop(arph, OBP_ADDRESS, (caddr_t)&arbase) == -1) 523986fd29aSsetje prom_panic("can't free boot archive"); 524986fd29aSsetje 525986fd29aSsetje #if !defined(C_OBP) 526986fd29aSsetje if (alloc_size == 0) 527986fd29aSsetje prom_free((caddr_t)(uintptr_t)arbase, arsize); 528986fd29aSsetje else { 529986fd29aSsetje uint32_t arend = arbase + arsize; 530986fd29aSsetje 531986fd29aSsetje while (arbase < arend) { 532986fd29aSsetje prom_free((caddr_t)(uintptr_t)arbase, 533986fd29aSsetje MIN(alloc_size, arend - arbase)); 534986fd29aSsetje arbase += alloc_size; 535986fd29aSsetje } 536986fd29aSsetje } 537986fd29aSsetje #else /* !C_OBP */ 538986fd29aSsetje cobp_free_mem((caddr_t)(uintptr_t)arbase, arsize); 539986fd29aSsetje #endif /* !C_OBP */ 540986fd29aSsetje } 541986fd29aSsetje 542986fd29aSsetje #if defined(C_OBP) 543986fd29aSsetje /* 544986fd29aSsetje * Blech. The C proms have a bug when freeing areas that cross 545986fd29aSsetje * page sizes, so we have to break up the free into sections 546986fd29aSsetje * bounded by the various pagesizes. 547986fd29aSsetje */ 548986fd29aSsetje void 549986fd29aSsetje cobp_free_mem(caddr_t base, size_t size) 550986fd29aSsetje { 551986fd29aSsetje int i; 552986fd29aSsetje size_t len, pgsz; 553986fd29aSsetje 554986fd29aSsetje /* 555986fd29aSsetje * Large pages only used when size > 512k 556986fd29aSsetje */ 557986fd29aSsetje if (size < MMU_PAGESIZE512K || 558986fd29aSsetje ((uintptr_t)base & MMU_PAGEOFFSET512K) != 0) { 559986fd29aSsetje prom_free(base, size); 560986fd29aSsetje return; 561986fd29aSsetje } 562986fd29aSsetje for (i = 3; i >= 0; i--) { 563986fd29aSsetje pgsz = page_get_pagesize(i); 564986fd29aSsetje if (size < pgsz) 565986fd29aSsetje continue; 566986fd29aSsetje len = size & ~(pgsz - 1); 567986fd29aSsetje prom_free(base, len); 568986fd29aSsetje base += len; 569986fd29aSsetje size -= len; 570986fd29aSsetje } 571986fd29aSsetje } 572986fd29aSsetje #endif /* C_OBP */ 573986fd29aSsetje 574986fd29aSsetje 5757c478bd9Sstevel@tonic-gate /* 5767c478bd9Sstevel@tonic-gate * Implementation of the "enter_mon" boot service. 5777c478bd9Sstevel@tonic-gate */ 5787c478bd9Sstevel@tonic-gate void 579986fd29aSsetje bop_enter_mon(void) 5807c478bd9Sstevel@tonic-gate { 581986fd29aSsetje prom_enter_mon(); 582986fd29aSsetje } 5837c478bd9Sstevel@tonic-gate 584986fd29aSsetje /* 585986fd29aSsetje * free elf info allocated by booter 586986fd29aSsetje */ 587986fd29aSsetje void 588986fd29aSsetje bop_free_elf(void) 589986fd29aSsetje { 590986fd29aSsetje uint32_t eadr; 591986fd29aSsetje uint32_t esize; 592986fd29aSsetje extern Addr dynseg; 593986fd29aSsetje extern size_t dynsize; 594986fd29aSsetje 595986fd29aSsetje if (bop_getprop("elfheader-address", (caddr_t)&eadr) == -1 || 596986fd29aSsetje bop_getprop("elfheader-length", (caddr_t)&esize) == -1) 597986fd29aSsetje prom_panic("missing elfheader"); 598986fd29aSsetje prom_free((caddr_t)(uintptr_t)eadr, roundup(esize, PAGESIZE)); 599986fd29aSsetje 600986fd29aSsetje prom_free((caddr_t)(uintptr_t)dynseg, roundup(dynsize, PAGESIZE)); 601986fd29aSsetje } 602986fd29aSsetje 603986fd29aSsetje 604986fd29aSsetje /* Simple message to indicate that the bootops pointer has been zeroed */ 605986fd29aSsetje #ifdef DEBUG 606986fd29aSsetje int bootops_gone_on = 0; 607986fd29aSsetje #define BOOTOPS_GONE() \ 608986fd29aSsetje if (bootops_gone_on) \ 609986fd29aSsetje prom_printf("The bootops vec is zeroed now!\n"); 610986fd29aSsetje #else 611986fd29aSsetje #define BOOTOPS_GONE() 612986fd29aSsetje #endif /* DEBUG */ 613986fd29aSsetje 614986fd29aSsetje void 615986fd29aSsetje bop_fini(void) 616986fd29aSsetje { 617986fd29aSsetje bop_free_archive(); 618986fd29aSsetje (void) bop_unmountroot(); 619986fd29aSsetje bop_free_elf(); 620986fd29aSsetje bop_temp_freeall(); 621986fd29aSsetje 622986fd29aSsetje bootops = (struct bootops *)NULL; 623986fd29aSsetje BOOTOPS_GONE(); 6247c478bd9Sstevel@tonic-gate } 625