:: commit 98d43c14283fe6f48ca194bd07e7d07ec4f7e486

pitust <piotr@stelmaszek.com> — 2021-11-26 12:09

parents: f26c8eacc1

fwcfg: implement the fw_cfg interface

diff --git a/Makefile b/Makefile
index 0fa3899c..c99ee4bb 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 <stdint.h>
+#include <lib/blib.h>
+#include <lib/libc.h>
+
+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..1c23e114
--- /dev/null
+++ b/stage23/drivers/fwcfg.s2.c
@@ -0,0 +1,100 @@
+#include <stdint.h>
+#include <lib/libc.h>
+#include <lib/print.h>
+#include <mm/pmm.h>
+#include <lib/blib.h>
+#include <sys/cpu.h>
+
+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..1e8a8717 100644
--- a/stage23/lib/config.c
+++ b/stage23/lib/config.c
@@ -1,3 +1,4 @@
+#include "lib/uri.h"
 #include <stddef.h>
 #include <stdbool.h>
 #include <lib/config.h>
@@ -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 <mm/pmm.h>
 #include <lib/print.h>
 #include <pxe/tftp.h>
+#include <drivers/fwcfg.h>
 #include <tinf.h>
 
 // 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
+
tab: 248 wrap: offon