Index: head/sys/boot/ficl/loader.c =================================================================== --- head/sys/boot/ficl/loader.c (revision 271405) +++ head/sys/boot/ficl/loader.c (revision 271406) @@ -1,811 +1,953 @@ /*- * Copyright (c) 2000 Daniel Capo Sobral * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /******************************************************************* ** l o a d e r . c ** Additional FICL words designed for FreeBSD's loader ** *******************************************************************/ #ifdef TESTMAIN #include #include #include #include #include #include #include #else #include #endif #include "bootstrap.h" #include #include "ficl.h" /* FreeBSD's loader interaction words and extras * * setenv ( value n name n' -- ) * setenv? ( value n name n' flag -- ) * getenv ( addr n -- addr' n' | -1 ) * unsetenv ( addr n -- ) * copyin ( addr addr' len -- ) * copyout ( addr addr' len -- ) * findfile ( name len type len' -- addr ) * pnpdevices ( -- addr ) * pnphandlers ( -- addr ) * ccall ( [[...[p10] p9] ... p1] n addr -- result ) * .# ( value -- ) */ void ficlSetenv(FICL_VM *pVM) { #ifndef TESTMAIN char *name, *value; #endif char *namep, *valuep; int names, values; #if FICL_ROBUST > 1 vmCheckStack(pVM, 4, 0); #endif names = stackPopINT(pVM->pStack); namep = (char*) stackPopPtr(pVM->pStack); values = stackPopINT(pVM->pStack); valuep = (char*) stackPopPtr(pVM->pStack); #ifndef TESTMAIN name = (char*) ficlMalloc(names+1); if (!name) vmThrowErr(pVM, "Error: out of memory"); strncpy(name, namep, names); name[names] = '\0'; value = (char*) ficlMalloc(values+1); if (!value) vmThrowErr(pVM, "Error: out of memory"); strncpy(value, valuep, values); value[values] = '\0'; setenv(name, value, 1); ficlFree(name); ficlFree(value); #endif return; } void ficlSetenvq(FICL_VM *pVM) { #ifndef TESTMAIN char *name, *value; #endif char *namep, *valuep; int names, values, overwrite; #if FICL_ROBUST > 1 vmCheckStack(pVM, 5, 0); #endif overwrite = stackPopINT(pVM->pStack); names = stackPopINT(pVM->pStack); namep = (char*) stackPopPtr(pVM->pStack); values = stackPopINT(pVM->pStack); valuep = (char*) stackPopPtr(pVM->pStack); #ifndef TESTMAIN name = (char*) ficlMalloc(names+1); if (!name) vmThrowErr(pVM, "Error: out of memory"); strncpy(name, namep, names); name[names] = '\0'; value = (char*) ficlMalloc(values+1); if (!value) vmThrowErr(pVM, "Error: out of memory"); strncpy(value, valuep, values); value[values] = '\0'; setenv(name, value, overwrite); ficlFree(name); ficlFree(value); #endif return; } void ficlGetenv(FICL_VM *pVM) { #ifndef TESTMAIN char *name, *value; #endif char *namep; int names; #if FICL_ROBUST > 1 vmCheckStack(pVM, 2, 2); #endif names = stackPopINT(pVM->pStack); namep = (char*) stackPopPtr(pVM->pStack); #ifndef TESTMAIN name = (char*) ficlMalloc(names+1); if (!name) vmThrowErr(pVM, "Error: out of memory"); strncpy(name, namep, names); name[names] = '\0'; value = getenv(name); ficlFree(name); if(value != NULL) { stackPushPtr(pVM->pStack, value); stackPushINT(pVM->pStack, strlen(value)); } else #endif stackPushINT(pVM->pStack, -1); return; } void ficlUnsetenv(FICL_VM *pVM) { #ifndef TESTMAIN char *name; #endif char *namep; int names; #if FICL_ROBUST > 1 vmCheckStack(pVM, 2, 0); #endif names = stackPopINT(pVM->pStack); namep = (char*) stackPopPtr(pVM->pStack); #ifndef TESTMAIN name = (char*) ficlMalloc(names+1); if (!name) vmThrowErr(pVM, "Error: out of memory"); strncpy(name, namep, names); name[names] = '\0'; unsetenv(name); ficlFree(name); #endif return; } void ficlCopyin(FICL_VM *pVM) { void* src; vm_offset_t dest; size_t len; #if FICL_ROBUST > 1 vmCheckStack(pVM, 3, 0); #endif len = stackPopINT(pVM->pStack); dest = stackPopINT(pVM->pStack); src = stackPopPtr(pVM->pStack); #ifndef TESTMAIN archsw.arch_copyin(src, dest, len); #endif return; } void ficlCopyout(FICL_VM *pVM) { void* dest; vm_offset_t src; size_t len; #if FICL_ROBUST > 1 vmCheckStack(pVM, 3, 0); #endif len = stackPopINT(pVM->pStack); dest = stackPopPtr(pVM->pStack); src = stackPopINT(pVM->pStack); #ifndef TESTMAIN archsw.arch_copyout(src, dest, len); #endif return; } void ficlFindfile(FICL_VM *pVM) { #ifndef TESTMAIN char *name, *type; #endif char *namep, *typep; struct preloaded_file* fp; int names, types; #if FICL_ROBUST > 1 vmCheckStack(pVM, 4, 1); #endif types = stackPopINT(pVM->pStack); typep = (char*) stackPopPtr(pVM->pStack); names = stackPopINT(pVM->pStack); namep = (char*) stackPopPtr(pVM->pStack); #ifndef TESTMAIN name = (char*) ficlMalloc(names+1); if (!name) vmThrowErr(pVM, "Error: out of memory"); strncpy(name, namep, names); name[names] = '\0'; type = (char*) ficlMalloc(types+1); if (!type) vmThrowErr(pVM, "Error: out of memory"); strncpy(type, typep, types); type[types] = '\0'; fp = file_findfile(name, type); #else fp = NULL; #endif stackPushPtr(pVM->pStack, fp); return; } #ifndef TESTMAIN #ifdef HAVE_PNP void ficlPnpdevices(FICL_VM *pVM) { static int pnp_devices_initted = 0; #if FICL_ROBUST > 1 vmCheckStack(pVM, 0, 1); #endif if(!pnp_devices_initted) { STAILQ_INIT(&pnp_devices); pnp_devices_initted = 1; } stackPushPtr(pVM->pStack, &pnp_devices); return; } void ficlPnphandlers(FICL_VM *pVM) { #if FICL_ROBUST > 1 vmCheckStack(pVM, 0, 1); #endif stackPushPtr(pVM->pStack, pnphandlers); return; } #endif #endif /* ndef TESTMAIN */ void ficlCcall(FICL_VM *pVM) { int (*func)(int, ...); int result, p[10]; int nparam, i; #if FICL_ROBUST > 1 vmCheckStack(pVM, 2, 0); #endif func = stackPopPtr(pVM->pStack); nparam = stackPopINT(pVM->pStack); #if FICL_ROBUST > 1 vmCheckStack(pVM, nparam, 1); #endif for (i = 0; i < nparam; i++) p[i] = stackPopINT(pVM->pStack); result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]); stackPushINT(pVM->pStack, result); return; } /************************************************************************** f i c l E x e c F D ** reads in text from file fd and passes it to ficlExec() * returns VM_OUTOFTEXT on success or the ficlExec() error code on * failure. */ #define nLINEBUF 256 int ficlExecFD(FICL_VM *pVM, int fd) { char cp[nLINEBUF]; int nLine = 0, rval = VM_OUTOFTEXT; char ch; CELL id; id = pVM->sourceID; pVM->sourceID.i = fd; /* feed each line to ficlExec */ while (1) { int status, i; i = 0; while ((status = read(fd, &ch, 1)) > 0 && ch != '\n') cp[i++] = ch; nLine++; if (!i) { if (status < 1) break; continue; } rval = ficlExecC(pVM, cp, i); if(rval != VM_QUIT && rval != VM_USEREXIT && rval != VM_OUTOFTEXT) { pVM->sourceID = id; return rval; } } /* ** Pass an empty line with SOURCE-ID == -1 to flush ** any pending REFILLs (as required by FILE wordset) */ pVM->sourceID.i = -1; ficlExec(pVM, ""); pVM->sourceID = id; return rval; } static void displayCellNoPad(FICL_VM *pVM) { CELL c; #if FICL_ROBUST > 1 vmCheckStack(pVM, 1, 0); #endif c = stackPop(pVM->pStack); ltoa((c).i, pVM->pad, pVM->base); vmTextOut(pVM, pVM->pad, 0); return; } /* isdir? - Return whether an fd corresponds to a directory. * * isdir? ( fd -- bool ) */ static void isdirQuestion(FICL_VM *pVM) { struct stat sb; FICL_INT flag; int fd; #if FICL_ROBUST > 1 vmCheckStack(pVM, 1, 1); #endif fd = stackPopINT(pVM->pStack); flag = FICL_FALSE; do { if (fd < 0) break; if (fstat(fd, &sb) < 0) break; if (!S_ISDIR(sb.st_mode)) break; flag = FICL_TRUE; } while (0); stackPushINT(pVM->pStack, flag); } /* fopen - open a file and return new fd on stack. * * fopen ( ptr count mode -- fd ) */ static void pfopen(FICL_VM *pVM) { int mode, fd, count; char *ptr, *name; #if FICL_ROBUST > 1 vmCheckStack(pVM, 3, 1); #endif mode = stackPopINT(pVM->pStack); /* get mode */ count = stackPopINT(pVM->pStack); /* get count */ ptr = stackPopPtr(pVM->pStack); /* get ptr */ if ((count < 0) || (ptr == NULL)) { stackPushINT(pVM->pStack, -1); return; } /* ensure that the string is null terminated */ name = (char *)malloc(count+1); bcopy(ptr,name,count); name[count] = 0; /* open the file */ fd = open(name, mode); free(name); stackPushINT(pVM->pStack, fd); return; } /* fclose - close a file who's fd is on stack. * * fclose ( fd -- ) */ static void pfclose(FICL_VM *pVM) { int fd; #if FICL_ROBUST > 1 vmCheckStack(pVM, 1, 0); #endif fd = stackPopINT(pVM->pStack); /* get fd */ if (fd != -1) close(fd); return; } /* fread - read file contents * * fread ( fd buf nbytes -- nread ) */ static void pfread(FICL_VM *pVM) { int fd, len; char *buf; #if FICL_ROBUST > 1 vmCheckStack(pVM, 3, 1); #endif len = stackPopINT(pVM->pStack); /* get number of bytes to read */ buf = stackPopPtr(pVM->pStack); /* get buffer */ fd = stackPopINT(pVM->pStack); /* get fd */ if (len > 0 && buf && fd != -1) stackPushINT(pVM->pStack, read(fd, buf, len)); else stackPushINT(pVM->pStack, -1); return; } /* freaddir - read directory contents * * freaddir ( fd -- ptr len TRUE | FALSE ) */ static void pfreaddir(FICL_VM *pVM) { #ifdef TESTMAIN static struct dirent dirent; struct stat sb; char *buf; off_t off, ptr; u_int blksz; int bufsz; #endif struct dirent *d; int fd; #if FICL_ROBUST > 1 vmCheckStack(pVM, 1, 3); #endif fd = stackPopINT(pVM->pStack); #if TESTMAIN /* * The readdirfd() function is specific to the loader environment. * We do the best we can to make freaddir work, but it's not at * all guaranteed. */ d = NULL; buf = NULL; do { if (fd == -1) break; if (fstat(fd, &sb) == -1) break; blksz = (sb.st_blksize) ? sb.st_blksize : getpagesize(); if ((blksz & (blksz - 1)) != 0) break; buf = malloc(blksz); if (buf == NULL) break; off = lseek(fd, 0LL, SEEK_CUR); if (off == -1) break; ptr = off; if (lseek(fd, 0, SEEK_SET) == -1) break; bufsz = getdents(fd, buf, blksz); while (bufsz > 0 && bufsz <= ptr) { ptr -= bufsz; bufsz = getdents(fd, buf, blksz); } if (bufsz <= 0) break; d = (void *)(buf + ptr); dirent = *d; off += d->d_reclen; d = (lseek(fd, off, SEEK_SET) != off) ? NULL : &dirent; } while (0); if (buf != NULL) free(buf); #else d = readdirfd(fd); #endif if (d != NULL) { stackPushPtr(pVM->pStack, d->d_name); stackPushINT(pVM->pStack, strlen(d->d_name)); stackPushINT(pVM->pStack, FICL_TRUE); } else { stackPushINT(pVM->pStack, FICL_FALSE); } } /* fload - interpret file contents * * fload ( fd -- ) */ static void pfload(FICL_VM *pVM) { int fd; #if FICL_ROBUST > 1 vmCheckStack(pVM, 1, 0); #endif fd = stackPopINT(pVM->pStack); /* get fd */ if (fd != -1) ficlExecFD(pVM, fd); return; } /* fwrite - write file contents * * fwrite ( fd buf nbytes -- nwritten ) */ static void pfwrite(FICL_VM *pVM) { int fd, len; char *buf; #if FICL_ROBUST > 1 vmCheckStack(pVM, 3, 1); #endif len = stackPopINT(pVM->pStack); /* get number of bytes to read */ buf = stackPopPtr(pVM->pStack); /* get buffer */ fd = stackPopINT(pVM->pStack); /* get fd */ if (len > 0 && buf && fd != -1) stackPushINT(pVM->pStack, write(fd, buf, len)); else stackPushINT(pVM->pStack, -1); return; } /* fseek - seek to a new position in a file * * fseek ( fd ofs whence -- pos ) */ static void pfseek(FICL_VM *pVM) { int fd, pos, whence; #if FICL_ROBUST > 1 vmCheckStack(pVM, 3, 1); #endif whence = stackPopINT(pVM->pStack); pos = stackPopINT(pVM->pStack); fd = stackPopINT(pVM->pStack); stackPushINT(pVM->pStack, lseek(fd, pos, whence)); return; } /* key - get a character from stdin * * key ( -- char ) */ static void key(FICL_VM *pVM) { #if FICL_ROBUST > 1 vmCheckStack(pVM, 0, 1); #endif stackPushINT(pVM->pStack, getchar()); return; } /* key? - check for a character from stdin (FACILITY) * * key? ( -- flag ) */ static void keyQuestion(FICL_VM *pVM) { #if FICL_ROBUST > 1 vmCheckStack(pVM, 0, 1); #endif #ifdef TESTMAIN /* XXX Since we don't fiddle with termios, let it always succeed... */ stackPushINT(pVM->pStack, FICL_TRUE); #else /* But here do the right thing. */ stackPushINT(pVM->pStack, ischar()? FICL_TRUE : FICL_FALSE); #endif return; } /* seconds - gives number of seconds since beginning of time * * beginning of time is defined as: * * BTX - number of seconds since midnight * FreeBSD - number of seconds since Jan 1 1970 * * seconds ( -- u ) */ static void pseconds(FICL_VM *pVM) { #if FICL_ROBUST > 1 vmCheckStack(pVM,0,1); #endif stackPushUNS(pVM->pStack, (FICL_UNS) time(NULL)); return; } /* ms - wait at least that many milliseconds (FACILITY) * * ms ( u -- ) * */ static void ms(FICL_VM *pVM) { #if FICL_ROBUST > 1 vmCheckStack(pVM,1,0); #endif #ifdef TESTMAIN usleep(stackPopUNS(pVM->pStack)*1000); #else delay(stackPopUNS(pVM->pStack)*1000); #endif return; } /* fkey - get a character from a file * * fkey ( file -- char ) */ static void fkey(FICL_VM *pVM) { int i, fd; char ch; #if FICL_ROBUST > 1 vmCheckStack(pVM, 1, 1); #endif fd = stackPopINT(pVM->pStack); i = read(fd, &ch, 1); stackPushINT(pVM->pStack, i > 0 ? ch : -1); return; } + +#ifdef __i386__ /* + * pcibios-device-count (devid -- count) + * + * Returns the PCI BIOS' count of how many devices matching devid are in the system. + * devid is the 32-bit vendor + device. + */ +static void +ficlPciBiosCountDevices(FICL_VM *pVM) +{ + uint32_t devid; + int i; + + devid = stackPopINT(pVM->pStack); + + i = biospci_count_device_type(devid); + + stackPushINT(pVM->pStack, i); +} + +/* + * pcibios-write-config (locator offset width value -- ) + * + * Writes the specified config register. + * Locator is bus << 8 | device << 3 | fuction + * offset is the pci config register + * width is 0 for byte, 1 for word, 2 for dword + * value is the value to write + */ +static void +ficlPciBiosWriteConfig(FICL_VM *pVM) +{ + uint32_t value, width, offset, locator; + + value = stackPopINT(pVM->pStack); + width = stackPopINT(pVM->pStack); + offset = stackPopINT(pVM->pStack); + locator = stackPopINT(pVM->pStack); + + biospci_write_config(locator, offset, width, value); +} + +/* + * pcibios-read-config (locator offset width -- value) + * + * Reads the specified config register. + * Locator is bus << 8 | device << 3 | fuction + * offset is the pci config register + * width is 0 for byte, 1 for word, 2 for dword + * value is the value to read from the register + */ +static void +ficlPciBiosReadConfig(FICL_VM *pVM) +{ + uint32_t value, width, offset, locator; + + width = stackPopINT(pVM->pStack); + offset = stackPopINT(pVM->pStack); + locator = stackPopINT(pVM->pStack); + + biospci_read_config(locator, offset, width, &value); + + stackPushINT(pVM->pStack, value); +} + +/* + * pcibios-find-devclass (class index -- locator) + * + * Finds the index'th instance of class in the pci tree. + * must be an exact match. + * class is the class to search for. + * index 0..N (set to 0, increment until error) + * + * Locator is bus << 8 | device << 3 | fuction (or -1 on error) + */ +static void +ficlPciBiosFindDevclass(FICL_VM *pVM) +{ + uint32_t index, class, locator; + + index = stackPopINT(pVM->pStack); + class = stackPopINT(pVM->pStack); + + if (biospci_find_devclass(class, index, &locator)) + locator = 0xffffffff; + + stackPushINT(pVM->pStack, locator); +} + +/* + * pcibios-find-device(devid index -- locator) + * + * Finds the index'th instance of devid in the pci tree. + * must be an exact match. + * class is the class to search for. + * index 0..N (set to 0, increment until error) + * + * Locator is bus << 8 | device << 3 | fuction (or -1 on error) + */ +static void +ficlPciBiosFindDevice(FICL_VM *pVM) +{ + uint32_t index, devid, locator; + + index = stackPopINT(pVM->pStack); + devid = stackPopINT(pVM->pStack); + + if (biospci_find_device(devid, index, &locator)) + locator = 0xffffffff; + + stackPushINT(pVM->pStack, locator); +} + +/* + * pcibios-find-device(bus device function -- locator) + * + * converts bus, device, function to locator. + * + * Locator is bus << 8 | device << 3 | fuction + */ +static void +ficlPciBiosLocator(FICL_VM *pVM) +{ + uint32_t bus, device, function, locator; + + function = stackPopINT(pVM->pStack); + device = stackPopINT(pVM->pStack); + bus = stackPopINT(pVM->pStack); + + locator = biospci_locator(bus, device, function); + + stackPushINT(pVM->pStack, locator); +} +#endif + +/* ** Retrieves free space remaining on the dictionary */ static void freeHeap(FICL_VM *pVM) { stackPushINT(pVM->pStack, dictCellsAvail(ficlGetDict(pVM->pSys))); } /******************* Increase dictionary size on-demand ******************/ static void ficlDictThreshold(FICL_VM *pVM) { stackPushPtr(pVM->pStack, &dictThreshold); } static void ficlDictIncrease(FICL_VM *pVM) { stackPushPtr(pVM->pStack, &dictIncrease); } - /************************************************************************** f i c l C o m p i l e P l a t f o r m ** Build FreeBSD platform extensions into the system dictionary **************************************************************************/ void ficlCompilePlatform(FICL_SYSTEM *pSys) { FICL_DICT *dp = pSys->dp; assert (dp); dictAppendWord(dp, ".#", displayCellNoPad, FW_DEFAULT); dictAppendWord(dp, "isdir?", isdirQuestion, FW_DEFAULT); dictAppendWord(dp, "fopen", pfopen, FW_DEFAULT); dictAppendWord(dp, "fclose", pfclose, FW_DEFAULT); dictAppendWord(dp, "fread", pfread, FW_DEFAULT); dictAppendWord(dp, "freaddir", pfreaddir, FW_DEFAULT); dictAppendWord(dp, "fload", pfload, FW_DEFAULT); dictAppendWord(dp, "fkey", fkey, FW_DEFAULT); dictAppendWord(dp, "fseek", pfseek, FW_DEFAULT); dictAppendWord(dp, "fwrite", pfwrite, FW_DEFAULT); dictAppendWord(dp, "key", key, FW_DEFAULT); dictAppendWord(dp, "key?", keyQuestion, FW_DEFAULT); dictAppendWord(dp, "ms", ms, FW_DEFAULT); dictAppendWord(dp, "seconds", pseconds, FW_DEFAULT); dictAppendWord(dp, "heap?", freeHeap, FW_DEFAULT); dictAppendWord(dp, "dictthreshold", ficlDictThreshold, FW_DEFAULT); dictAppendWord(dp, "dictincrease", ficlDictIncrease, FW_DEFAULT); dictAppendWord(dp, "setenv", ficlSetenv, FW_DEFAULT); dictAppendWord(dp, "setenv?", ficlSetenvq, FW_DEFAULT); dictAppendWord(dp, "getenv", ficlGetenv, FW_DEFAULT); dictAppendWord(dp, "unsetenv", ficlUnsetenv, FW_DEFAULT); dictAppendWord(dp, "copyin", ficlCopyin, FW_DEFAULT); dictAppendWord(dp, "copyout", ficlCopyout, FW_DEFAULT); dictAppendWord(dp, "findfile", ficlFindfile, FW_DEFAULT); dictAppendWord(dp, "ccall", ficlCcall, FW_DEFAULT); #ifndef TESTMAIN #ifdef __i386__ dictAppendWord(dp, "outb", ficlOutb, FW_DEFAULT); dictAppendWord(dp, "inb", ficlInb, FW_DEFAULT); #endif #ifdef HAVE_PNP dictAppendWord(dp, "pnpdevices",ficlPnpdevices, FW_DEFAULT); dictAppendWord(dp, "pnphandlers",ficlPnphandlers, FW_DEFAULT); #endif #endif +#ifdef __i386__ + dictAppendWord(dp, "pcibios-device-count", ficlPciBiosCountDevices, FW_DEFAULT); + dictAppendWord(dp, "pcibios-read-config", ficlPciBiosReadConfig, FW_DEFAULT); + dictAppendWord(dp, "pcibios-write-config", ficlPciBiosWriteConfig, FW_DEFAULT); + dictAppendWord(dp, "pcibios-find-devclass", ficlPciBiosFindDevclass, FW_DEFAULT); + dictAppendWord(dp, "pcibios-find-device", ficlPciBiosFindDevice, FW_DEFAULT); + dictAppendWord(dp, "pcibios-locator", ficlPciBiosLocator, FW_DEFAULT); +#endif #if defined(PC98) ficlSetEnv(pSys, "arch-pc98", FICL_TRUE); #elif defined(__i386__) ficlSetEnv(pSys, "arch-i386", FICL_TRUE); ficlSetEnv(pSys, "arch-powerpc", FICL_FALSE); #elif defined(__powerpc__) ficlSetEnv(pSys, "arch-i386", FICL_FALSE); ficlSetEnv(pSys, "arch-powerpc", FICL_TRUE); #endif return; } - Index: head/sys/boot/forth/pcibios.4th =================================================================== --- head/sys/boot/forth/pcibios.4th (nonexistent) +++ head/sys/boot/forth/pcibios.4th (revision 271406) @@ -0,0 +1,47 @@ +\ Copyright (c) 2014 M. Warner Losh +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +only forth also support-functions also builtins definitions + +\ pci-device-count pci-id +\ +\ Counts the number of instances of pci-id in the system and reports +\ it to the user. +: pci-device-count + 0= if ( interpreted ) get_arguments then + + 0= if ." Need an argument" cr abort then + \ First argument is 0 when we're interprated. See support.4th + \ for get_arguments reading the rest of the line and parsing it + \ stack: argN lenN ... arg1 len1 N + hex ?number decimal + 0= if ." Bad pci-id given (must be legal hex value)" cr abort then + dup pcibios-device-count ." Found " . ." instances of " hex . decimal cr +; + +also forth definitions also builtins + +builtin: pci-device-count Property changes on: head/sys/boot/forth/pcibios.4th ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/sys/boot/i386/libi386/biospci.c =================================================================== --- head/sys/boot/i386/libi386/biospci.c (revision 271405) +++ head/sys/boot/i386/libi386/biospci.c (revision 271406) @@ -1,350 +1,428 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * PnP enumerator using the PCI BIOS. */ #include #include #include #include #include #include "libi386.h" /* * Stupid PCI BIOS interface doesn't let you simply enumerate everything * that's there, instead you have to ask it if it has something. * * So we have to scan by class code, subclass code and sometimes programming * interface. */ struct pci_progif { int pi_code; const char *pi_name; }; static struct pci_progif progif_null[] = { {0x0, NULL}, {-1, NULL} }; static struct pci_progif progif_display[] = { {0x0, "VGA"}, {0x1, "8514"}, {-1, NULL} }; static struct pci_progif progif_ide[] = { {0x00, NULL}, {0x01, NULL}, {0x02, NULL}, {0x03, NULL}, {0x04, NULL}, {0x05, NULL}, {0x06, NULL}, {0x07, NULL}, {0x08, NULL}, {0x09, NULL}, {0x0a, NULL}, {0x0b, NULL}, {0x0c, NULL}, {0x0d, NULL}, {0x0e, NULL}, {0x0f, NULL}, {0x80, NULL}, {0x81, NULL}, {0x82, NULL}, {0x83, NULL}, {0x84, NULL}, {0x85, NULL}, {0x86, NULL}, {0x87, NULL}, {0x88, NULL}, {0x89, NULL}, {0x8a, NULL}, {0x8b, NULL}, {0x8c, NULL}, {0x8d, NULL}, {0x8e, NULL}, {0x8f, NULL}, {-1, NULL} }; static struct pci_progif progif_serial[] = { {0x0, "8250"}, {0x1, "16450"}, {0x2, "16550"}, {-1, NULL} }; static struct pci_progif progif_parallel[] = { {0x0, "Standard"}, {0x1, "Bidirectional"}, {0x2, "ECP"}, {-1, NULL} }; static struct pci_progif progif_firewire[] = { {0x10, "OHCI"}, {-1, NULL} }; struct pci_subclass { int ps_subclass; const char *ps_name; struct pci_progif *ps_progif; /* if set, use for programming interface value(s) */ }; static struct pci_subclass subclass_old[] = { {0x0, "Old non-VGA", progif_null}, {0x1, "Old VGA", progif_null}, {-1, NULL, NULL} }; static struct pci_subclass subclass_mass[] = { {0x0, "SCSI", progif_null}, {0x1, "IDE", progif_ide}, {0x2, "Floppy disk", progif_null}, {0x3, "IPI", progif_null}, {0x4, "RAID", progif_null}, {0x80, "mass storage", progif_null}, {-1, NULL, NULL} }; static struct pci_subclass subclass_net[] = { {0x0, "Ethernet", progif_null}, {0x1, "Token ring", progif_null}, {0x2, "FDDI", progif_null}, {0x3, "ATM", progif_null}, {0x80, "network", progif_null}, {-1, NULL, NULL} }; static struct pci_subclass subclass_display[] = { {0x0, NULL, progif_display}, {0x1, "XGA", progif_null}, {0x80, "other", progif_null}, {-1, NULL, NULL} }; static struct pci_subclass subclass_comms[] = { {0x0, "serial", progif_serial}, {0x1, "parallel", progif_parallel}, {0x80, "communications", progif_null}, {-1, NULL, NULL} }; static struct pci_subclass subclass_serial[] = { {0x0, "FireWire", progif_firewire}, {0x1, "ACCESS.bus", progif_null}, {0x2, "SSA", progif_null}, {0x3, "USB", progif_null}, {0x4, "Fibrechannel", progif_null}, {-1, NULL, NULL} }; static struct pci_class { int pc_class; const char *pc_name; struct pci_subclass *pc_subclass; } pci_classes[] = { {0x0, "device", subclass_old}, {0x1, "controller", subclass_mass}, {0x2, "controller", subclass_net}, {0x3, "display", subclass_display}, {0x7, "controller", subclass_comms}, {0xc, "controller", subclass_serial}, {-1, NULL, NULL} }; static void biospci_enumerate(void); static void biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi); -static int biospci_version; -static int biospci_hwcap; - struct pnphandler biospcihandler = { "PCI BIOS", biospci_enumerate }; -static void -biospci_enumerate(void) +#define PCI_BIOS_PRESENT 0xb101 +#define FIND_PCI_DEVICE 0xb102 +#define FIND_PCI_CLASS_CODE 0xb103 +#define GENERATE_SPECIAL_CYCLE 0xb106 +#define READ_CONFIG_BYTE 0xb108 +#define READ_CONFIG_WORD 0xb109 +#define READ_CONFIG_DWORD 0xb10a +#define WRITE_CONFIG_BYTE 0xb10b +#define WRITE_CONFIG_WORD 0xb10c +#define WRITE_CONFIG_DWORD 0xb10d +#define GET_IRQ_ROUTING_OPTIONS 0xb10e +#define SET_PCI_IRQ 0xb10f + +#define PCI_INT 0x1a + +#define PCI_SIGNATURE 0x20494350 /* AKA "PCI " */ + +void +biospci_detect(void) { - int device_index, err; - uint32_t locator, devid; - struct pci_class *pc; - struct pci_subclass *psc; - struct pci_progif *ppi; + uint16_t version, hwcap, maxbus; + char buf[24]; /* Find the PCI BIOS */ v86.ctl = V86_FLAGS; - v86.addr = 0x1a; - v86.eax = 0xb101; + v86.addr = PCI_INT; + v86.eax = PCI_BIOS_PRESENT; v86.edi = 0x0; v86int(); /* Check for OK response */ if (V86_CY(v86.efl) || ((v86.eax & 0xff00) != 0) || - (v86.edx != 0x20494350)) + (v86.edx != PCI_SIGNATURE)) return; - biospci_version = v86.ebx & 0xffff; - biospci_hwcap = v86.eax & 0xff; + version = v86.ebx & 0xffff; + hwcap = v86.eax & 0xff; + maxbus = v86.ecx & 0xff; #if 0 - printf("PCI BIOS %d.%d%s%s\n", - bcd2bin((biospci_version >> 8) & 0xf), bcd2bin(biospci_version & 0xf), - (biospci_hwcap & 1) ? " config1" : "", (biospci_hwcap & 2) ? " config2" : ""); + printf("PCI BIOS %d.%d%s%s maxbus %d\n", + bcd2bin((version >> 8) & 0xf), bcd2bin(version & 0xf), + (hwcap & 1) ? " config1" : "", (hwcap & 2) ? " config2" : "", + maxbus); #endif + sprintf(buf, "%d", bcd2bin((version >> 8) & 0xf)); + setenv("pcibios.major", buf, 1); + sprintf(buf, "%d", bcd2bin(version & 0xf)); + setenv("pcibios.minor", buf, 1); + sprintf(buf, "%d", !!(hwcap & 1)); + setenv("pcibios.config1", buf, 1); + sprintf(buf, "%d", !!(hwcap & 2)); + setenv("pcibios.config2", buf, 1); + sprintf(buf, "%d", maxbus); + setenv("pcibios.maxbus", buf, 1); + +} + +static void +biospci_enumerate(void) +{ + int device_index, err; + uint32_t locator, devid; + struct pci_class *pc; + struct pci_subclass *psc; + struct pci_progif *ppi; + /* Iterate over known classes */ for (pc = pci_classes; pc->pc_class >= 0; pc++) { /* Iterate over subclasses */ for (psc = pc->pc_subclass; psc->ps_subclass >= 0; psc++) { /* Iterate over programming interfaces */ for (ppi = psc->ps_progif; ppi->pi_code >= 0; ppi++) { /* Scan for matches */ for (device_index = 0; ; device_index++) { /* Look for a match */ err = biospci_find_devclass((pc->pc_class << 16) + (psc->ps_subclass << 8) + ppi->pi_code, device_index, &locator); if (err != 0) break; /* Read the device identifier from the nominated device */ err = biospci_read_config(locator, 0, 2, &devid); if (err != 0) break; /* We have the device ID, create a PnP object and save everything */ biospci_addinfo(devid, pc, psc, ppi); } } } } } static void biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi) { struct pnpinfo *pi; char desc[80]; /* build the description */ desc[0] = 0; if (ppi->pi_name != NULL) { strcat(desc, ppi->pi_name); strcat(desc, " "); } if (psc->ps_name != NULL) { strcat(desc, psc->ps_name); strcat(desc, " "); } if (pc->pc_name != NULL) strcat(desc, pc->pc_name); pi = pnp_allocinfo(); pi->pi_desc = strdup(desc); sprintf(desc,"0x%08x", devid); pnp_addident(pi, desc); pnp_addinfo(pi); } int biospci_find_devclass(uint32_t class, int index, uint32_t *locator) { v86.ctl = V86_FLAGS; - v86.addr = 0x1a; - v86.eax = 0xb103; + v86.addr = PCI_INT; + v86.eax = FIND_PCI_CLASS_CODE; v86.ecx = class; v86.esi = index; v86int(); /* error */ if (V86_CY(v86.efl) || (v86.eax & 0xff00)) return (-1); *locator = v86.ebx; return (0); } + +int +biospci_find_device(uint32_t devid, int index, uint32_t *locator) +{ + v86.ctl = V86_FLAGS; + v86.addr = PCI_INT; + v86.eax = FIND_PCI_DEVICE; + v86.edx = devid & 0xffff; /* EDX - Vendor ID */ + v86.ecx = (devid >> 16) & 0xffff; /* ECX - Device ID */ + v86.esi = index; + v86int(); + + /* error */ + if (V86_CY(v86.efl) || (v86.eax & 0xff00)) + return (-1); + + *locator = v86.ebx; + return (0); +} /* * Configuration space access methods. * width = 0(byte), 1(word) or 2(dword). */ int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val) { v86.ctl = V86_FLAGS; - v86.addr = 0x1a; - v86.eax = 0xb10b + width; + v86.addr = PCI_INT; + v86.eax = WRITE_CONFIG_BYTE + width; v86.ebx = locator; v86.edi = offset; v86.ecx = val; v86int(); /* error */ if (V86_CY(v86.efl) || (v86.eax & 0xff00)) return (-1); return(0); } int biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val) { v86.ctl = V86_FLAGS; - v86.addr = 0x1a; - v86.eax = 0xb108 + width; + v86.addr = PCI_INT; + v86.eax = READ_CONFIG_BYTE + width; v86.ebx = locator; v86.edi = offset; v86int(); /* error */ if (V86_CY(v86.efl) || (v86.eax & 0xff00)) return (-1); *val = v86.ecx; return (0); } uint32_t biospci_locator(int8_t bus, uint8_t device, uint8_t function) { return ((bus << 8) | ((device & 0x1f) << 3) | (function & 0x7)); +} + +/* + * Counts the number of instances of devid we have in the system, as least as + * far as the PCI BIOS is able to tell. + */ +int +biospci_count_device_type(uint32_t devid) +{ + int i; + + for (i = 0; 1; i++) { + v86.ctl = V86_FLAGS; + v86.addr = PCI_INT; + v86.eax = FIND_PCI_DEVICE; + v86.edx = devid & 0xffff; /* EDX - Vendor ID */ + v86.ecx = (devid >> 16) & 0xffff; /* ECX - Device ID */ + v86.esi = i; + v86int(); + if (V86_CY(v86.efl) || (v86.eax & 0xff00)) + break; + + } + return i; } Index: head/sys/boot/i386/libi386/libi386.h =================================================================== --- head/sys/boot/i386/libi386/libi386.h (revision 271405) +++ head/sys/boot/i386/libi386/libi386.h (revision 271406) @@ -1,125 +1,128 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * i386 fully-qualified device descriptor. * Note, this must match the 'struct devdesc' declaration * in bootstrap.h and also with struct zfs_devdesc for zfs * support. */ struct i386_devdesc { struct devsw *d_dev; int d_type; int d_unit; union { struct { void *data; int slice; int partition; off_t offset; } biosdisk; struct { void *data; } bioscd; struct { void *data; uint64_t pool_guid; uint64_t root_guid; } zfs; } d_kind; }; int i386_getdev(void **vdev, const char *devspec, const char **path); char *i386_fmtdev(void *vdev); int i386_setcurrdev(struct env_var *ev, int flags, const void *value); extern struct devdesc currdev; /* our current device */ #define MAXDEV 31 /* maximum number of distinct devices */ #define MAXBDDEV MAXDEV /* exported devices XXX rename? */ extern struct devsw bioscd; extern struct devsw biosdisk; extern struct devsw pxedisk; extern struct fs_ops pxe_fsops; int bc_add(int biosdev); /* Register CD booted from. */ int bc_getdev(struct i386_devdesc *dev); /* return dev_t for (dev) */ int bc_bios2unit(int biosdev); /* xlate BIOS device -> bioscd unit */ int bc_unit2bios(int unit); /* xlate bioscd unit -> BIOS device */ uint32_t bd_getbigeom(int bunit); /* return geometry in bootinfo format */ int bd_bios2unit(int biosdev); /* xlate BIOS device -> biosdisk unit */ int bd_unit2bios(int unit); /* xlate biosdisk unit -> BIOS device */ int bd_getdev(struct i386_devdesc *dev); /* return dev_t for (dev) */ ssize_t i386_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t i386_copyout(const vm_offset_t src, void *dest, const size_t len); ssize_t i386_readin(const int fd, vm_offset_t dest, const size_t len); struct preloaded_file; void bios_addsmapdata(struct preloaded_file *); void bios_getsmap(void); void bios_getmem(void); extern uint32_t bios_basemem; /* base memory in bytes */ extern uint32_t bios_extmem; /* extended memory in bytes */ extern vm_offset_t memtop; /* last address of physical memory + 1 */ extern vm_offset_t memtop_copyin; /* memtop less heap size for the cases */ /* when heap is at the top of */ /* extended memory; for other cases */ /* just the same as memtop */ extern uint32_t high_heap_size; /* extended memory region available */ extern vm_offset_t high_heap_base; /* for use as the heap */ +void biospci_detect(void); +int biospci_count_device_type(uint32_t devid); int biospci_find_devclass(uint32_t class, int index, uint32_t *locator); +int biospci_find_device(uint32_t devid, int index, uint32_t *locator); int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val); int biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val); uint32_t biospci_locator(int8_t bus, uint8_t device, uint8_t function); void biosacpi_detect(void); void smbios_detect(void); int i386_autoload(void); int bi_getboothowto(char *kargs); void bi_setboothowto(int howto); vm_offset_t bi_copyenv(vm_offset_t addr); int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernend); int bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernend); char *pxe_default_rc(void); void pxe_enable(void *pxeinfo); Index: head/sys/boot/i386/loader/Makefile =================================================================== --- head/sys/boot/i386/loader/Makefile (revision 271405) +++ head/sys/boot/i386/loader/Makefile (revision 271406) @@ -1,137 +1,138 @@ # $FreeBSD$ .include MK_SSP= no LOADER?= loader PROG= ${LOADER}.sym INTERNALPROG= NEWVERSWHAT?= "bootstrap loader" x86 # architecture-specific loader code SRCS= main.c conf.c vers.c # Put LOADER_FIREWIRE_SUPPORT=yes in /etc/make.conf for FireWire/dcons support .if defined(LOADER_FIREWIRE_SUPPORT) CFLAGS+= -DLOADER_FIREWIRE_SUPPORT LIBFIREWIRE= ${.OBJDIR}/../libfirewire/libfirewire.a .endif # Set by zfsloader Makefile .if defined(LOADER_ZFS_SUPPORT) CFLAGS+= -DLOADER_ZFS_SUPPORT LIBZFSBOOT= ${.OBJDIR}/../../zfs/libzfsboot.a .endif # Enable PXE TFTP or NFS support, not both. .if defined(LOADER_TFTP_SUPPORT) CFLAGS+= -DLOADER_TFTP_SUPPORT .else CFLAGS+= -DLOADER_NFS_SUPPORT .endif # Include bcache code. HAVE_BCACHE= yes # Enable PnP and ISA-PnP code. HAVE_PNP= yes HAVE_ISABUS= yes .if ${MK_FORTH} != "no" # Enable BootForth BOOT_FORTH= yes CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/i386 .if ${MACHINE_CPUARCH} == "amd64" LIBFICL= ${.OBJDIR}/../../ficl32/libficl.a .else LIBFICL= ${.OBJDIR}/../../ficl/libficl.a .endif .endif .if defined(LOADER_BZIP2_SUPPORT) CFLAGS+= -DLOADER_BZIP2_SUPPORT .endif .if !defined(LOADER_NO_GZIP_SUPPORT) CFLAGS+= -DLOADER_GZIP_SUPPORT .endif .if defined(LOADER_NANDFS_SUPPORT) CFLAGS+= -DLOADER_NANDFS_SUPPORT .endif # Always add MI sources .PATH: ${.CURDIR}/../../common .include "${.CURDIR}/../../common/Makefile.inc" CFLAGS+= -I${.CURDIR}/../../common CFLAGS+= -I. CLEANFILES= vers.c ${LOADER} ${LOADER}.bin loader.help CFLAGS+= -Wall LDFLAGS= -static -Ttext 0x0 # i386 standalone support library LIBI386= ${.OBJDIR}/../libi386/libi386.a CFLAGS+= -I${.CURDIR}/.. LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a # BTX components CFLAGS+= -I${.CURDIR}/../btx/lib # Debug me! #CFLAGS+= -g #LDFLAGS+= -g # Pick up ../Makefile.inc early. .include vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version \ ${NEWVERSWHAT} ${LOADER}: ${LOADER}.bin ${BTXLDR} ${BTXKERN} btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ -b ${BTXKERN} ${LOADER}.bin ${LOADER}.bin: ${LOADER}.sym cp ${.ALLSRC} ${.TARGET} strip -R .comment -R .note ${.TARGET} loader.help: help.common help.i386 cat ${.ALLSRC} | awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} FILES= ${LOADER} # XXX INSTALLFLAGS_loader= -b FILESMODE_${LOADER}= ${BINMODE} -b .if !defined(LOADER_ONLY) .PATH: ${.CURDIR}/../../forth FILES+= loader.help loader.4th support.4th loader.conf FILES+= screen.4th frames.4th beastie.4th FILES+= brand.4th check-password.4th color.4th delay.4th FILES+= menu.4th menu-commands.4th menusets.4th shortcuts.4th version.4th +FILES+= pcibios.4th FILESDIR_loader.conf= /boot/defaults .if !exists(${DESTDIR}/boot/loader.rc) FILES+= loader.rc .endif .if !exists(${DESTDIR}/boot/menu.rc) FILES+= menu.rc .endif .endif # XXX crt0.o needs to be first for pxeboot(8) to work OBJS= ${BTXCRT} DPADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND} LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND} .include .if ${MACHINE_CPUARCH} == "amd64" beforedepend ${OBJS}: machine CLEANFILES+= machine CFLAGS+= -DLOADER_PREFER_AMD64 machine: .NOPATH ln -sf ${.CURDIR}/../../../i386/include machine .endif Index: head/sys/boot/i386/loader/main.c =================================================================== --- head/sys/boot/i386/loader/main.c (revision 271405) +++ head/sys/boot/i386/loader/main.c (revision 271406) @@ -1,394 +1,397 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * MD bootstrap main() and assorted miscellaneous * commands. */ #include #include #include #include #include #include #include #include "bootstrap.h" #include "common/bootargs.h" #include "libi386/libi386.h" #include "btxv86.h" #ifdef LOADER_ZFS_SUPPORT #include "../zfs/libzfs.h" #endif CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE); CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); /* Arguments passed in from the boot1/boot2 loader */ static struct bootargs *kargs; static u_int32_t initial_howto; static u_int32_t initial_bootdev; static struct bootinfo *initial_bootinfo; struct arch_switch archsw; /* MI/MD interface boundary */ static void extract_currdev(void); static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); #ifdef LOADER_ZFS_SUPPORT static void i386_zfs_probe(void); #endif /* from vers.c */ extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; /* XXX debugging */ extern char end[]; static void *heap_top; static void *heap_bottom; int main(void) { int i; /* Pick up arguments */ kargs = (void *)__args; initial_howto = kargs->howto; initial_bootdev = kargs->bootdev; initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; /* Initialize the v86 register set to a known-good state. */ bzero(&v86, sizeof(v86)); v86.efl = PSL_RESERVED_DEFAULT | PSL_I; /* * Initialise the heap as early as possible. Once this is done, malloc() is usable. */ bios_getmem(); #if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || \ defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT) if (high_heap_size > 0) { heap_top = PTOV(high_heap_base + high_heap_size); heap_bottom = PTOV(high_heap_base); if (high_heap_base < memtop_copyin) memtop_copyin = high_heap_base; } else #endif { heap_top = (void *)PTOV(bios_basemem); heap_bottom = (void *)end; } setheap(heap_bottom, heap_top); /* * XXX Chicken-and-egg problem; we want to have console output early, but some * console attributes may depend on reading from eg. the boot device, which we * can't do yet. * * We can use printf() etc. once this is done. * If the previous boot stage has requested a serial console, prefer that. */ bi_setboothowto(initial_howto); if (initial_howto & RB_MULTIPLE) { if (initial_howto & RB_SERIAL) setenv("console", "comconsole vidconsole", 1); else setenv("console", "vidconsole comconsole", 1); } else if (initial_howto & RB_SERIAL) setenv("console", "comconsole", 1); else if (initial_howto & RB_MUTE) setenv("console", "nullconsole", 1); cons_probe(); /* * Initialise the block cache */ bcache_init(32, 512); /* 16k cache XXX tune this */ /* * Special handling for PXE and CD booting. */ if (kargs->bootinfo == 0) { /* * We only want the PXE disk to try to init itself in the below * walk through devsw if we actually booted off of PXE. */ if (kargs->bootflags & KARGS_FLAGS_PXE) pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); else if (kargs->bootflags & KARGS_FLAGS_CD) bc_add(initial_bootdev); } archsw.arch_autoload = i386_autoload; archsw.arch_getdev = i386_getdev; archsw.arch_copyin = i386_copyin; archsw.arch_copyout = i386_copyout; archsw.arch_readin = i386_readin; archsw.arch_isainb = isa_inb; archsw.arch_isaoutb = isa_outb; #ifdef LOADER_ZFS_SUPPORT archsw.arch_zfs_probe = i386_zfs_probe; #endif /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); if (initial_bootinfo != NULL) { initial_bootinfo->bi_basemem = bios_basemem / 1024; initial_bootinfo->bi_extmem = bios_extmem / 1024; } /* detect ACPI for future reference */ biosacpi_detect(); /* detect SMBIOS for future reference */ smbios_detect(); + /* detect PCI BIOS for future reference */ + biospci_detect(); + printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); extract_currdev(); /* set $currdev and $loaddev */ setenv("LINES", "24", 1); /* optional */ bios_getsmap(); #ifdef LOADER_TFTP_SUPPORT if (kargs->bootflags & KARGS_FLAGS_PXE) interact(pxe_default_rc()); else #endif interact(NULL); /* if we ever get here, it is an error */ return (1); } /* * Set the 'current device' by (if possible) recovering the boot device as * supplied by the initial bootstrap. * * XXX should be extended for netbooting. */ static void extract_currdev(void) { struct i386_devdesc new_currdev; #ifdef LOADER_ZFS_SUPPORT char buf[20]; struct zfs_boot_args *zargs; #endif int biosdev = -1; /* Assume we are booting from a BIOS disk by default */ new_currdev.d_dev = &biosdisk; /* new-style boot loaders such as pxeldr and cdldr */ if (kargs->bootinfo == 0) { if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { /* we are booting from a CD with cdboot */ new_currdev.d_dev = &bioscd; new_currdev.d_unit = bc_bios2unit(initial_bootdev); } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { /* we are booting from pxeldr */ new_currdev.d_dev = &pxedisk; new_currdev.d_unit = 0; } else { /* we don't know what our boot device is */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } #ifdef LOADER_ZFS_SUPPORT } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { zargs = NULL; /* check for new style extended argument */ if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) zargs = (struct zfs_boot_args *)(kargs + 1); if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, primary_pool)) { /* sufficient data is provided */ new_currdev.d_kind.zfs.pool_guid = zargs->pool; new_currdev.d_kind.zfs.root_guid = zargs->root; if (zargs->size >= sizeof(*zargs) && zargs->primary_vdev != 0) { sprintf(buf, "%llu", zargs->primary_pool); setenv("vfs.zfs.boot.primary_pool", buf, 1); sprintf(buf, "%llu", zargs->primary_vdev); setenv("vfs.zfs.boot.primary_vdev", buf, 1); } } else { /* old style zfsboot block */ new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; new_currdev.d_kind.zfs.root_guid = 0; } new_currdev.d_dev = &zfs_dev; #endif } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { /* The passed-in boot device is bad */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } else { new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); biosdev = initial_bootinfo->bi_bios_dev; /* * If we are booted by an old bootstrap, we have to guess at the BIOS * unit number. We will lose if there is more than one disk type * and we are not booting from the lowest-numbered disk type * (ie. SCSI when IDE also exists). */ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ } new_currdev.d_type = new_currdev.d_dev->dv_type; /* * If we are booting off of a BIOS disk and we didn't succeed in determining * which one we booted off of, just use disk0: as a reasonable default. */ if ((new_currdev.d_type == biosdisk.dv_type) && ((new_currdev.d_unit = bd_bios2unit(biosdev)) == -1)) { printf("Can't work out which disk we are booting from.\n" "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); new_currdev.d_unit = 0; } env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, env_nounset); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); printf("Rebooting...\n"); delay(1000000); __exit(0); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { __exit(code); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { mallocstats(); printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, sbrk(0), heap_top); return(CMD_OK); } #ifdef LOADER_ZFS_SUPPORT COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", command_lszfs); static int command_lszfs(int argc, char *argv[]) { int err; if (argc != 2) { command_errmsg = "wrong number of arguments"; return (CMD_ERROR); } err = zfs_list(argv[1]); if (err != 0) { command_errmsg = strerror(err); return (CMD_ERROR); } return (CMD_OK); } #endif /* ISA bus access functions for PnP. */ static int isa_inb(int port) { return (inb(port)); } static void isa_outb(int port, int value) { outb(port, value); } #ifdef LOADER_ZFS_SUPPORT static void i386_zfs_probe(void) { char devname[32]; int unit; /* * Open all the disks we can find and see if we can reconstruct * ZFS pools from them. */ for (unit = 0; unit < MAXBDDEV; unit++) { if (bd_unit2bios(unit) == -1) break; sprintf(devname, "disk%d:", unit); zfs_probe_dev(devname, NULL); } } #endif