Index: head/sys/boot/efi/libefi/Makefile =================================================================== --- head/sys/boot/efi/libefi/Makefile (revision 307878) +++ head/sys/boot/efi/libefi/Makefile (revision 307879) @@ -1,44 +1,45 @@ # $FreeBSD$ LIB= efi INTERNALLIB= WARNS?= 2 SRCS= delay.c devpath.c efi_console.c efinet.c efipart.c env.c errno.c \ handles.c libefi.c .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SRCS+= time.c .elif ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" SRCS+= time_event.c .endif # We implement a slightly non-standard %S in that it always takes a # CHAR16 that's common in UEFI-land instead of a wchar_t. This only # seems to matter on arm64 where wchar_t defaults to an int instead # of a short. There's no good cast to use here so just ignore the # warnings for now. CWARNFLAGS.efinet.c+= -Wno-format .if ${MACHINE_CPUARCH} == "aarch64" CFLAGS+= -msoft-float -mgeneral-regs-only .endif .if ${MACHINE_ARCH} == "amd64" CFLAGS+= -fPIC -mno-red-zone .endif +CFLAGS+= -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/${MACHINE} CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../../lib/libstand # Pick up the bootstrap header for some interface items CFLAGS+= -I${.CURDIR}/../../common # Handle FreeBSD specific %b and %D printf format specifiers CFLAGS+= ${FORMAT_EXTENSIONS} # Do not use TERM_EMU on arm and arm64 as it doesn't behave well with serial console .if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "aarch64" CFLAGS+= -DTERM_EMU .endif .include Index: head/sys/boot/efi/libefi/env.c =================================================================== --- head/sys/boot/efi/libefi/env.c (revision 307878) +++ head/sys/boot/efi/libefi/env.c (revision 307879) @@ -1,55 +1,234 @@ /* * Copyright (c) 2015 Netflix, Inc. 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$"); +#include +#include #include #include +#include +#include "bootstrap.h" +#include "ficl.h" +int efi_variable_support = 1; + /* * Simple wrappers to the underlying UEFI functions. * See http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES * for details. */ EFI_STATUS efi_get_next_variable_name(UINTN *variable_name_size, CHAR16 *variable_name, EFI_GUID *vendor_guid) { return RS->GetNextVariableName(variable_name_size, variable_name, vendor_guid); } EFI_STATUS efi_get_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, UINT32 *attributes, UINTN *data_size, void *data) { return RS->GetVariable(variable_name, vendor_guid, attributes, data_size, data); } EFI_STATUS efi_set_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, UINT32 attributes, UINTN data_size, void *data) { return RS->SetVariable(variable_name, vendor_guid, attributes, data_size, data); } + +/* + * FreeBSD's loader interaction words and extras + * + * efi-setenv ( value n name n guid n attr -- 0 | -1) + * efi-getenv ( guid n addr n -- addr' n' | -1 ) + * efi-unsetenv ( name n guid n'' -- ) + */ + +/* + * efi-setenv + * efi-setenv ( value n name n guid n attr -- 0 | -1) + * + * Set environment variables using the SetVariable EFI runtime service. + * + * Value and guid are passed through in binary form (so guid needs to be + * converted to binary form from its string form). Name is converted from + * ASCII to CHAR16. Since ficl doesn't have support for internationalization, + * there's no native CHAR16 interface provided. + * + * attr is an int in the bitmask of the following attributes for this variable. + * + * 1 Non volatile + * 2 Boot service access + * 4 Run time access + * (corresponding to the same bits in the UEFI spec). + */ +void +ficlEfiSetenv(FICL_VM *pVM) +{ +#ifndef TESTMAIN + char *value = NULL, *guid = NULL; + CHAR16 *name = NULL; + int i; +#endif + char *namep, *valuep, *guidp; + int names, values, guids, attr; + int status; + uuid_t u; + uint32_t ustatus; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 6, 0); +#endif + attr = stackPopINT(pVM->pStack); + guids = stackPopINT(pVM->pStack); + guidp = (char*)stackPopPtr(pVM->pStack); + names = stackPopINT(pVM->pStack); + namep = (char*)stackPopPtr(pVM->pStack); + values = stackPopINT(pVM->pStack); + valuep = (char*)stackPopPtr(pVM->pStack); + +#ifndef TESTMAIN + guid = (char*)ficlMalloc(guids); + if (guid != NULL) + vmThrowErr(pVM, "Error: out of memory"); + memcpy(guid, guidp, guids); + uuid_from_string(guid, &u, &ustatus); + if (ustatus != uuid_s_ok) { + stackPushINT(pVM->pStack, -1); + goto out; + } + + name = (CHAR16 *)ficlMalloc((names + 1) * sizeof(CHAR16)); + if (name == NULL) + vmThrowErr(pVM, "Error: out of memory"); + for (i = 0; i < names; i++) + name[i] = namep[i]; + name[names] = (CHAR16)0; + + value = (char*)ficlMalloc(values + 1); + if (value != NULL) + vmThrowErr(pVM, "Error: out of memory"); + memcpy(value, valuep, values); + + status = efi_set_variable(name, (EFI_GUID *)&u, attr, values, value); + if (status == EFI_SUCCESS) + stackPushINT(pVM->pStack, 0); + else + stackPushINT(pVM->pStack, -1); +out: + ficlFree(name); + ficlFree(value); + ficlFree(guid); +#endif + + return; +} + +void +ficlEfiGetenv(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 +ficlEfiUnsetenv(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; +} + +/************************************************************************** +** Add FreeBSD UEFI platform extensions into the system dictionary +**************************************************************************/ +void ficlEfiCompilePlatform(FICL_SYSTEM *pSys) +{ + FICL_DICT *dp = pSys->dp; + assert (dp); + + dictAppendWord(dp, "efi-setenv", ficlEfiSetenv, FW_DEFAULT); + dictAppendWord(dp, "efi-getenv", ficlEfiGetenv, FW_DEFAULT); + dictAppendWord(dp, "efi-unsetenv", ficlEfiUnsetenv, FW_DEFAULT); + + /* Would like to export the EFI version, but this will do for now */ + ficlSetEnv(pSys, "efi-boot", 1); + + return; +} + +FICL_COMPILE_SET(ficlEfiCompilePlatform); Index: head/sys/boot/efi/loader/main.c =================================================================== --- head/sys/boot/efi/loader/main.c (revision 307878) +++ head/sys/boot/efi/loader/main.c (revision 307879) @@ -1,1075 +1,1079 @@ /*- * Copyright (c) 2008-2010 Rui Paulo * Copyright (c) 2006 Marcel Moolenaar * 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 ``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 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$"); #include #include #include #include #include #include #include #include #include #include #include #include #ifdef EFI_ZFS_BOOT #include #endif #include "loader_efi.h" extern char bootprog_name[]; extern char bootprog_rev[]; extern char bootprog_date[]; extern char bootprog_maker[]; +/* Force a reference to bring in EFI support from the library */ +extern int efi_variable_support; +int *dummy1 = &efi_variable_support; + struct arch_switch archsw; /* MI/MD interface boundary */ EFI_GUID acpi = ACPI_TABLE_GUID; EFI_GUID acpi20 = ACPI_20_TABLE_GUID; EFI_GUID devid = DEVICE_PATH_PROTOCOL; EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; EFI_GUID mps = MPS_TABLE_GUID; EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL; EFI_GUID smbios = SMBIOS_TABLE_GUID; EFI_GUID dxe = DXE_SERVICES_TABLE_GUID; EFI_GUID hoblist = HOB_LIST_TABLE_GUID; EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID; EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID; EFI_GUID fdtdtb = FDT_TABLE_GUID; EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; #ifdef EFI_ZFS_BOOT static void efi_zfs_probe(void); #endif /* * cpy8to16 copies a traditional C string into a CHAR16 string and * 0 terminates it. len is the size of *dst in bytes. */ static void cpy8to16(const char *src, CHAR16 *dst, size_t len) { len <<= 1; /* Assume CHAR16 is 2 bytes */ while (len > 0 && *src) { *dst++ = *src++; len--; } *dst++ = (CHAR16)0; } static void cpy16to8(const CHAR16 *src, char *dst, size_t len) { size_t i; for (i = 0; i < len && src[i]; i++) dst[i] = (char)src[i]; if (i < len) dst[i] = '\0'; } static int has_keyboard(void) { EFI_STATUS status; EFI_DEVICE_PATH *path; EFI_HANDLE *hin, *hin_end, *walker; UINTN sz; int retval = 0; /* * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and * do the typical dance to get the right sized buffer. */ sz = 0; hin = NULL; status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0); if (status == EFI_BUFFER_TOO_SMALL) { hin = (EFI_HANDLE *)malloc(sz); status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, hin); if (EFI_ERROR(status)) free(hin); } if (EFI_ERROR(status)) return retval; /* * Look at each of the handles. If it supports the device path protocol, * use it to get the device path for this handle. Then see if that * device path matches either the USB device path for keyboards or the * legacy device path for keyboards. */ hin_end = &hin[sz / sizeof(*hin)]; for (walker = hin; walker < hin_end; walker++) { status = BS->HandleProtocol(*walker, &devid, (VOID **)&path); if (EFI_ERROR(status)) continue; while (!IsDevicePathEnd(path)) { /* * Check for the ACPI keyboard node. All PNP3xx nodes * are keyboards of different flavors. Note: It is * unclear of there's always a keyboard node when * there's a keyboard controller, or if there's only one * when a keyboard is detected at boot. */ if (DevicePathType(path) == ACPI_DEVICE_PATH && (DevicePathSubType(path) == ACPI_DP || DevicePathSubType(path) == ACPI_EXTENDED_DP)) { ACPI_HID_DEVICE_PATH *acpi; acpi = (ACPI_HID_DEVICE_PATH *)(void *)path; if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 && (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) { retval = 1; goto out; } /* * Check for USB keyboard node, if present. Unlike a * PS/2 keyboard, these definitely only appear when * connected to the system. */ } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH && DevicePathSubType(path) == MSG_USB_CLASS_DP) { USB_CLASS_DEVICE_PATH *usb; usb = (USB_CLASS_DEVICE_PATH *)(void *)path; if (usb->DeviceClass == 3 && /* HID */ usb->DeviceSubClass == 1 && /* Boot devices */ usb->DeviceProtocol == 1) { /* Boot keyboards */ retval = 1; goto out; } } path = NextDevicePathNode(path); } } out: free(hin); return retval; } static int find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit, uint64_t *extra) { EFI_DEVICE_PATH *devpath, *copy; EFI_HANDLE h; /* * Try the device handle from our loaded image first. If that * fails, use the device path from the loaded image and see if * any of the nodes in that path match one of the enumerated * handles. */ if (efi_handle_lookup(img->DeviceHandle, dev, unit, extra) == 0) return (0); copy = NULL; devpath = efi_lookup_image_devpath(IH); while (devpath != NULL) { h = efi_devpath_handle(devpath); if (h == NULL) break; if (efi_handle_lookup(h, dev, unit, extra) == 0) { if (copy != NULL) free(copy); return (0); } if (copy != NULL) free(copy); devpath = efi_lookup_devpath(h); if (devpath != NULL) { copy = efi_devpath_trim(devpath); devpath = copy; } } return (ENOENT); } EFI_STATUS main(int argc, CHAR16 *argv[]) { char var[128]; EFI_LOADED_IMAGE *img; EFI_GUID *guid; int i, j, vargood, unit, howto; struct devsw *dev; uint64_t pool_guid; UINTN k; int has_kbd; char buf[40]; archsw.arch_autoload = efi_autoload; archsw.arch_getdev = efi_getdev; archsw.arch_copyin = efi_copyin; archsw.arch_copyout = efi_copyout; archsw.arch_readin = efi_readin; #ifdef EFI_ZFS_BOOT /* Note this needs to be set before ZFS init. */ archsw.arch_zfs_probe = efi_zfs_probe; #endif /* Init the time source */ efi_time_init(); has_kbd = has_keyboard(); /* * 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. */ cons_probe(); /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); /* * Parse the args to set the console settings, etc * boot1.efi passes these in, if it can read /boot.config or /boot/config * or iPXE may be setup to pass these in. * * Loop through the args, and for each one that contains an '=' that is * not the first character, add it to the environment. This allows * loader and kernel env vars to be passed on the command line. Convert * args from UCS-2 to ASCII (16 to 8 bit) as they are copied. */ howto = 0; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (j = 1; argv[i][j] != 0; j++) { int ch; ch = argv[i][j]; switch (ch) { case 'a': howto |= RB_ASKNAME; break; case 'd': howto |= RB_KDB; break; case 'D': howto |= RB_MULTIPLE; break; case 'h': howto |= RB_SERIAL; break; case 'm': howto |= RB_MUTE; break; case 'p': howto |= RB_PAUSE; break; case 'P': if (!has_kbd) howto |= RB_SERIAL | RB_MULTIPLE; break; case 'r': howto |= RB_DFLTROOT; break; case 's': howto |= RB_SINGLE; break; case 'S': if (argv[i][j + 1] == 0) { if (i + 1 == argc) { setenv("comconsole_speed", "115200", 1); } else { cpy16to8(&argv[i + 1][0], var, sizeof(var)); setenv("comconsole_speedspeed", var, 1); } i++; break; } else { cpy16to8(&argv[i][j + 1], var, sizeof(var)); setenv("comconsole_speed", var, 1); break; } case 'v': howto |= RB_VERBOSE; break; } } } else { vargood = 0; for (j = 0; argv[i][j] != 0; j++) { if (j == sizeof(var)) { vargood = 0; break; } if (j > 0 && argv[i][j] == '=') vargood = 1; var[j] = (char)argv[i][j]; } if (vargood) { var[j] = 0; putenv(var); } } } for (i = 0; howto_names[i].ev != NULL; i++) if (howto & howto_names[i].mask) setenv(howto_names[i].ev, "YES", 1); if (howto & RB_MULTIPLE) { if (howto & RB_SERIAL) setenv("console", "comconsole efi" , 1); else setenv("console", "efi comconsole" , 1); } else if (howto & RB_SERIAL) { setenv("console", "comconsole" , 1); } if (efi_copy_init()) { printf("failed to allocate staging area\n"); return (EFI_BUFFER_TOO_SMALL); } /* * 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)(); /* Get our loaded image protocol interface structure. */ BS->HandleProtocol(IH, &imgid, (VOID**)&img); printf("Command line arguments:"); for (i = 0; i < argc; i++) printf(" %S", argv[i]); printf("\n"); printf("Image base: 0x%lx\n", (u_long)img->ImageBase); printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); /* * Disable the watchdog timer. By default the boot manager sets * the timer to 5 minutes before invoking a boot option. If we * want to return to the boot manager, we have to disable the * watchdog timer and since we're an interactive program, we don't * want to wait until the user types "quit". The timer may have * fired by then. We don't care if this fails. It does not prevent * normal functioning in any way... */ BS->SetWatchdogTimer(0, 0, 0, NULL); if (find_currdev(img, &dev, &unit, &pool_guid) != 0) return (EFI_NOT_FOUND); switch (dev->dv_type) { #ifdef EFI_ZFS_BOOT case DEVT_ZFS: { struct zfs_devdesc currdev; currdev.d_dev = dev; currdev.d_unit = unit; currdev.d_type = currdev.d_dev->dv_type; currdev.d_opendata = NULL; currdev.pool_guid = pool_guid; currdev.root_guid = 0; env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), efi_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, env_nounset); init_zfs_bootenv(zfs_fmtdev(&currdev)); break; } #endif default: { struct devdesc currdev; currdev.d_dev = dev; currdev.d_unit = unit; currdev.d_opendata = NULL; currdev.d_type = currdev.d_dev->dv_type; env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), efi_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, env_nounset); break; } } snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset); setenv("LINES", "24", 1); /* optional */ for (k = 0; k < ST->NumberOfTableEntries; k++) { guid = &ST->ConfigurationTable[k].VendorGuid; if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) { snprintf(buf, sizeof(buf), "%p", ST->ConfigurationTable[k].VendorTable); setenv("hint.smbios.0.mem", buf, 1); smbios_detect(ST->ConfigurationTable[k].VendorTable); break; } } interact(NULL); /* doesn't return */ return (EFI_SUCCESS); /* keep compiler happy */ } /* XXX move to lib stand ? */ static int wcscmp(CHAR16 *a, CHAR16 *b) { while (*a && *b && *a == *b) { a++; b++; } return *a - *b; } 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)(); RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 23, (CHAR16 *)"Reboot from the loader"); /* NOTREACHED */ return (CMD_ERROR); } COMMAND_SET(quit, "quit", "exit the loader", command_quit); static int command_quit(int argc, char *argv[]) { exit(0); return (CMD_OK); } COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); static int command_memmap(int argc, char *argv[]) { UINTN sz; EFI_MEMORY_DESCRIPTOR *map, *p; UINTN key, dsz; UINT32 dver; EFI_STATUS status; int i, ndesc; static char *types[] = { "Reserved", "LoaderCode", "LoaderData", "BootServicesCode", "BootServicesData", "RuntimeServicesCode", "RuntimeServicesData", "ConventionalMemory", "UnusableMemory", "ACPIReclaimMemory", "ACPIMemoryNVS", "MemoryMappedIO", "MemoryMappedIOPortSpace", "PalCode" }; sz = 0; status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); if (status != EFI_BUFFER_TOO_SMALL) { printf("Can't determine memory map size\n"); return (CMD_ERROR); } map = malloc(sz); status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); if (EFI_ERROR(status)) { printf("Can't read memory map\n"); return (CMD_ERROR); } ndesc = sz / dsz; printf("%23s %12s %12s %8s %4s\n", "Type", "Physical", "Virtual", "#Pages", "Attr"); for (i = 0, p = map; i < ndesc; i++, p = NextMemoryDescriptor(p, dsz)) { printf("%23s %012jx %012jx %08jx ", types[p->Type], (uintmax_t)p->PhysicalStart, (uintmax_t)p->VirtualStart, (uintmax_t)p->NumberOfPages); if (p->Attribute & EFI_MEMORY_UC) printf("UC "); if (p->Attribute & EFI_MEMORY_WC) printf("WC "); if (p->Attribute & EFI_MEMORY_WT) printf("WT "); if (p->Attribute & EFI_MEMORY_WB) printf("WB "); if (p->Attribute & EFI_MEMORY_UCE) printf("UCE "); if (p->Attribute & EFI_MEMORY_WP) printf("WP "); if (p->Attribute & EFI_MEMORY_RP) printf("RP "); if (p->Attribute & EFI_MEMORY_XP) printf("XP "); printf("\n"); } return (CMD_OK); } COMMAND_SET(configuration, "configuration", "print configuration tables", command_configuration); static const char * guid_to_string(EFI_GUID *guid) { static char buf[40]; sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); return (buf); } static int command_configuration(int argc, char *argv[]) { UINTN i; printf("NumberOfTableEntries=%lu\n", (unsigned long)ST->NumberOfTableEntries); for (i = 0; i < ST->NumberOfTableEntries; i++) { EFI_GUID *guid; printf(" "); guid = &ST->ConfigurationTable[i].VendorGuid; if (!memcmp(guid, &mps, sizeof(EFI_GUID))) printf("MPS Table"); else if (!memcmp(guid, &acpi, sizeof(EFI_GUID))) printf("ACPI Table"); else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID))) printf("ACPI 2.0 Table"); else if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) printf("SMBIOS Table %p", ST->ConfigurationTable[i].VendorTable); else if (!memcmp(guid, &dxe, sizeof(EFI_GUID))) printf("DXE Table"); else if (!memcmp(guid, &hoblist, sizeof(EFI_GUID))) printf("HOB List Table"); else if (!memcmp(guid, &memtype, sizeof(EFI_GUID))) printf("Memory Type Information Table"); else if (!memcmp(guid, &debugimg, sizeof(EFI_GUID))) printf("Debug Image Info Table"); else if (!memcmp(guid, &fdtdtb, sizeof(EFI_GUID))) printf("FDT Table"); else printf("Unknown Table (%s)", guid_to_string(guid)); printf(" at %p\n", ST->ConfigurationTable[i].VendorTable); } return (CMD_OK); } COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode); static int command_mode(int argc, char *argv[]) { UINTN cols, rows; unsigned int mode; int i; char *cp; char rowenv[8]; EFI_STATUS status; SIMPLE_TEXT_OUTPUT_INTERFACE *conout; extern void HO(void); conout = ST->ConOut; if (argc > 1) { mode = strtol(argv[1], &cp, 0); if (cp[0] != '\0') { printf("Invalid mode\n"); return (CMD_ERROR); } status = conout->QueryMode(conout, mode, &cols, &rows); if (EFI_ERROR(status)) { printf("invalid mode %d\n", mode); return (CMD_ERROR); } status = conout->SetMode(conout, mode); if (EFI_ERROR(status)) { printf("couldn't set mode %d\n", mode); return (CMD_ERROR); } sprintf(rowenv, "%u", (unsigned)rows); setenv("LINES", rowenv, 1); HO(); /* set cursor */ return (CMD_OK); } printf("Current mode: %d\n", conout->Mode->Mode); for (i = 0; i <= conout->Mode->MaxMode; i++) { status = conout->QueryMode(conout, i, &cols, &rows); if (EFI_ERROR(status)) continue; printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols, (unsigned)rows); } if (i != 0) printf("Select a mode with the command \"mode \"\n"); return (CMD_OK); } #ifdef EFI_ZFS_BOOT 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); } COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", command_reloadbe); static int command_reloadbe(int argc, char *argv[]) { int err; char *root; if (argc > 2) { command_errmsg = "wrong number of arguments"; return (CMD_ERROR); } if (argc == 2) { err = zfs_bootenv(argv[1]); } else { root = getenv("zfs_be_root"); if (root == NULL) { return (CMD_OK); } err = zfs_bootenv(root); } if (err != 0) { command_errmsg = strerror(err); return (CMD_ERROR); } return (CMD_OK); } #endif COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show); static int efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag) { UINTN datasz, i; EFI_STATUS status; UINT32 attr; CHAR16 *data; char *str; uint32_t uuid_status; int is_ascii; datasz = 0; status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, NULL); if (status != EFI_BUFFER_TOO_SMALL) { printf("Can't get the variable: error %#lx\n", status); return (CMD_ERROR); } data = malloc(datasz); status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, data); if (status != EFI_SUCCESS) { printf("Can't get the variable: error %#lx\n", status); return (CMD_ERROR); } uuid_to_string((uuid_t *)matchguid, &str, &uuid_status); if (lflag) { printf("%s 0x%x %S", str, attr, varnamearg); } else { printf("%s 0x%x %S=", str, attr, varnamearg); is_ascii = 1; free(str); str = (char *)data; for (i = 0; i < datasz - 1; i++) { /* Quick hack to see if this ascii-ish string printable range plus tab, cr and lf */ if ((str[i] < 32 || str[i] > 126) && str[i] != 9 && str[i] != 10 && str[i] != 13) { is_ascii = 0; break; } } if (str[datasz - 1] != '\0') is_ascii = 0; if (is_ascii) printf("%s", str); else { for (i = 0; i < datasz / 2; i++) { if (isalnum(data[i]) || isspace(data[i])) printf("%c", data[i]); else printf("\\x%02x", data[i]); } } } free(data); if (pager_output("\n")) return (CMD_WARN); return (CMD_OK); } static int command_efi_show(int argc, char *argv[]) { /* * efi-show [-a] * print all the env * efi-show -u UUID * print all the env vars tagged with UUID * efi-show -v var * search all the env vars and print the ones matching var * eif-show -u UUID -v var * eif-show UUID var * print all the env vars that match UUID and var */ /* NB: We assume EFI_GUID is the same as uuid_t */ int aflag = 0, gflag = 0, lflag = 0, vflag = 0; int ch, rv; unsigned i; EFI_STATUS status; EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; EFI_GUID matchguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; uint32_t uuid_status; CHAR16 *varname; CHAR16 *newnm; CHAR16 varnamearg[128]; UINTN varalloc; UINTN varsz; while ((ch = getopt(argc, argv, "ag:lv:")) != -1) { switch (ch) { case 'a': aflag = 1; break; case 'g': gflag = 1; uuid_from_string(optarg, (uuid_t *)&matchguid, &uuid_status); if (uuid_status != uuid_s_ok) { printf("uid %s could not be parsed\n", optarg); return (CMD_ERROR); } break; case 'l': lflag = 1; break; case 'v': vflag = 1; if (strlen(optarg) >= nitems(varnamearg)) { printf("Variable %s is longer than %zd characters\n", optarg, nitems(varnamearg)); return (CMD_ERROR); } for (i = 0; i < strlen(optarg); i++) varnamearg[i] = optarg[i]; varnamearg[i] = 0; break; default: printf("Invalid argument %c\n", ch); return (CMD_ERROR); } } if (aflag && (gflag || vflag)) { printf("-a isn't compatible with -v or -u\n"); return (CMD_ERROR); } if (aflag && optind < argc) { printf("-a doesn't take any args"); return (CMD_ERROR); } if (optind == argc) aflag = 1; argc -= optind; argv += optind; pager_open(); if (vflag && gflag) { rv = efi_print_var(varnamearg, &matchguid, lflag); pager_close(); return (rv); } if (argc == 2) { optarg = argv[0]; if (strlen(optarg) >= nitems(varnamearg)) { printf("Variable %s is longer than %zd characters\n", optarg, nitems(varnamearg)); pager_close(); return (CMD_ERROR); } for (i = 0; i < strlen(optarg); i++) varnamearg[i] = optarg[i]; varnamearg[i] = 0; optarg = argv[1]; uuid_from_string(optarg, (uuid_t *)&matchguid, &uuid_status); if (uuid_status != uuid_s_ok) { printf("uid %s could not be parsed\n", optarg); pager_close(); return (CMD_ERROR); } rv = efi_print_var(varnamearg, &matchguid, lflag); pager_close(); return (rv); } - if (argc != 0) { - printf("Too many args\n"); + if (argc > 0) { + printf("Too many args %d\n", argc); pager_close(); return (CMD_ERROR); } /* * Initiate the search -- note the standard takes pain * to specify the initial call must be a poiner to a NULL * character. */ varalloc = 1024; varname = malloc(varalloc); if (varname == NULL) { printf("Can't allocate memory to get variables\n"); pager_close(); return (CMD_ERROR); } varname[0] = 0; while (1) { varsz = varalloc; status = RS->GetNextVariableName(&varsz, varname, &varguid); if (status == EFI_BUFFER_TOO_SMALL) { varalloc = varsz; newnm = malloc(varalloc); if (newnm == NULL) { printf("Can't allocate memory to get variables\n"); free(varname); pager_close(); return (CMD_ERROR); } memcpy(newnm, varname, varsz); free(varname); varname = newnm; continue; /* Try again with bigger buffer */ } if (status != EFI_SUCCESS) break; if (aflag) { if (efi_print_var(varname, &varguid, lflag) != CMD_OK) break; continue; } if (vflag) { if (wcscmp(varnamearg, varname) == 0) { if (efi_print_var(varname, &varguid, lflag) != CMD_OK) break; continue; } } if (gflag) { if (memcmp(&varguid, &matchguid, sizeof(varguid)) == 0) { if (efi_print_var(varname, &varguid, lflag) != CMD_OK) break; continue; } } } free(varname); pager_close(); return (CMD_OK); } COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set); static int command_efi_set(int argc, char *argv[]) { char *uuid, *var, *val; CHAR16 wvar[128]; EFI_GUID guid; uint32_t status; EFI_STATUS err; if (argc != 4) { printf("efi-set uuid var new-value\n"); return (CMD_ERROR); } uuid = argv[1]; var = argv[2]; val = argv[3]; uuid_from_string(uuid, (uuid_t *)&guid, &status); if (status != uuid_s_ok) { printf("Invalid uuid %s %d\n", uuid, status); return (CMD_ERROR); } cpy8to16(var, wvar, sizeof(wvar)); err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, strlen(val) + 1, val); if (EFI_ERROR(err)) { printf("Failed to set variable: error %lu\n", EFI_ERROR_CODE(err)); return (CMD_ERROR); } return (CMD_OK); } COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset); static int command_efi_unset(int argc, char *argv[]) { char *uuid, *var; CHAR16 wvar[128]; EFI_GUID guid; uint32_t status; EFI_STATUS err; if (argc != 3) { printf("efi-unset uuid var\n"); return (CMD_ERROR); } uuid = argv[1]; var = argv[2]; uuid_from_string(uuid, (uuid_t *)&guid, &status); if (status != uuid_s_ok) { printf("Invalid uuid %s\n", uuid); return (CMD_ERROR); } cpy8to16(var, wvar, sizeof(wvar)); err = RS->SetVariable(wvar, &guid, 0, 0, NULL); if (EFI_ERROR(err)) { printf("Failed to unset variable: error %lu\n", EFI_ERROR_CODE(err)); return (CMD_ERROR); } return (CMD_OK); } #ifdef LOADER_FDT_SUPPORT extern int command_fdt_internal(int argc, char *argv[]); /* * Since proper fdt command handling function is defined in fdt_loader_cmd.c, * and declaring it as extern is in contradiction with COMMAND_SET() macro * (which uses static pointer), we're defining wrapper function, which * calls the proper fdt handling routine. */ static int command_fdt(int argc, char *argv[]) { return (command_fdt_internal(argc, argv)); } COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif #ifdef EFI_ZFS_BOOT static void efi_zfs_probe(void) { EFI_HANDLE h; u_int unit; int i; char dname[SPECNAMELEN + 1]; uint64_t guid; unit = 0; h = efi_find_handle(&efipart_dev, 0); for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) { snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i); if (zfs_probe_dev(dname, &guid) == 0) (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid); } } #endif Index: head/sys/boot/ficl/efi.c =================================================================== --- head/sys/boot/ficl/efi.c (revision 307878) +++ head/sys/boot/ficl/efi.c (nonexistent) @@ -1,207 +0,0 @@ -/*- - * Copyright (c) 2014 Netflix, Inc - * 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$ - */ - -/******************************************************************* -** e f i . c -** Additional words for EFI -** -*******************************************************************/ - -#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 - * - * efi-setenv ( value n name n guid n attr -- 0 | -1) - * efi-getenv ( guid n addr n -- addr' n' | -1 ) - * efi-unsetenv ( name n guid n'' -- ) - */ - -/* - * efi-setenv - * efi-setenv ( value n name n guid n attr -- 0 | -1) - * - * Set environment variables using the SetVariable EFI runtime service. - * - * Value and guid are passed through in binary form (so guid needs to be - * converted to binary form from its string form). Name is converted from - * ASCII to CHAR16. Since ficl doesn't have support for internationalization, - * there's no native CHAR16 interface provided. - * - * attr is an int in the bitmask of the following attributes for this variable. - * - * 1 Non volatile - * 2 Boot service access - * 4 Run time access - * (corresponding to the same bits in the UEFI spec). - */ -void -ficlEfiSetenv(FICL_VM *pVM) -{ -#ifndef TESTMAIN - char *value, *guid; - CHAR16 *name - int i; -#endif - char *namep, *valuep, *guidp; - int names, values, guids, attr; - -#if FICL_ROBUST > 1 - vmCheckStack(pVM, 6, 0); -#endif - attr = stackPopINT(pVM->pStack); - guids = stackPopINT(pVM->pStack); - guidp = (char*)stackPopPtr(pVM->pStack); - names = stackPopINT(pVM->pStack); - namep = (char*)stackPopPtr(pVM->pStack); - values = stackPopINT(pVM->pStack); - valuep = (char*)stackPopPtr(pVM->pStack); - -#ifndef TESTMAIN - guid = (char*)ficlMalloc(guids); - if (guid != NULL) - vmThrowErr(pVM, "Error: out of memory"); - memcpy(guid, guidp, guids); - - name = (char*)ficlMalloc((names + 1) * sizeof(CHAR16)); - if (name == NULL) - vmThrowErr(pVM, "Error: out of memory"); - for (i = 0; i < names; i++) - name[i] = namep[i]; - name[names] = (CHAR16)0; - - value = (char*)ficlMalloc(values + 1); - if (value != NULL) - vmThrowErr(pVM, "Error: out of memory"); - memcpy(value, valuep, values); - - status = efi_set_variable(name, guid, attr, value); - if (status == EFI_SUCCESS) - stackPushINT(pVM->pStack, 0); - else - stackPushINT(pVM->pStack, -1); - - ficlFree(name); - ficlFree(value); - ficlFree(guid); -#endif - - return; -} - -void -ficlEfiGetenv(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 -ficlEfiUnsetenv(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; -} -/************************************************************************** - -** Build FreeBSD platform extensions into the system dictionary -**************************************************************************/ -void ficlEfiCompilePlatform(FICL_SYSTEM *pSys) -{ - FICL_DICT *dp = pSys->dp; - assert (dp); - - dictAppendWord(dp, "efi-setenv", ficlEfiSetenv, FW_DEFAULT); - dictAppendWord(dp, "efi-getenv", ficlEfiGetenv, FW_DEFAULT); - dictAppendWord(dp, "efi-unsetenv", ficlEfiUnsetenv, FW_DEFAULT); - - return; -} Property changes on: head/sys/boot/ficl/efi.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/boot/ficl/loader.c =================================================================== --- head/sys/boot/ficl/loader.c (revision 307878) +++ head/sys/boot/ficl/loader.c (revision 307879) @@ -1,842 +1,841 @@ /*- * 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 #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 ) * uuid-from-string ( addr n -- addr' ) * uuid-to-string ( addr' -- addr n ) * .# ( 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; } 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; } void ficlUuidFromString(FICL_VM *pVM) { #ifndef TESTMAIN char *uuid; uint32_t status; #endif char *uuidp; int uuids; uuid_t *u; #if FICL_ROBUST > 1 vmCheckStack(pVM, 2, 0); #endif uuids = stackPopINT(pVM->pStack); uuidp = (char *) stackPopPtr(pVM->pStack); #ifndef TESTMAIN uuid = (char *)ficlMalloc(uuids + 1); if (!uuid) vmThrowErr(pVM, "Error: out of memory"); strncpy(uuid, uuidp, uuids); uuid[uuids] = '\0'; u = (uuid_t *)ficlMalloc(sizeof (*u)); uuid_from_string(uuid, u, &status); ficlFree(uuid); if (status != uuid_s_ok) { ficlFree(u); u = NULL; } #else u = NULL; #endif stackPushPtr(pVM->pStack, u); return; } void ficlUuidToString(FICL_VM *pVM) { #ifndef TESTMAIN char *uuid; uint32_t status; #endif uuid_t *u; #if FICL_ROBUST > 1 vmCheckStack(pVM, 1, 0); #endif u = (uuid_t *)stackPopPtr(pVM->pStack); #ifndef TESTMAIN uuid_to_string(u, &uuid, &status); if (status != uuid_s_ok) { stackPushPtr(pVM->pStack, uuid); stackPushINT(pVM->pStack, strlen(uuid)); } else #endif stackPushINT(pVM->pStack, -1); 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; } /* ** 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) { ficlCompileFcn **fnpp; 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); dictAppendWord(dp, "uuid-from-string", ficlUuidFromString, FW_DEFAULT); dictAppendWord(dp, "uuid-to-string", ficlUuidToString, FW_DEFAULT); - SET_FOREACH(fnpp, Xficl_compile_set) { + SET_FOREACH(fnpp, Xficl_compile_set) (*fnpp)(pSys); - } #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/Makefile.inc =================================================================== --- head/sys/boot/forth/Makefile.inc (revision 307878) +++ head/sys/boot/forth/Makefile.inc (revision 307879) @@ -1,25 +1,26 @@ # $FreeBSD$ FILES+= beastie.4th FILES+= brand.4th FILES+= brand-fbsd.4th FILES+= check-password.4th FILES+= color.4th FILES+= delay.4th +FILES+= efi.4th FILES+= frames.4th FILES+= loader.4th FILES+= loader.conf FILES+= loader.help FILES+= logo-beastie.4th FILES+= logo-beastiebw.4th FILES+= logo-fbsdbw.4th FILES+= logo-orb.4th FILES+= logo-orbbw.4th FILES+= menu.4th FILES+= menu-commands.4th FILES+= menusets.4th FILES+= screen.4th FILES+= shortcuts.4th FILES+= support.4th FILES+= version.4th FILESDIR_loader.conf= /boot/defaults Index: head/sys/boot/forth/efi.4th =================================================================== --- head/sys/boot/forth/efi.4th (nonexistent) +++ head/sys/boot/forth/efi.4th (revision 307879) @@ -0,0 +1,30 @@ +\ Copyright (c) 2016 Netflix, Inc +\ 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 definitions + +\ Place holder for more functions +.( EFI boot environment) cr Property changes on: head/sys/boot/forth/efi.4th ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/boot/forth/loader.4th =================================================================== --- head/sys/boot/forth/loader.4th (revision 307878) +++ head/sys/boot/forth/loader.4th (revision 307879) @@ -1,263 +1,266 @@ \ Copyright (c) 1999 Daniel C. Sobral \ Copyright (c) 2011-2015 Devin Teske \ 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 definitions s" arch-i386" environment? [if] [if] s" loader_version" environment? [if] 11 < [if] .( Loader version 1.1+ required) cr abort [then] [else] .( Could not get loader version!) cr abort [then] [then] [then] 256 dictthreshold ! \ 256 cells minimum free space 2048 dictincrease ! \ 2048 additional cells each time include /boot/support.4th include /boot/color.4th include /boot/delay.4th include /boot/check-password.4th +s" efi-boot" environment? [if] [if] + include /boot/efi.4th +[then] [then] only forth definitions : bootmsg ( -- ) loader_color? dup ( -- bool bool ) if 7 fg 4 bg then ." Booting..." if me then cr ; : try-menu-unset \ menu-unset may not be present s" beastie_disable" getenv dup -1 <> if s" YES" compare-insensitive 0= if exit then else drop then s" menu-unset" sfind if execute else drop then s" menusets-unset" sfind if execute else drop then ; only forth also support-functions also builtins definitions : boot 0= if ( interpreted ) get_arguments then \ Unload only if a path was passed dup if >r over r> swap c@ [char] - <> if 0 1 unload drop else s" kernelname" getenv? if ( a kernel has been loaded ) try-menu-unset bootmsg 1 boot exit then load_kernel_and_modules ?dup if exit then try-menu-unset bootmsg 0 1 boot exit then else s" kernelname" getenv? if ( a kernel has been loaded ) try-menu-unset bootmsg 1 boot exit then load_kernel_and_modules ?dup if exit then try-menu-unset bootmsg 0 1 boot exit then load_kernel_and_modules ?dup 0= if bootmsg 0 1 boot then ; \ ***** boot-conf \ \ Prepares to boot as specified by loaded configuration files. : boot-conf 0= if ( interpreted ) get_arguments then 0 1 unload drop load_kernel_and_modules ?dup 0= if 0 1 autoboot then ; also forth definitions previous builtin: boot builtin: boot-conf only forth definitions also support-functions \ ***** start \ \ Initializes support.4th global variables, sets loader_conf_files, \ processes conf files, and, if any one such file was successfully \ read to the end, loads kernel and modules. : start ( -- ) ( throws: abort & user-defined ) s" /boot/defaults/loader.conf" initialize include_conf_files include_nextboot_file \ If the user defined a post-initialize hook, call it now s" post-initialize" sfind if execute else drop then \ Will *NOT* try to load kernel and modules if no configuration file \ was successfully loaded! any_conf_read? if s" loader_delay" getenv -1 = if load_xen_throw load_kernel load_modules else drop ." Loading Kernel and Modules (Ctrl-C to Abort)" cr s" also support-functions" evaluate s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate s" set delay_showdots" evaluate delay_execute then then ; \ ***** initialize \ \ Overrides support.4th initialization word with one that does \ everything start one does, short of loading the kernel and \ modules. Returns a flag. : initialize ( -- flag ) s" /boot/defaults/loader.conf" initialize include_conf_files include_nextboot_file \ If the user defined a post-initialize hook, call it now s" post-initialize" sfind if execute else drop then any_conf_read? ; \ ***** read-conf \ \ Read a configuration file, whose name was specified on the command \ line, if interpreted, or given on the stack, if compiled in. : (read-conf) ( addr len -- ) conf_files string= include_conf_files \ Will recurse on new loader_conf_files definitions ; : read-conf ( | addr len -- ) ( throws: abort & user-defined ) state @ if \ Compiling postpone (read-conf) else \ Interpreting bl parse (read-conf) then ; immediate \ show, enable, disable, toggle module loading. They all take module from \ the next word : set-module-flag ( module_addr val -- ) \ set and print flag over module.flag ! dup module.name strtype module.flag @ if ." will be loaded" else ." will not be loaded" then cr ; : enable-module find-module ?dup if true set-module-flag then ; : disable-module find-module ?dup if false set-module-flag then ; : toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ; \ ***** show-module \ \ Show loading information about a module. : show-module ( -- ) find-module ?dup if show-one-module then ; \ Words to be used inside configuration files : retry false ; \ For use in load error commands : ignore true ; \ For use in load error commands \ Return to strict forth vocabulary : #type over - >r type r> spaces ; : .? 2 spaces 2swap 15 #type 2 spaces type cr ; \ Execute the ? command to print all the commands defined in \ C, then list the ones we support here. Please note that this \ doesn't use pager_* routines that the C implementation of ? \ does, so these will always appear, even if you stop early \ there. And they may cause the commands to scroll off the \ screen if the number of commands modulus LINES is close \ to LINEs.... : ? ['] ? execute s" boot-conf" s" load kernel and modules, then autoboot" .? s" read-conf" s" read a configuration file" .? s" enable-module" s" enable loading of a module" .? s" disable-module" s" disable loading of a module" .? s" toggle-module" s" toggle loading of a module" .? s" show-module" s" show module load data" .? s" try-include" s" try to load/interpret files" .? ; : try-include ( -- ) \ see loader.4th(8) ['] include ( -- xt ) \ get the execution token of `include' catch ( xt -- exception# | 0 ) if \ failed LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data) \ ... prevents words unused by `include' from being interpreted then ; immediate \ interpret immediately for access to `source' (aka tib) only forth definitions