~sircmpwn/helios-devel

wstr: introduce function conv to convert strings from utf16 to utf8 v1 APPLIED

Simon Zeni: 4
 wstr: introduce function conv to convert strings from utf16 to utf8
 wstr: introduce wstrcmp to compare two char16_t strings
 fs: introduce readdir function
 modules: introduce load_modules function

 10 files changed, 176 insertions(+), 1 deletions(-)
Thanks!

To git@git.sr.ht:~sircmpwn/hboot
   8d4b296..745fe4f  master -> master
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~sircmpwn/helios-devel/patches/46856/mbox | git am -3
Learn more about email & git

[PATCH 1/4] wstr: introduce function conv to convert strings from utf16 to utf8 Export this patch

---
 include/wstr.h |  2 ++
 src/wstr.c     | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/include/wstr.h b/include/wstr.h
index 13f11c6..aea8dcc 100644
--- a/include/wstr.h
+++ b/include/wstr.h
@@ -1,7 +1,9 @@
#ifndef WSTR_H
#define WSTR_H

#include <efi/types.h> // for char16_t

char16_t *wconv(const char *str, char16_t *buf, size_t n);
char *conv(const char16_t *str, char *buf, size_t n);

#endif
diff --git a/src/wstr.c b/src/wstr.c
index 6f1227c..3b16205 100644
--- a/src/wstr.c
+++ b/src/wstr.c
@@ -13,3 +13,51 @@ wconv(const char *str, char16_t *buf, size_t n)
	buf[i] = 0;
	return buf;
}

/**
 * Thanks U-boot
 * https://elixir.bootlin.com/u-boot/v2023.10/source/lib/charset.c#L211
 */
int32_t utf16_get(const char16_t **src)
{
	int32_t code, code2;

	if (!src || !*src)
		return -1;
	if (!**src)
		return 0;
	code = **src;
	++*src;
	if (code >= 0xDC00 && code <= 0xDFFF)
		return -1;
	if (code >= 0xD800 && code <= 0xDBFF) {
		if (!**src)
			return -1;
		code &= 0x3ff;
		code <<= 10;
		code += 0x10000;
		code2 = **src;
		++*src;
		if (code2 <= 0xDC00 || code2 >= 0xDFFF)
			return -1;
		code2 &= 0x3ff;
		code += code2;
	}
	return code;
}

char *
conv(const char16_t *str, char *buf, size_t n)
{
	size_t i;
	for (i = 0; i < n; ++i) {
		int32_t c = utf16_get(&str);
		if (!c) {
			break;
		}
		buf[i] = c;
	}
	assert(i + 1 < n);
	buf[i] = 0;
	return buf;
}
-- 
2.42.1

[PATCH 2/4] wstr: introduce wstrcmp to compare two char16_t strings Export this patch

---
 include/wstr.h |  1 +
 src/wstr.c     | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/include/wstr.h b/include/wstr.h
index aea8dcc..229facc 100644
--- a/include/wstr.h
+++ b/include/wstr.h
@@ -5,5 +5,6 @@

char16_t *wconv(const char *str, char16_t *buf, size_t n);
char *conv(const char16_t *str, char *buf, size_t n);
int wstrcmp(const char16_t *str1, const char16_t *str2);

#endif
diff --git a/src/wstr.c b/src/wstr.c
index 3b16205..371ea78 100644
--- a/src/wstr.c
+++ b/src/wstr.c
@@ -61,3 +61,14 @@ conv(const char16_t *str, char *buf, size_t n)
	buf[i] = 0;
	return buf;
}

