diff --git a/Makefile b/Makefile index dd13daf1..789591c4 100644 --- a/Makefile +++ b/Makefile @@ -231,6 +231,30 @@ echfs-test: $(BINDIR)/limine-install test.hdd qemu-system-x86_64 -net none -smp 4 -hda test.hdd -debugcon stdio +.PHONY: fwcfg-common fwcfg-test fwcfg-simple-test +fwcfg-common: + $(MAKE) test-clean + $(MAKE) limine-bios + $(MAKE) limine-install + $(MAKE) -C test + rm -rf test_image/ + mkdir -p test_image/boot + cp -rv $(BINDIR)/* test_image/boot/ + xorriso -as mkisofs -b boot/limine-cd.bin -no-emul-boot -boot-load-size 4 -boot-info-table test_image/ -o test.iso + +fwcfg-simple-test: + $(MAKE) fwcfg-common + qemu-system-x86_64 -net none -smp 4 -cdrom test.iso -debugcon stdio \ + -fw_cfg opt/org.limine-bootloader.background,file=test/bg.bmp \ + -fw_cfg opt/org.limine-bootloader.kernel,file=test/test.elf + +fwcfg-test: + $(MAKE) fwcfg-common + qemu-system-x86_64 -net none -smp 4 -cdrom test.iso -debugcon stdio \ + -fw_cfg opt/org.limine-bootloader.config,file=test/limine-fwcfg.cfg \ + -fw_cfg opt/org.limine-bootloader.background,file=test/bg.bmp \ + -fw_cfg opt/org.limine-bootloader.kernel,file=test/test.elf + .PHONY: ext2-test ext2-test: $(MAKE) test-clean diff --git a/stage23/drivers/fwcfg.h b/stage23/drivers/fwcfg.h new file mode 100644 index 00000000..c6048e11 --- /dev/null +++ b/stage23/drivers/fwcfg.h @@ -0,0 +1,10 @@ +#ifndef __DRIVERS__FWCFG_H__ +#define __DRIVERS__FWCFG_H__ + +#include +#include +#include + +bool fwcfg_open(struct file_handle *handle, const char *name); + +#endif diff --git a/stage23/drivers/fwcfg.s2.c b/stage23/drivers/fwcfg.s2.c new file mode 100644 index 00000000..b20c7fa5 --- /dev/null +++ b/stage23/drivers/fwcfg.s2.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include + +struct dma_descr { + uint32_t control; + uint32_t length; + uint64_t address; +}; + +struct fw_cfg_file { + uint32_t size; + uint16_t select; + uint16_t reserved; + char name[56]; +}; +struct fw_cfg_files { + uint32_t count; + struct fw_cfg_file f[]; +}; + +static uint16_t bswap16(uint16_t value) { + uint8_t* value_ptr = (uint8_t*)&value; + return value_ptr[0]<<8|value_ptr[1]; +} + +static uint32_t bswap32(uint32_t value) { + uint8_t* value_ptr = (uint8_t*)&value; + return value_ptr[0]<<24|value_ptr[1]<<16|value_ptr[2]<<8|value_ptr[3]; +} + +static void fwcfg_disp_read(uint16_t sel, uint32_t outsz, uint8_t* outbuf) { + outw(0x510, sel); + for (uint32_t i = 0;i < outsz;i++) outbuf[i] = inb(0x511); +} + +static struct fw_cfg_files* filebuf = NULL; +static const char* simple_mode_config = + "TIMEOUT=0\n" + ":simple mode config\n" + "KERNEL_PATH=fwcfg:///opt/org.limine-bootloader.kernel"; + +static const char* simple_mode_bg_config = + "TIMEOUT=0\n" + "GRAPHICS=yes\n" + "THEME_BACKGROUND=50000000\n" + "BACKGROUND_PATH=fwcfg:///opt/org.limine-bootloader.background\n" + "BACKGROUND_STYLE=stretched\n" + ":simple mode config\n" + "KERNEL_PATH=fwcfg:///opt/org.limine-bootloader.kernel"; + +static bool simple_mode = false; + +bool fwcfg_open(struct file_handle *handle, const char *name) { + char sig[5] = { 0 }; + fwcfg_disp_read(/* signature */ 0x0000, 4, (uint8_t*)sig); + if (strcmp(sig, "QEMU")) return false; + + uint32_t count; + fwcfg_disp_read(0x0019, 4, (uint8_t*)&count); + count = bswap32(count); + + if (!filebuf) { + filebuf = (struct fw_cfg_files*)ext_mem_alloc(count * 64 + 4); + fwcfg_disp_read(0x0019, count * 64 + 4, (uint8_t*)filebuf); + } + + bool has_kernel = false, has_background = false; + for (uint32_t i = 0;i < count;i++) { + if (!strncmp(filebuf->f[i].name, name, 56)) { + uint16_t sel = bswap16(filebuf->f[i].select); + handle->size = bswap32(filebuf->f[i].size); + handle->is_memfile = true; + uint8_t* buf = (uint8_t*)(handle->fd = ext_mem_alloc(handle->size)); + fwcfg_disp_read(sel, handle->size, buf); + return true; + } + if (!strncmp(filebuf->f[i].name, "opt/org.limine-bootloader.background", 56)) { + has_background = true; + } + if (!strncmp(filebuf->f[i].name, "opt/org.limine-bootloader.kernel", 56)) { + has_kernel = true; + } + } + + if (has_kernel && !strcmp(name, "opt/org.limine-bootloader.config")) { + const char* conf = has_background ? simple_mode_bg_config : simple_mode_config; + handle->size = strlen(conf); + handle->is_memfile = true; + char* buf = (char*)(handle->fd = ext_mem_alloc(handle->size + 1)); + strcpy(buf, conf); + simple_mode = true; + return true; + } + + return false; +} diff --git a/stage23/lib/config.c b/stage23/lib/config.c index 130bac71..9be23996 100644 --- a/stage23/lib/config.c +++ b/stage23/lib/config.c @@ -1,3 +1,4 @@ +#include "lib/uri.h" #include #include #include @@ -21,7 +22,8 @@ int init_config_disk(struct volume *part) { if ((f = fopen(part, "/limine.cfg")) == NULL && (f = fopen(part, "/boot/limine.cfg")) == NULL - && (f = fopen(part, "/EFI/BOOT/limine.cfg")) == NULL) { + && (f = fopen(part, "/EFI/BOOT/limine.cfg")) == NULL + && (f = uri_open("fwcfg:///opt/org.limine-bootloader.config")) == NULL) { return -1; } diff --git a/stage23/lib/uri.c b/stage23/lib/uri.c index da172831..c6d4dba5 100644 --- a/stage23/lib/uri.c +++ b/stage23/lib/uri.c @@ -8,6 +8,7 @@ #include #include #include +#include #include // A URI takes the form of: resource://root/path @@ -132,6 +133,15 @@ static struct file_handle *uri_guid_dispatch(char *guid_str, char *path) { return fopen(volume, path); } +static struct file_handle *uri_fwcfg_dispatch(char *path) { + struct file_handle *ret = ext_mem_alloc(sizeof(struct file_handle)); + if (!fwcfg_open(ret, path)) { + return NULL; + } + + return ret; +} + #if bios == 1 static struct file_handle *uri_tftp_dispatch(char *root, char *path) { uint32_t ip; @@ -210,6 +220,10 @@ struct file_handle *uri_open(char *uri) { } else if (!strcmp(resource, "tftp")) { ret = uri_tftp_dispatch(root, path); #endif + // note: fwcfg MUST be the last on the list due to fwcfg simple mode. + } else if (!strcmp(resource, "fwcfg")) { + if (*root != 0) panic("no root supported in an fwcfg:// uri!"); + ret = uri_fwcfg_dispatch(path); } else { panic("Resource `%s` not valid.", resource); } diff --git a/test/limine-fwcfg.cfg b/test/limine-fwcfg.cfg new file mode 100644 index 00000000..4711e1db --- /dev/null +++ b/test/limine-fwcfg.cfg @@ -0,0 +1,28 @@ +DEFAULT_ENTRY=1 +TIMEOUT=3 +GRAPHICS=yes +VERBOSE=yes + +THEME_BACKGROUND=50000000 + +BACKGROUND_PATH=fwcfg:///opt/org.limine-bootloader.background +BACKGROUND_STYLE=stretched +BACKDROP_COLOUR=008080 + +:fwcfg:// test + +COMMENT=Test of the stivale2 boot protocol. + +# Let's use autodetection +#PROTOCOL=stivale2 +RESOLUTION=800x600 +KERNEL_PATH=fwcfg:///opt/org.limine-bootloader.kernel +KERNEL_CMDLINE=Woah! Another example! + +MODULE_PATH=fwcfg:///opt/org.limine-bootloader.background +MODULE_STRING=yooooo + +# Test that the module string provided to the kernel will be +# the module path since a module string is not specified. +# (cc CONFIG.md stivale2.`MODULE_STRING` section) +MODULE_PATH=fwcfg:///opt/org.limine-bootloader.background diff --git a/test/limine.cfg b/test/limine.cfg index 23ae6778..3b456885 100644 --- a/test/limine.cfg +++ b/test/limine.cfg @@ -98,3 +98,4 @@ KERNEL_CMDLINE=Woah! Another example! MODULE_PATH=odd://1:/boot/bg.bmp MODULE_STRING=yooooo +