From 43eadd7d37ebe2c0f593e31cff840c9144a7e946 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Wed, 6 Apr 2022 00:37:13 -0500 Subject: [PATCH 1/3] loader: add bits for attaching to a preloaded kernel With m1n1, we'll pass the kernel through as an "initramfs," which this will then attach to. A bootm1 command is added that loads that and boots. The following should be added to loader.conf: menu_timeout_command="bootm1" --- stand/efi/loader/Makefile | 2 + stand/efi/loader/conf.c | 5 + stand/efi/loader/elffs.c | 233 ++++++++++++++++++++++++++++++++++++ stand/efi/loader/memdev.c | 236 +++++++++++++++++++++++++++++++++++++ stand/fdt/fdt_loader_cmd.c | 9 ++ stand/fdt/fdt_platform.h | 1 + stand/lua/cli.lua | 7 ++ 7 files changed, 493 insertions(+) create mode 100644 stand/efi/loader/elffs.c create mode 100644 stand/efi/loader/memdev.c diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile index 1edb5674712..0784a9f37c7 100644 --- a/stand/efi/loader/Makefile +++ b/stand/efi/loader/Makefile @@ -18,9 +18,11 @@ SRCS= autoload.c \ bootinfo.c \ conf.c \ copy.c \ + elffs.c \ efi_main.c \ framebuffer.c \ main.c \ + memdev.c \ self_reloc.c \ vers.c \ gfx_fb.c \ diff --git a/stand/efi/loader/conf.c b/stand/efi/loader/conf.c index 863c9188c72..7a65f5c34d0 100644 --- a/stand/efi/loader/conf.c +++ b/stand/efi/loader/conf.c @@ -39,6 +39,9 @@ extern struct devsw vdisk_dev; extern struct devsw md_dev; #endif +extern struct devsw memdisk_dev; +extern struct fs_ops elffs_fsops; + struct devsw *devsw[] = { &efipart_fddev, &efipart_cddev, @@ -54,6 +57,7 @@ struct devsw *devsw[] = { #ifdef MD_IMAGE_SIZE &md_dev, #endif + &memdisk_dev, NULL }; @@ -69,6 +73,7 @@ struct fs_ops *file_system[] = { &nfs_fsops, &gzipfs_fsops, &bzipfs_fsops, + &elffs_fsops, NULL }; diff --git a/stand/efi/loader/elffs.c b/stand/efi/loader/elffs.c new file mode 100644 index 00000000000..437fd4abb7b --- /dev/null +++ b/stand/efi/loader/elffs.c @@ -0,0 +1,233 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Andrew Turner + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory (Department of Computer Science and + * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the + * DARPA SSITH research programme. + * + * 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 "stand.h" + +struct elf_file { + uint64_t mediasize; + uint64_t offset; +}; + +static int elf_open(const char *path, struct open_file *fd); +static int elf_close(struct open_file *fd); +static int elf_read(struct open_file *fd, void *buf, size_t size, size_t *resid); +static off_t elf_seek(struct open_file *fd, off_t offset, int whence); +static int elf_stat(struct open_file *fd, struct stat *sb); +static int elf_readdir(struct open_file *fd, struct dirent *d); + +struct fs_ops elffs_fsops = { + + "elffs", + elf_open, + elf_close, + elf_read, + null_write, + elf_seek, + elf_stat, + elf_readdir +}; + +static int +elf_open(const char *path, struct open_file *fd) +{ + char buf[512]; + Elf64_Ehdr *hdr; + struct elf_file *f; + size_t rsize; + int err; + + if (strcmp(path, "/boot/kernel/kernel.gz") != 0) + return (ENOENT); + + f = malloc(sizeof(*f)); + + err = fd->f_dev->dv_strategy(fd->f_devdata, F_READ, 0, sizeof(buf), buf, + &rsize); + if (err == 0 && rsize != 0) + err = EIO; + if (err != 0) { + free(f); + return (err); + } + +#if 0 + hdr = (Elf64_Ehdr *)&buf[0]; + if (!IS_ELF(*hdr)) { +printf("%s: EINVAL\n", __func__); + free(f); + return (EINVAL); + } +#endif + + fd->f_dev->dv_ioctl(fd, DIOCGMEDIASIZE, &f->mediasize); + f->offset = 0; + fd->f_fsdata = (void *)f; + + printf("%s: OK\n", __func__); + return (0); +} + +static int +elf_close(struct open_file *fd) +{ + + free(fd->f_fsdata); + return (0); +} + +static int +elf_read(struct open_file *fd, void *buf, size_t nbyte, size_t *residp) +{ + char *b, *tmp; + struct elf_file *f; + size_t ofs, onbyte, resid, rsize, rlen; + int err; + + f = fd->f_fsdata; + + b = buf; + onbyte = nbyte; + err = 0; + rlen = 0; + tmp = NULL; + ofs = f->offset % 512; + if (ofs != 0) { + /* Unaligned prefix, take care of that, first. */ + tmp = malloc(512); + if (tmp == NULL) { + errno = ENOMEM; + goto out; + } + err = fd->f_dev->dv_strategy(fd->f_devdata, F_READ, + f->offset / 512, 512, tmp, &resid); + if (err != 0) + goto out; + rsize = 512 - ofs - resid; + if (rsize == 0) { + err = EIO; + goto out; + } + f->offset += rsize; + rlen += rsize; + memcpy(b, tmp + ofs, rsize); + nbyte -= rsize; + b += rsize; + + if (resid != 0) + goto out; + } + + while (nbyte >= 512) { + err = fd->f_dev->dv_strategy(fd->f_devdata, F_READ, + f->offset / 512, 512, b, &resid); + if (err != 0) + goto out; + rsize = 512 - resid; + f->offset += rsize; + rlen += rsize; + nbyte -= rsize; + b += rsize; + if (resid != 0) + goto out; + } + if (nbyte > 0) { + if (tmp == NULL) + tmp = malloc(512); + if (tmp == NULL) { + errno = ENOMEM; + goto out; + } + err = fd->f_dev->dv_strategy(fd->f_devdata, F_READ, + f->offset / 512, 512, tmp, &resid); + if (err != 0) + goto out; + nbyte = MIN(512 - resid, nbyte); + f->offset += nbyte; + rlen += nbyte; + memcpy(b, tmp, nbyte); + free(tmp); + } + +out: + if (residp != NULL) + *residp = onbyte - rlen; + return (err); +} + +static off_t +elf_seek(struct open_file *fd, off_t offset, int whence) +{ + struct elf_file *f; + + f = fd->f_fsdata; + + switch (whence) { + case SEEK_SET: + f->offset = offset; + break; + case SEEK_CUR: + f->offset += offset; + break; + case SEEK_END: + default: + errno = EINVAL; +printf("%s: %d\n", __func__, errno); + return (-1); + } + + return (f->offset); +} + +static int +elf_stat(struct open_file *fd, struct stat *sb) +{ + + sb->st_mode = S_IFREG | 0444; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + sb->st_size = -1; + return (0); +} + +static int +elf_readdir(struct open_file *fd, struct dirent *d) +{ + +printf("%s\n", __func__); + return (EINVAL); +} diff --git a/stand/efi/loader/memdev.c b/stand/efi/loader/memdev.c new file mode 100644 index 00000000000..1cee709a2d0 --- /dev/null +++ b/stand/efi/loader/memdev.c @@ -0,0 +1,236 @@ +/*- + * Copyright (c) 2009 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 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 + +#include "bootstrap.h" + +#include +#include +#include +#include + +#define MD_BLOCK_SIZE 512 + +static struct fdt_header *fdtp; + +/* + * Preloaded image gets put here. + * Applications that patch the object with the image can determine + * the size looking at the start and end markers (strings), + * so we want them contiguous. + */ +static struct { + void *start; + void *end; +} md_image; + +/* devsw I/F */ +static int md_init(void); +static int md_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int md_open(struct open_file *, ...); +static int md_close(struct open_file *); +static int md_ioctl(struct open_file *, u_long, void *); +static int md_print(int); + +struct devsw memdisk_dev = { + .dv_name = "md", + .dv_type = DEVT_DISK, + .dv_init = md_init, + .dv_strategy = md_strategy, + .dv_open = md_open, + .dv_close = md_close, + .dv_ioctl = md_ioctl, + .dv_print = md_print, + .dv_cleanup = NULL +}; + +static uintmax_t +fdt_read_prop(struct fdt_header *fdtp, int offset, const char *prop) +{ + const void *data; + uintmax_t val; + int i, len; + + data = fdt_getprop(fdtp, offset, prop, &len); + if (data == NULL) + return (0); + + val = 0; + for (i = 0; len > 3; len -= 4, i++) { + val <<= 32; + val |= fdt32_to_cpu(*((const uint32_t *)data + i)); + } + return (val); +} + +static int +md_init(void) +{ + int offset; + SHA256_CTX ctx; + unsigned char digest[32]; + + fdtp = fdt_get(); + if (fdtp == NULL) + return (EINVAL); + + offset = fdt_path_offset(fdtp, "/chosen"); + if (offset < 0) + return (EINVAL); + + md_image.start = (void *)fdt_read_prop(fdtp, offset, + "linux,initrd-start"); + md_image.end = (void *)fdt_read_prop(fdtp, offset, + "linux,initrd-end"); + if (md_image.start >= md_image.end || md_image.end - md_image.start <= 5) + return (EINVAL); + + SHA256_Init(&ctx); + SHA256_Update(&ctx, (const unsigned char *)md_image.start, + md_image.end - md_image.start); + SHA256_Final(digest, &ctx); + + printf("SHA256(MD) = "); + for (size_t i = 0; i < 32; i++) { + printf("%.02x", digest[i]); + } + + printf("\n"); + return (0); +} + +static int +md_strategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) +{ + struct devdesc *dev = (struct devdesc *)devdata; + size_t ofs, memsz, osize, resid; + + osize = size; + if (dev->d_unit != 0) + return (ENXIO); + + memsz = md_image.end - md_image.start; + if (blk < 0 || blk >= howmany(memsz, MD_BLOCK_SIZE)) { + return (EIO); + } + + if (size % MD_BLOCK_SIZE) { + return (EIO); + } + + ofs = blk * MD_BLOCK_SIZE; + resid = osize - size; + if ((ofs + size) >= roundup2(memsz, MD_BLOCK_SIZE)) { + size = roundup2(memsz, MD_BLOCK_SIZE) - ofs; + resid = osize - (memsz - ofs); + } + + if (rsize != NULL) + *rsize = resid; + + switch (rw & F_MASK) { + case F_READ: + if ((ofs + size) <= memsz) { + bcopy(md_image.start + ofs, buf, size); + } else if (size != 0) { + memset(buf, 0, size); + bcopy(md_image.start + ofs, buf, memsz - ofs); + } + return (0); + case F_WRITE: + if ((ofs + size) <= memsz) + bcopy(buf, md_image.start + ofs, size); + else + bcopy(buf, md_image.start + ofs, memsz - ofs); + return (0); + } + + return (ENODEV); +} + +static int +md_open(struct open_file *f, ...) +{ + va_list ap; + struct devdesc *dev; + + va_start(ap, f); + dev = va_arg(ap, struct devdesc *); + va_end(ap); + + if (dev->d_unit != 0) + return (ENXIO); + + return (0); +} + +static int +md_close(struct open_file *f) +{ + struct devdesc *dev; + + dev = (struct devdesc *)(f->f_devdata); + return ((dev->d_unit != 0) ? ENXIO : 0); +} + +static int +md_ioctl(struct open_file *f, u_long cmd, void *data) +{ + + switch (cmd) { + default: + return (EINVAL); + case DIOCGSECTORSIZE: + *(u_int *)data = MD_BLOCK_SIZE; + return (0); + case DIOCGMEDIASIZE: + *(uint64_t *)data = roundup2(md_image.end - md_image.start, + MD_BLOCK_SIZE); + return (0); + } +} + +static int +md_print(int verbose) +{ + + printf("%s devices:", memdisk_dev.dv_name); + if (pager_output("\n") != 0) + return (1); + + printf("MD (%lu bytes)", md_image.end - md_image.start); + return (pager_output("\n")); +} diff --git a/stand/fdt/fdt_loader_cmd.c b/stand/fdt/fdt_loader_cmd.c index c14b99768d7..aaa1df06615 100644 --- a/stand/fdt/fdt_loader_cmd.c +++ b/stand/fdt/fdt_loader_cmd.c @@ -113,6 +113,15 @@ static const struct cmdtab commands[] = { static char cwd[FDT_CWD_LEN] = "/"; +struct fdt_header * +fdt_get(void) +{ + + if (fdt_is_setup() == 0) + fdt_setup_fdtp(); + return (fdtp); +} + static vm_offset_t fdt_find_static_dtb() { diff --git a/stand/fdt/fdt_platform.h b/stand/fdt/fdt_platform.h index 7bd1c977b4d..60f3429749b 100644 --- a/stand/fdt/fdt_platform.h +++ b/stand/fdt/fdt_platform.h @@ -38,6 +38,7 @@ struct fdt_mem_region { #define TMP_MAX_ETH 8 +struct fdt_header *fdt_get(void); int fdt_copy(vm_offset_t); void fdt_fixup_cpubusfreqs(unsigned long, unsigned long); void fdt_fixup_ethernet(const char *, char *, int); diff --git a/stand/lua/cli.lua b/stand/lua/cli.lua index 12f6b57642d..a6340965375 100644 --- a/stand/lua/cli.lua +++ b/stand/lua/cli.lua @@ -255,6 +255,13 @@ cli["disable-device"] = function(...) end end +cli["bootm1"] = function() + loader.perform("set rootdev=disk0p3:") + loader.perform("set currdev=md0:") + loader.perform("load /boot/kernel/kernel") + loader.perform("boot") +end + -- Used for splitting cli varargs into cmd_name and the rest of argv function cli.arguments(...) local argv = {...} -- 2.33.0