int
wstrcmp(const char16_t *str1, const char16_t *str2)
{
	while(*str1 && (*str1 == *str2))
	{
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
-- 
2.42.1
Thanks!

To git@git.sr.ht:~sircmpwn/hboot
   8d4b296..745fe4f  master -> master

[PATCH 3/4] fs: introduce readdir function Export this patch

---
 include/fs.h |  1 +
 src/fs.c     | 16 ++++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/include/fs.h b/include/fs.h
index 945ec94..ed8758b 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -10,5 +10,6 @@ efi_file_protocol *open(char16_t *filename, uint64_t mode, uint64_t attrs);
size_t read(efi_file_protocol *f, void *buf, size_t n);
void seek(efi_file_protocol *f, uint64_t pos);
void close(efi_file_protocol *f);
const efi_file_info *readdir(efi_file_protocol *file);

#endif
diff --git a/src/fs.c b/src/fs.c
index 34e425a..8201d46 100644
--- a/src/fs.c
+++ b/src/fs.c
@@ -5,6 +5,9 @@
#include <efi/protocol/simple-file-system.h>
#include "fs.h"

// Reserve space for file name in wstr
#define EFI_FILE_SIZE sizeof(efi_file_info) + 512

static efi_file_protocol *root = NULL;

efi_status
@@ -57,3 +60,16 @@ close(efi_file_protocol *f)
	efi_status st = f->Close(f);
	assert(st == EFI_SUCCESS);
}

const efi_file_info *
readdir(efi_file_protocol *file)
{
	static uint8_t buffer[EFI_FILE_SIZE] = {0};

	size_t n = read(file, buffer, sizeof(buffer));
	if (n == 0) {
		return NULL;
	}

	return (efi_file_info *)buffer;
}
-- 
2.42.1

[PATCH 4/4] modules: introduce load_modules function Export this patch

---
 Makefile          |  3 ++-
 include/modules.h | 12 +++++++++
 src/main.c        | 14 ++++++++++
 src/modules.c     | 69 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 97 insertions(+), 1 deletion(-)
 create mode 100644 include/modules.h
 create mode 100644 src/modules.c

diff --git a/Makefile b/Makefile
index 6c7db18..39a4de2 100644
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,7 @@ BOOT_OBJ=\
	 src/guids.o \
	 src/load.o \
	 src/main.o \
	 src/modules.o \
	 src/mmap.o \
	 src/mmu.o \
	 src/string.o \
@@ -53,6 +54,6 @@ nographic-gdb: boot.img
		-m 1G -no-reboot -no-shutdown \
		-drive file=boot.img,format=raw \
		-display none \
		-serial stdio -enable-kvm
		-serial stdio -enable-kvm -d cpu_reset

.PHONY: all clean nographic
diff --git a/include/modules.h b/include/modules.h
new file mode 100644
index 0000000..7d00057
--- /dev/null
+++ b/include/modules.h
@@ -0,0 +1,12 @@
#ifndef MODULES_H
#define MODULES_H

#include <efi/types.h>
#include <efi/system-table.h>
#include <efi/protocol/file.h>
#include "bootctx.h"

efi_status load_modules (efi_boot_services *bsvc, struct bootctx *ctx,
	efi_file_protocol *modules);

#endif
diff --git a/src/main.c b/src/main.c
index 3dbfed2..3d22f51 100644
--- a/src/main.c
+++ b/src/main.c
@@ -8,6 +8,7 @@
#include "global.h"
#include "hboot.h"
#include "load.h"
#include "modules.h"
#include "mmap.h"
#include "mmu.h"

@@ -55,6 +56,19 @@ efi_main(efi_handle image, efi_system_table *systab)

	close(kernel);

	efi_file_protocol *modules = open(L"\\modules", EFI_FILE_MODE_READ, 0);
	if (modules == NULL) {
		bprintfln("Error loading boot modules from /modules");
		return EFI_LOAD_ERROR;
	}

	st = load_modules(bsvc, ctx, modules);
	if (st != EFI_SUCCESS) {
		bprintfln("Error loading boot modules");
		return st;
	}
	close(modules);

	size_t map_key;
	st = collect_mmap(bsvc, ctx, &map_key);
	if (st != EFI_SUCCESS) {
diff --git a/src/modules.c b/src/modules.c
new file mode 100644
index 0000000..f3da398
--- /dev/null
+++ b/src/modules.c
@@ -0,0 +1,69 @@
#include <assert.h>
#include "bprintf.h"
#include "fs.h"
#include "modules.h"
#include "wstr.h"

#define MAX_MODS 16

efi_status load_modules(efi_boot_services *bsvc, struct bootctx *ctx,
		efi_file_protocol *modules)
{
	efi_status st = EFI_SUCCESS;

	struct bootmodule mods[MAX_MODS] = {0};
	
	size_t nmods;
	for (nmods = 0; nmods < MAX_MODS; ++nmods) {
		const efi_file_info *info = readdir(modules);
		if (info == NULL) {
			break;
		}

		if (info->Attribute & EFI_FILE_DIRECTORY ||
				wstrcmp(info->FileName, L".") == 0 ||
				wstrcmp(info->FileName, L"..") == 0) {
			continue;
		}

		char filename[256] = {0};
		conv(info->FileName, filename, sizeof(filename));
		bprintfln("Load boot module /modules/%s", filename);

		struct bootmodule *mod = &mods[nmods++];
		mod->length = info->FileSize;
		
		efi_file_protocol *file = NULL;
		modules->Open(modules, &file, info->FileName,
			EFI_FILE_MODE_READ, 0);
		if (file == NULL) {
			bprintfln("Error loading module");
			return EFI_LOAD_ERROR;
		}

		efi_physical_addr *data;
		st = bsvc->AllocatePool(EfiLoaderData, mod->length,
			(void **)&data);
		if (st != EFI_SUCCESS) {
			bprintfln("Failed to allocate file");
			return st;
		}
		size_t n = read(file, data, mod->length);
		assert(n == mod->length);
		mod->base = *data;
	}

	size_t slicesz = sizeof(struct bootmodule) * nmods;
	struct slice *slice = &ctx->mods;
	slice->length = nmods;
	slice->capacity = nmods;
	st = bsvc->AllocatePool(EfiLoaderData, slicesz, (void **)&slice->data);
	if (st != EFI_SUCCESS) {
		bprintfln("Failed to allocate modules slice");
		return st;
	}

	bsvc->CopyMem(slice->data, mods, slicesz);

	return st;
}
-- 
2.42.1