-/* $OpenBSD: efiboot.c,v 1.39 2022/03/22 10:32:10 kettenis Exp $ */
+/* $OpenBSD: efiboot.c,v 1.40 2022/12/22 15:44:02 kettenis Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
EFI_BOOT_SERVICES *BS;
EFI_RUNTIME_SERVICES *RS;
EFI_HANDLE IH, efi_bootdp;
+void *fdt_sys = NULL;
+void *fdt_override = NULL;
+size_t fdt_override_size;
EFI_PHYSICAL_ADDRESS heap;
UINTN heapsiz = 1 * 1024 * 1024;
static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+static EFI_GUID fdt_guid = FDT_TABLE_GUID;
+
+#define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID))
int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
static void efi_memprobe_internal(void);
static void efi_timer_init(void);
static void efi_timer_cleanup(void);
-static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *);
+static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_MEMORY_TYPE,
+ EFI_PHYSICAL_ADDRESS *);
+void *efi_fdt(void);
+int fdt_load_override(char *);
EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
EFI_LOADED_IMAGE *imgp;
EFI_DEVICE_PATH *dp = NULL;
EFI_STATUS status;
+ int i;
ST = systab;
BS = ST->BootServices;
if (status == EFI_SUCCESS)
efi_bootdp = dp;
+ for (i = 0; i < ST->NumberOfTableEntries; i++) {
+ if (efi_guidcmp(&fdt_guid,
+ &ST->ConfigurationTable[i].VendorGuid) == 0)
+ fdt_sys = ST->ConfigurationTable[i].VendorTable;
+ }
+ fdt_init(fdt_sys);
+
progname = "BOOTARM";
boot(0);
* kernel. That's fine. They're just used as an index into the cdevs
* array and never passed on to the kernel.
*/
-static dev_t serial = makedev(0, 0);
-static dev_t framebuffer = makedev(1, 0);
+static dev_t serial = makedev(1, 0);
+static dev_t framebuffer = makedev(2, 0);
static char framebuffer_path[128];
efi_cons_probe(struct consdev *cn)
{
cn->cn_pri = CN_MIDPRI;
- cn->cn_dev = serial;
+ cn->cn_dev = makedev(0, 0);
}
void
conout->OutputString(conout, buf);
}
+void
+efi_com_probe(struct consdev *cn)
+{
+ cn->cn_pri = CN_LOWPRI;
+ cn->cn_dev = serial;
+}
+
+void
+efi_com_init(struct consdev *cn)
+{
+ conin = ST->ConIn;
+ conout = ST->ConOut;
+}
+
+int
+efi_com_getc(dev_t dev)
+{
+ return efi_cons_getc(dev);
+}
+
+void
+efi_com_putc(dev_t dev, int c)
+{
+ efi_cons_putc(dev, c);
+}
+
void
efi_fb_probe(struct consdev *cn)
{
sizeof(framebuffer_path));
}
+void
+efi_console(void)
+{
+ void *node;
+
+ if (major(cn_tab->cn_dev) == major(serial)) {
+ char *serial_path;
+ char alias[16];
+ int len;
+
+ /* Construct alias and resolve it. */
+ snprintf(alias, sizeof(alias), "serial%d",
+ minor(cn_tab->cn_dev));
+ node = fdt_find_node("/aliases");
+ len = fdt_node_property(node, alias, &serial_path);
+ if (len <= 0)
+ return;
+
+ /* Point stdout-path at the serial node. */
+ node = fdt_find_node("/chosen");
+ fdt_node_add_property(node, "stdout-path",
+ serial_path, strlen(serial_path) + 1);
+ } else if (major(cn_tab->cn_dev) == major(framebuffer)) {
+ if (strlen(framebuffer_path) == 0)
+ return;
+
+ /* Point stdout-path at the framebuffer node. */
+ node = fdt_find_node("/chosen");
+ fdt_node_add_property(node, "stdout-path",
+ framebuffer_path, strlen(framebuffer_path) + 1);
+ }
+}
+
uint64_t dma_constraint[2] = { 0, -1 };
void
dma_constraint, sizeof(dma_constraint));
}
-void
-efi_console(void)
-{
- void *node;
-
- if (cn_tab->cn_dev != framebuffer)
- return;
-
- if (strlen(framebuffer_path) == 0)
- return;
-
- /* Point stdout-path at the framebuffer node. */
- node = fdt_find_node("/chosen");
- fdt_node_add_property(node, "stdout-path",
- framebuffer_path, strlen(framebuffer_path) + 1);
-}
-
-void *fdt = NULL;
char *bootmac = NULL;
-static EFI_GUID fdt_guid = FDT_TABLE_GUID;
-
-#define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID))
void *
efi_makebootargs(char *bootargs, int howto)
uint64_t uefi_system_table = htobe64((uintptr_t)ST);
uint32_t boothowto = htobe32(howto);
EFI_PHYSICAL_ADDRESS addr;
- void *node;
+ void *node, *fdt;
size_t len;
- int i;
- if (fdt == NULL) {
- for (i = 0; i < ST->NumberOfTableEntries; i++) {
- if (efi_guidcmp(&fdt_guid,
- &ST->ConfigurationTable[i].VendorGuid) == 0)
- fdt = ST->ConfigurationTable[i].VendorTable;
- }
- }
+ fdt = efi_fdt();
+ if (fdt == NULL)
+ return NULL;
if (!fdt_get_size(fdt))
return NULL;
if (!fdt_init(fdt))
return NULL;
+ /* Create common nodes which might not exist when using mach dtb */
+ node = fdt_find_node("/aliases");
+ if (node == NULL)
+ fdt_node_add_node(fdt_find_node("/"), "aliases", &node);
node = fdt_find_node("/chosen");
- if (!node)
- return NULL;
+ if (node == NULL)
+ fdt_node_add_node(fdt_find_node("/"), "chosen", &node);
+ node = fdt_find_node("/chosen");
len = strlen(bootargs) + 1;
fdt_node_add_property(node, "bootargs", bootargs, len);
fdt_node_add_property(node, "openbsd,boothowto",
EFI_STATUS status;
cninit();
+ efi_heap_init();
/*
* The kernel expects to be loaded at offset 0x00300000 into a
if (efi_loadaddr == 0)
printf("Can't allocate memory\n");
- efi_heap_init();
efi_timer_init();
efi_diskprobe();
efi_pxeprobe();
p[2] = '0' + sd_boot_vol;
}
-const char cdevs[][4] = { "com", "fb" };
+const char cdevs[][4] = { "cons", "com", "fb" };
const int ncdevs = nitems(cdevs);
int
}
static EFI_STATUS
-efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr)
+efi_memprobe_find(UINTN pages, UINTN align, EFI_MEMORY_TYPE type,
+ EFI_PHYSICAL_ADDRESS *addr)
{
EFI_MEMORY_DESCRIPTOR *mm;
int i, j;
if (paddr & (align - 1))
continue;
- if (BS->AllocatePages(AllocateAddress, EfiLoaderData,
+ if (BS->AllocatePages(AllocateAddress, type,
pages, &paddr) == EFI_SUCCESS) {
*addr = paddr;
return EFI_SUCCESS;
return EFI_OUT_OF_RESOURCES;
}
-/*
- * Commands
- */
+int
+mdrandom(char *buf, size_t buflen)
+{
+ char *random;
+ void *node;
+ int i, len, ret = -1;
-int Xdtb_efi(void);
-int Xexit_efi(void);
-int Xpoweroff_efi(void);
+ node = fdt_find_node("/chosen");
+ if (!node)
+ return -1;
-const struct cmd_table cmd_machine[] = {
- { "dtb", CMDT_CMD, Xdtb_efi },
- { "exit", CMDT_CMD, Xexit_efi },
- { "poweroff", CMDT_CMD, Xpoweroff_efi },
- { NULL, 0 }
-};
+ len = fdt_node_property(node, "rng-seed", &random);
+ if (len > 0) {
+ for (i = 0; i < buflen; i++)
+ buf[i] ^= random[i % len];
+ ret = 0;
+ }
+
+ len = fdt_node_property(node, "kaslr-seed", &random);
+ if (len > 0) {
+ for (i = 0; i < buflen; i++)
+ buf[i] ^= random[i % len];
+ ret = 0;
+ }
+
+ return ret;
+}
+
+void *
+efi_fdt(void)
+{
+ /* 'mach dtb' has precedence */
+ if (fdt_override != NULL)
+ return fdt_override;
+
+ return fdt_sys;
+}
int
-Xdtb_efi(void)
+fdt_load_override(char *file)
{
EFI_PHYSICAL_ADDRESS addr;
char path[MAXPATHLEN];
struct stat sb;
int fd;
- if (cmd.argc != 2)
- return (1);
+ if (file == NULL && fdt_override) {
+ BS->FreePages((uint64_t)fdt_override,
+ EFI_SIZE_TO_PAGES(fdt_override_size));
+ fdt_override = NULL;
+ fdt_init(fdt_sys);
+ return 0;
+ }
- snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, cmd.argv[1]);
+ snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, file);
fd = open(path, O_RDONLY);
if (fd < 0 || fstat(fd, &sb) == -1) {
printf("cannot open %s\n", path);
- return (1);
+ return 0;
}
if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size),
- 0x1000, &addr) != EFI_SUCCESS) {
+ PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) {
printf("cannot allocate memory for %s\n", path);
- return (1);
+ return 0;
}
if (read(fd, (void *)addr, sb.st_size) != sb.st_size) {
printf("cannot read from %s\n", path);
- return (1);
+ return 0;
}
- fdt = (void *)addr;
- return (0);
+ if (!fdt_init((void *)addr)) {
+ printf("invalid device tree\n");
+ BS->FreePages(addr, EFI_SIZE_TO_PAGES(sb.st_size));
+ return 0;
+ }
+
+ if (fdt_override) {
+ BS->FreePages((uint64_t)fdt_override,
+ EFI_SIZE_TO_PAGES(fdt_override_size));
+ fdt_override = NULL;
+ }
+
+ fdt_override = (void *)addr;
+ fdt_override_size = sb.st_size;
+ return 0;
+}
+
+/*
+ * Commands
+ */
+
+int Xdtb_efi(void);
+int Xexit_efi(void);
+int Xpoweroff_efi(void);
+
+const struct cmd_table cmd_machine[] = {
+ { "dtb", CMDT_CMD, Xdtb_efi },
+ { "exit", CMDT_CMD, Xexit_efi },
+ { "poweroff", CMDT_CMD, Xpoweroff_efi },
+ { NULL, 0 }
+};
+
+int
+Xdtb_efi(void)
+{
+ if (cmd.argc == 1) {
+ fdt_load_override(NULL);
+ return (0);
+ }
+
+ if (cmd.argc != 2) {
+ printf("dtb file\n");
+ return (0);
+ }
+
+ return fdt_load_override(cmd.argv[1]);
}
int