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*3f9058a8SWilliam Roche * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Definitions of interfaces that provide services from the secondary 287c478bd9Sstevel@tonic-gate * boot program to its clients (primarily Solaris, krtld, kmdb and their 297c478bd9Sstevel@tonic-gate * successors.) This interface replaces the bootops (BOP) implementation 307c478bd9Sstevel@tonic-gate * as the interface to be called by boot clients. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 35986fd29aSsetje #include <sys/systm.h> 367c478bd9Sstevel@tonic-gate #include <sys/reboot.h> 377c478bd9Sstevel@tonic-gate #include <sys/param.h> 387c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 397c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h> 40986fd29aSsetje #include <sys/promimpl.h> 41986fd29aSsetje #include <sys/prom_plat.h> 427c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 437c478bd9Sstevel@tonic-gate #include <sys/bootstat.h> 44986fd29aSsetje #include <sys/kobj_impl.h> 457c478bd9Sstevel@tonic-gate 46986fd29aSsetje struct bootops *bootops; 47986fd29aSsetje struct bootops kbootops; 48986fd29aSsetje 49986fd29aSsetje pnode_t chosennode; 50*3f9058a8SWilliam Roche /* 51*3f9058a8SWilliam Roche * Flag to disable the use of real ramdisks (in the OBP - on Sparc) when 52*3f9058a8SWilliam Roche * the associated memory is no longer available. 53*3f9058a8SWilliam Roche */ 54*3f9058a8SWilliam Roche int bootops_obp_ramdisk_disabled = 0; 55986fd29aSsetje 56986fd29aSsetje #define FAKE_ROOT (pnode_t)1 57986fd29aSsetje 58986fd29aSsetje struct fakeprop { 59986fd29aSsetje char *bootname; 60986fd29aSsetje pnode_t promnode; 61986fd29aSsetje char *promname; 62986fd29aSsetje } fakeprops[] = { 63986fd29aSsetje { "mfg-name", FAKE_ROOT, "name" }, 64986fd29aSsetje { NULL, 0, NULL } 65986fd29aSsetje }; 66986fd29aSsetje 67986fd29aSsetje static void 68986fd29aSsetje fakelook_init(void) 697c478bd9Sstevel@tonic-gate { 70986fd29aSsetje struct fakeprop *fpp = fakeprops; 71986fd29aSsetje 72986fd29aSsetje while (fpp->bootname != NULL) { 73986fd29aSsetje switch (fpp->promnode) { 74986fd29aSsetje case FAKE_ROOT: 75986fd29aSsetje fpp->promnode = prom_rootnode(); 76986fd29aSsetje break; 77986fd29aSsetje } 78986fd29aSsetje fpp++; 79986fd29aSsetje } 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 82986fd29aSsetje static struct fakeprop * 83986fd29aSsetje fakelook(const char *prop) 84986fd29aSsetje { 85986fd29aSsetje struct fakeprop *fpp = fakeprops; 86986fd29aSsetje 87986fd29aSsetje while (fpp->bootname != NULL) { 88986fd29aSsetje if (strcmp(prop, fpp->bootname) == 0) 89986fd29aSsetje return (fpp); 90986fd29aSsetje fpp++; 91986fd29aSsetje } 92986fd29aSsetje return (NULL); 93986fd29aSsetje } 94986fd29aSsetje 95986fd29aSsetje ihandle_t bfs_ih = OBP_BADNODE; 96986fd29aSsetje ihandle_t afs_ih = OBP_BADNODE; 97986fd29aSsetje 98986fd29aSsetje void 99986fd29aSsetje bop_init(void) 100986fd29aSsetje { 101986fd29aSsetje chosennode = prom_chosennode(); 102986fd29aSsetje 103986fd29aSsetje fakelook_init(); 104986fd29aSsetje 105986fd29aSsetje /* fake bootops - it needs to point to non-NULL */ 106986fd29aSsetje bootops = &kbootops; 107986fd29aSsetje } 108986fd29aSsetje 109986fd29aSsetje #define MAXPROMFD 16 110986fd29aSsetje 111986fd29aSsetje static ihandle_t prom_ihs[MAXPROMFD]; 112986fd29aSsetje int filter_etc = 1; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* 1157c478bd9Sstevel@tonic-gate * Implementation of the "open" boot service. 1167c478bd9Sstevel@tonic-gate */ 117986fd29aSsetje /*ARGSUSED*/ 1187c478bd9Sstevel@tonic-gate int 119986fd29aSsetje bop_open(const char *name, int flags) 1207c478bd9Sstevel@tonic-gate { 121986fd29aSsetje int fd = -1, layered; 122986fd29aSsetje ihandle_t ih; 1237c478bd9Sstevel@tonic-gate 124986fd29aSsetje /* 125986fd29aSsetje * Only look underneath archive for /etc files 126986fd29aSsetje */ 127986fd29aSsetje layered = filter_etc ? 128986fd29aSsetje strncmp(name, "/etc", sizeof ("/etc") - 1) == 0 : 1; 1297c478bd9Sstevel@tonic-gate 130986fd29aSsetje if (afs_ih != OBP_BADNODE) { 131986fd29aSsetje ih = afs_ih; 132986fd29aSsetje fd = prom_fopen(ih, (char *)name); 133986fd29aSsetje if (fd == -1 && !layered) 134986fd29aSsetje return (BOOT_SVC_FAIL); 135986fd29aSsetje } 136986fd29aSsetje if (fd == -1 && bfs_ih != OBP_BADNODE) { 137986fd29aSsetje ih = bfs_ih; 138986fd29aSsetje fd = prom_fopen(ih, (char *)name); 139986fd29aSsetje } 140986fd29aSsetje if (fd == -1) 141986fd29aSsetje return (BOOT_SVC_FAIL); 142986fd29aSsetje ASSERT(fd < MAXPROMFD); 143986fd29aSsetje ASSERT(prom_ihs[fd] == 0); 144986fd29aSsetje prom_ihs[fd] = ih; 145986fd29aSsetje return (fd); 146986fd29aSsetje } 147986fd29aSsetje 148986fd29aSsetje static void 149986fd29aSsetje spinner(void) 150986fd29aSsetje { 151986fd29aSsetje static int pos; 152986fd29aSsetje static char ind[] = "|/-\\"; /* that's entertainment? */ 153986fd29aSsetje static int blks_read; 154986fd29aSsetje 155986fd29aSsetje if ((blks_read++ & 0x3) == 0) 156986fd29aSsetje prom_printf("%c\b", ind[pos++ & 3]); 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * Implementation of the "read" boot service. 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate int 163986fd29aSsetje bop_read(int fd, caddr_t buf, size_t size) 1647c478bd9Sstevel@tonic-gate { 165986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 166986fd29aSsetje spinner(); 167986fd29aSsetje return (prom_fread(prom_ihs[fd], fd, buf, size)); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * Implementation of the "seek" boot service. 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate int 174986fd29aSsetje bop_seek(int fd, off_t off) 1757c478bd9Sstevel@tonic-gate { 176986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 177986fd29aSsetje return (prom_fseek(prom_ihs[fd], fd, off)); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* 1817c478bd9Sstevel@tonic-gate * Implementation of the "close" boot service. 1827c478bd9Sstevel@tonic-gate */ 1837c478bd9Sstevel@tonic-gate int 184986fd29aSsetje bop_close(int fd) 1857c478bd9Sstevel@tonic-gate { 186986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 187986fd29aSsetje prom_fclose(prom_ihs[fd], fd); 188986fd29aSsetje prom_ihs[fd] = 0; 189986fd29aSsetje return (0); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 193986fd29aSsetje * Simple temp memory allocator 1947c478bd9Sstevel@tonic-gate * 195986fd29aSsetje * >PAGESIZE allocations are gotten directly from prom at bighand 196986fd29aSsetje * smaller ones are satisfied from littlehand, which does a 197986fd29aSsetje * 1 page bighand allocation when it runs out of memory 198986fd29aSsetje */ 199986fd29aSsetje static caddr_t bighand = (caddr_t)BOOTTMPBASE; 200986fd29aSsetje static caddr_t littlehand = (caddr_t)BOOTTMPBASE; 201986fd29aSsetje 202986fd29aSsetje #define NTMPALLOC 128 203986fd29aSsetje 204986fd29aSsetje static caddr_t temp_base[NTMPALLOC]; 205986fd29aSsetje static size_t temp_size[NTMPALLOC]; 206986fd29aSsetje static int temp_indx; 207986fd29aSsetje 208986fd29aSsetje #if defined(C_OBP) 209986fd29aSsetje void cobp_free_mem(caddr_t, size_t); 210986fd29aSsetje #endif /* C_OBP */ 211986fd29aSsetje 212986fd29aSsetje 213986fd29aSsetje /* 214986fd29aSsetje * temporary memory storage until bop_tmp_freeall is called 215986fd29aSsetje * (after the kernel heap is initialized) 2167c478bd9Sstevel@tonic-gate */ 2177c478bd9Sstevel@tonic-gate caddr_t 218986fd29aSsetje bop_temp_alloc(size_t size, int align) 2197c478bd9Sstevel@tonic-gate { 220986fd29aSsetje caddr_t ret; 2217c478bd9Sstevel@tonic-gate 222986fd29aSsetje /* 223986fd29aSsetje * OBP allocs 10MB to boot, which is where virthint = 0 224986fd29aSsetje * memory was allocated from. Without boot, we allocate 225986fd29aSsetje * from BOOTTMPBASE and free when we're ready to take 226986fd29aSsetje * the machine from OBP 227986fd29aSsetje */ 228986fd29aSsetje if (size < PAGESIZE) { 229986fd29aSsetje size_t left = 230986fd29aSsetje ALIGN(littlehand, PAGESIZE) - (uintptr_t)littlehand; 2317c478bd9Sstevel@tonic-gate 232986fd29aSsetje size = roundup(size, MAX(align, 8)); 233986fd29aSsetje if (size <= left) { 234986fd29aSsetje ret = littlehand; 235986fd29aSsetje littlehand += size; 236986fd29aSsetje return (ret); 237986fd29aSsetje } 238986fd29aSsetje littlehand = bighand + size; 239986fd29aSsetje } 240986fd29aSsetje size = roundup(size, PAGESIZE); 241986fd29aSsetje ret = prom_alloc(bighand, size, align); 242986fd29aSsetje if (ret == NULL) 243986fd29aSsetje prom_panic("boot temp overflow"); 244986fd29aSsetje bighand += size; 245986fd29aSsetje 246986fd29aSsetje /* log it for bop_fini() */ 247986fd29aSsetje temp_base[temp_indx] = ret; 248986fd29aSsetje temp_size[temp_indx] = size; 249986fd29aSsetje if (++temp_indx == NTMPALLOC) 250986fd29aSsetje prom_panic("out of bop temp space"); 251986fd29aSsetje 252986fd29aSsetje return (ret); 253986fd29aSsetje } 254986fd29aSsetje 255986fd29aSsetje void 256986fd29aSsetje bop_temp_freeall(void) 257986fd29aSsetje { 258986fd29aSsetje int i; 259986fd29aSsetje 260986fd29aSsetje /* 261986fd29aSsetje * We have to call prom_free() with the same args 262986fd29aSsetje * as we used in prom_alloc() 263986fd29aSsetje */ 264986fd29aSsetje for (i = 0; i < NTMPALLOC; i++) { 265986fd29aSsetje if (temp_base[i] == NULL) 266986fd29aSsetje break; 267986fd29aSsetje #if !defined(C_OBP) 268986fd29aSsetje prom_free(temp_base[i], temp_size[i]); 269986fd29aSsetje #else /* !C_OBP */ 270986fd29aSsetje cobp_free_mem(temp_base[i], temp_size[i]); 271986fd29aSsetje #endif /* !C_OBP */ 272986fd29aSsetje } 273986fd29aSsetje } 274986fd29aSsetje 275986fd29aSsetje 276986fd29aSsetje /* 277986fd29aSsetje * Implementation of the "alloc" boot service. 278986fd29aSsetje */ 279986fd29aSsetje caddr_t 280986fd29aSsetje bop_alloc(caddr_t virthint, size_t size, int align) 281986fd29aSsetje { 282986fd29aSsetje if (virthint == NULL) 283986fd29aSsetje return (bop_temp_alloc(size, align)); 284986fd29aSsetje return (prom_alloc(virthint, size, align)); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 287ca622e3aSsvemuri 288ca622e3aSsvemuri /* 289ca622e3aSsvemuri * Similar to bop_alloc functionality except that 290ca622e3aSsvemuri * it will try to breakup into PAGESIZE chunk allocations 291ca622e3aSsvemuri * if the original single chunk request failed. 292ca622e3aSsvemuri * This routine does not guarantee physical contig 293ca622e3aSsvemuri * allocation. 294ca622e3aSsvemuri */ 295ca622e3aSsvemuri caddr_t 296ca622e3aSsvemuri bop_alloc_chunk(caddr_t virthint, size_t size, int align) 297ca622e3aSsvemuri { 298ca622e3aSsvemuri caddr_t ret; 299ca622e3aSsvemuri size_t chunksz; 300ca622e3aSsvemuri 301ca622e3aSsvemuri if (virthint == NULL) 302ca622e3aSsvemuri return (bop_temp_alloc(size, align)); 303ca622e3aSsvemuri 304ca622e3aSsvemuri if ((ret = prom_alloc(virthint, size, align))) 305ca622e3aSsvemuri return (ret); 306ca622e3aSsvemuri 307ca622e3aSsvemuri /* 308ca622e3aSsvemuri * Normal request to prom_alloc has failed. 309ca622e3aSsvemuri * We will attempt to satisfy the request by allocating 310ca622e3aSsvemuri * smaller chunks resulting in allocation that 311ca622e3aSsvemuri * will be virtually contiguous but potentially 312ca622e3aSsvemuri * not physically contiguous. There are additional 313ca622e3aSsvemuri * requirements before we want to do this: 314ca622e3aSsvemuri * 1. virthirt must be PAGESIZE aligned. 315ca622e3aSsvemuri * 2. align must not be greater than PAGESIZE 316ca622e3aSsvemuri * 3. size request must be at least PAGESIZE 317ca622e3aSsvemuri * Otherwise, we will revert back to the original 318ca622e3aSsvemuri * bop_alloc behavior i.e. return failure. 319ca622e3aSsvemuri */ 320ca622e3aSsvemuri if (P2PHASE_TYPED(virthint, PAGESIZE, size_t) != 0 || 321ca622e3aSsvemuri align > PAGESIZE || size < PAGESIZE) 322ca622e3aSsvemuri return (ret); 323ca622e3aSsvemuri 324ca622e3aSsvemuri /* 325ca622e3aSsvemuri * Now we will break up the allocation 326ca622e3aSsvemuri * request in smaller chunks that are 327ca622e3aSsvemuri * always PAGESIZE aligned. 328ca622e3aSsvemuri */ 329ca622e3aSsvemuri ret = virthint; 330ca622e3aSsvemuri chunksz = P2ALIGN((size >> 1), PAGESIZE); 331ca622e3aSsvemuri chunksz = MAX(chunksz, PAGESIZE); 332ca622e3aSsvemuri 333ca622e3aSsvemuri while (size) { 334ca622e3aSsvemuri do { 335ca622e3aSsvemuri /*LINTED E_FUNC_SET_NOT_USED*/ 336ca622e3aSsvemuri caddr_t res; 337ca622e3aSsvemuri if ((res = prom_alloc(virthint, chunksz, 338ca622e3aSsvemuri PAGESIZE))) { 339ca622e3aSsvemuri ASSERT(virthint == res); 340ca622e3aSsvemuri break; 341ca622e3aSsvemuri } 342ca622e3aSsvemuri 343ca622e3aSsvemuri chunksz >>= 1; 344ca622e3aSsvemuri chunksz = P2ALIGN(chunksz, PAGESIZE); 345ca622e3aSsvemuri } while (chunksz >= PAGESIZE); 346ca622e3aSsvemuri 347ca622e3aSsvemuri if (chunksz < PAGESIZE) 348ca622e3aSsvemuri /* Can't really happen.. */ 349ca622e3aSsvemuri prom_panic("bop_alloc_chunk failed"); 350ca622e3aSsvemuri 351ca622e3aSsvemuri virthint += chunksz; 352ca622e3aSsvemuri size -= chunksz; 353ca622e3aSsvemuri if (size < chunksz) 354ca622e3aSsvemuri chunksz = size; 355ca622e3aSsvemuri } 356ca622e3aSsvemuri return (ret); 357ca622e3aSsvemuri } 358ca622e3aSsvemuri 359ca622e3aSsvemuri 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * Implementation of the "alloc_virt" boot service 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate caddr_t 364986fd29aSsetje bop_alloc_virt(caddr_t virt, size_t size) 3657c478bd9Sstevel@tonic-gate { 366986fd29aSsetje return (prom_claim_virt(size, virt)); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * Implementation of the "free" boot service. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3737c478bd9Sstevel@tonic-gate void 374986fd29aSsetje bop_free(caddr_t virt, size_t size) 3757c478bd9Sstevel@tonic-gate { 376986fd29aSsetje prom_free(virt, size); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * Implementation of the "getproplen" boot service. 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3857c478bd9Sstevel@tonic-gate int 386986fd29aSsetje bop_getproplen(const char *name) 3877c478bd9Sstevel@tonic-gate { 388986fd29aSsetje struct fakeprop *fpp; 389986fd29aSsetje pnode_t node; 390986fd29aSsetje char *prop; 3917c478bd9Sstevel@tonic-gate 392986fd29aSsetje fpp = fakelook(name); 393986fd29aSsetje if (fpp != NULL) { 394986fd29aSsetje node = fpp->promnode; 395986fd29aSsetje prop = fpp->promname; 396986fd29aSsetje } else { 397986fd29aSsetje node = chosennode; 398986fd29aSsetje prop = (char *)name; 399986fd29aSsetje } 400986fd29aSsetje return (prom_getproplen(node, prop)); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * Implementation of the "getprop" boot service. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4077c478bd9Sstevel@tonic-gate int 408986fd29aSsetje bop_getprop(const char *name, void *value) 4097c478bd9Sstevel@tonic-gate { 410986fd29aSsetje struct fakeprop *fpp; 411986fd29aSsetje pnode_t node; 412986fd29aSsetje char *prop; 4137c478bd9Sstevel@tonic-gate 414986fd29aSsetje fpp = fakelook(name); 415986fd29aSsetje if (fpp != NULL) { 416986fd29aSsetje node = fpp->promnode; 417986fd29aSsetje prop = fpp->promname; 418986fd29aSsetje } else { 419986fd29aSsetje node = chosennode; 420986fd29aSsetje prop = (char *)name; 421986fd29aSsetje } 422986fd29aSsetje return (prom_getprop(node, prop, value)); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate /* 426986fd29aSsetje * Implementation of the "print" boot service. 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4297c478bd9Sstevel@tonic-gate void 430986fd29aSsetje bop_printf(void *ops, const char *fmt, ...) 4317c478bd9Sstevel@tonic-gate { 432986fd29aSsetje va_list adx; 4337c478bd9Sstevel@tonic-gate 434986fd29aSsetje va_start(adx, fmt); 435986fd29aSsetje prom_vprintf(fmt, adx); 436986fd29aSsetje va_end(adx); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* 440986fd29aSsetje * Special routine for kmdb 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate void 443986fd29aSsetje bop_putsarg(const char *fmt, char *arg) 4447c478bd9Sstevel@tonic-gate { 445986fd29aSsetje prom_printf(fmt, arg); 446986fd29aSsetje } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* 449986fd29aSsetje * panic for krtld only 4507c478bd9Sstevel@tonic-gate */ 451986fd29aSsetje void 452986fd29aSsetje bop_panic(const char *s) 453986fd29aSsetje { 454986fd29aSsetje prom_panic((char *)s); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* 4587c478bd9Sstevel@tonic-gate * Implementation of the "mount" boot service. 4597c478bd9Sstevel@tonic-gate * 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4627c478bd9Sstevel@tonic-gate int 463986fd29aSsetje bop_mountroot(void) 4647c478bd9Sstevel@tonic-gate { 465986fd29aSsetje (void) prom_getprop(chosennode, "bootfs", (caddr_t)&bfs_ih); 466986fd29aSsetje (void) prom_getprop(chosennode, "archfs", (caddr_t)&afs_ih); 467986fd29aSsetje return ((bfs_ih == -1 && afs_ih == -1) ? BOOT_SVC_FAIL : BOOT_SVC_OK); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate /* 4717c478bd9Sstevel@tonic-gate * Implementation of the "unmountroot" boot service. 4727c478bd9Sstevel@tonic-gate */ 4737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4747c478bd9Sstevel@tonic-gate int 475986fd29aSsetje bop_unmountroot(void) 4767c478bd9Sstevel@tonic-gate { 4777c478bd9Sstevel@tonic-gate 478986fd29aSsetje if (bfs_ih != OBP_BADNODE) { 479986fd29aSsetje (void) prom_close(bfs_ih); 480986fd29aSsetje bfs_ih = OBP_BADNODE; 4817c478bd9Sstevel@tonic-gate } 482986fd29aSsetje if (afs_ih != OBP_BADNODE) { 483986fd29aSsetje (void) prom_close(afs_ih); 484986fd29aSsetje afs_ih = OBP_BADNODE; 485986fd29aSsetje } 486986fd29aSsetje return (BOOT_SVC_OK); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate /* 4907c478bd9Sstevel@tonic-gate * Implementation of the "fstat" boot service. 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate int 493986fd29aSsetje bop_fstat(int fd, struct bootstat *st) 4947c478bd9Sstevel@tonic-gate { 495986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 496986fd29aSsetje return (prom_fsize(prom_ihs[fd], fd, (size_t *)&st->st_size)); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 499986fd29aSsetje int 500986fd29aSsetje boot_compinfo(int fd, struct compinfo *cb) 501986fd29aSsetje { 502986fd29aSsetje ASSERT(prom_ihs[fd] != 0); 503986fd29aSsetje return (prom_compinfo(prom_ihs[fd], fd, 504986fd29aSsetje &cb->iscmp, &cb->fsize, &cb->blksize)); 505986fd29aSsetje } 506986fd29aSsetje 507986fd29aSsetje void 508986fd29aSsetje bop_free_archive(void) 509986fd29aSsetje { 510986fd29aSsetje char archive[OBP_MAXPATHLEN]; 511986fd29aSsetje pnode_t arph; 512986fd29aSsetje uint32_t arbase, arsize, alloc_size; 513986fd29aSsetje 514986fd29aSsetje /* 515986fd29aSsetje * If the ramdisk will eventually be root, or we weren't 516986fd29aSsetje * booted via the archive, then nothing to do here 517986fd29aSsetje */ 518986fd29aSsetje if (root_is_ramdisk == B_TRUE || 519986fd29aSsetje prom_getprop(chosennode, "bootarchive", archive) == -1) 520986fd29aSsetje return; 521986fd29aSsetje arph = prom_finddevice(archive); 522986fd29aSsetje if (arph == -1 || 523986fd29aSsetje prom_getprop(arph, OBP_ALLOCSIZE, (caddr_t)&alloc_size) == -1 || 524986fd29aSsetje prom_getprop(arph, OBP_SIZE, (caddr_t)&arsize) == -1 || 525986fd29aSsetje prom_getprop(arph, OBP_ADDRESS, (caddr_t)&arbase) == -1) 526986fd29aSsetje prom_panic("can't free boot archive"); 527986fd29aSsetje 528*3f9058a8SWilliam Roche bootops_obp_ramdisk_disabled = 1; 529*3f9058a8SWilliam Roche 530986fd29aSsetje #if !defined(C_OBP) 531986fd29aSsetje if (alloc_size == 0) 532986fd29aSsetje prom_free((caddr_t)(uintptr_t)arbase, arsize); 533986fd29aSsetje else { 534986fd29aSsetje uint32_t arend = arbase + arsize; 535986fd29aSsetje 536986fd29aSsetje while (arbase < arend) { 537986fd29aSsetje prom_free((caddr_t)(uintptr_t)arbase, 538986fd29aSsetje MIN(alloc_size, arend - arbase)); 539986fd29aSsetje arbase += alloc_size; 540986fd29aSsetje } 541986fd29aSsetje } 542986fd29aSsetje #else /* !C_OBP */ 543986fd29aSsetje cobp_free_mem((caddr_t)(uintptr_t)arbase, arsize); 544986fd29aSsetje #endif /* !C_OBP */ 545986fd29aSsetje } 546986fd29aSsetje 547986fd29aSsetje #if defined(C_OBP) 548986fd29aSsetje /* 549986fd29aSsetje * Blech. The C proms have a bug when freeing areas that cross 550986fd29aSsetje * page sizes, so we have to break up the free into sections 551986fd29aSsetje * bounded by the various pagesizes. 552986fd29aSsetje */ 553986fd29aSsetje void 554986fd29aSsetje cobp_free_mem(caddr_t base, size_t size) 555986fd29aSsetje { 556986fd29aSsetje int i; 557986fd29aSsetje size_t len, pgsz; 558986fd29aSsetje 559986fd29aSsetje /* 560986fd29aSsetje * Large pages only used when size > 512k 561986fd29aSsetje */ 562986fd29aSsetje if (size < MMU_PAGESIZE512K || 563986fd29aSsetje ((uintptr_t)base & MMU_PAGEOFFSET512K) != 0) { 564986fd29aSsetje prom_free(base, size); 565986fd29aSsetje return; 566986fd29aSsetje } 567986fd29aSsetje for (i = 3; i >= 0; i--) { 568986fd29aSsetje pgsz = page_get_pagesize(i); 569986fd29aSsetje if (size < pgsz) 570986fd29aSsetje continue; 571986fd29aSsetje len = size & ~(pgsz - 1); 572986fd29aSsetje prom_free(base, len); 573986fd29aSsetje base += len; 574986fd29aSsetje size -= len; 575986fd29aSsetje } 576986fd29aSsetje } 577986fd29aSsetje #endif /* C_OBP */ 578986fd29aSsetje 579986fd29aSsetje 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * Implementation of the "enter_mon" boot service. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate void 584986fd29aSsetje bop_enter_mon(void) 5857c478bd9Sstevel@tonic-gate { 586986fd29aSsetje prom_enter_mon(); 587986fd29aSsetje } 5887c478bd9Sstevel@tonic-gate 589986fd29aSsetje /* 590986fd29aSsetje * free elf info allocated by booter 591986fd29aSsetje */ 592986fd29aSsetje void 593986fd29aSsetje bop_free_elf(void) 594986fd29aSsetje { 595986fd29aSsetje uint32_t eadr; 596986fd29aSsetje uint32_t esize; 597986fd29aSsetje extern Addr dynseg; 598986fd29aSsetje extern size_t dynsize; 599986fd29aSsetje 600986fd29aSsetje if (bop_getprop("elfheader-address", (caddr_t)&eadr) == -1 || 601986fd29aSsetje bop_getprop("elfheader-length", (caddr_t)&esize) == -1) 602986fd29aSsetje prom_panic("missing elfheader"); 603986fd29aSsetje prom_free((caddr_t)(uintptr_t)eadr, roundup(esize, PAGESIZE)); 604986fd29aSsetje 605986fd29aSsetje prom_free((caddr_t)(uintptr_t)dynseg, roundup(dynsize, PAGESIZE)); 606986fd29aSsetje } 607986fd29aSsetje 608986fd29aSsetje 609986fd29aSsetje /* Simple message to indicate that the bootops pointer has been zeroed */ 610986fd29aSsetje #ifdef DEBUG 611986fd29aSsetje int bootops_gone_on = 0; 612986fd29aSsetje #define BOOTOPS_GONE() \ 613986fd29aSsetje if (bootops_gone_on) \ 614986fd29aSsetje prom_printf("The bootops vec is zeroed now!\n"); 615986fd29aSsetje #else 616986fd29aSsetje #define BOOTOPS_GONE() 617986fd29aSsetje #endif /* DEBUG */ 618986fd29aSsetje 619986fd29aSsetje void 620986fd29aSsetje bop_fini(void) 621986fd29aSsetje { 622986fd29aSsetje bop_free_archive(); 623986fd29aSsetje (void) bop_unmountroot(); 624986fd29aSsetje bop_free_elf(); 625986fd29aSsetje bop_temp_freeall(); 626986fd29aSsetje 627986fd29aSsetje bootops = (struct bootops *)NULL; 628986fd29aSsetje BOOTOPS_GONE(); 6297c478bd9Sstevel@tonic-gate } 630