commit c41010422015c90adb51f7a39e4e33a152c89a4f
Author: Matsuda Kenji <info@mtkn.jp>
Date: Thu, 14 Mar 2024 14:27:44 +0900
first commit
Diffstat:
9 files changed, 309 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,3 @@
+image
+disk.img
+include
diff --git a/Makefile b/Makefile
@@ -0,0 +1,28 @@
+CC = x86_64-w64-mingw32-gcc
+CFLAGS = -shared -nostdlib -mno-red-zone -fno-stack-protector -O0 -Wall -e EfiMain
+OBJCOPY = objcopy
+SRC = hello.c utils.c
+HDR = uefi.h
+
+all: hello.efi
+
+hello.dll: $(SRC) $(HDR)
+ $(CC) $(CFLAGS) -o $@ $(SRC)
+
+hello.efi: hello.dll
+ $(OBJCOPY) --target=efi-app-x86_64 $< $@
+
+run: hello.efi
+ mkdir -p image
+ doas mount disk.img image
+ doas mkdir -p image/EFI/BOOT
+ doas cp hello.efi image/EFI/BOOT/BOOTX64.EFI
+ doas umount image
+ qemu-system-x86_64 -bios /usr/share/edk2/x64/OVMF.fd -drive format=raw,file=disk.img
+
+test: test/*
+ (cd test && make)
+
+clean:
+ rm -f *.o *.efi *.dll
+ (cd test && make clean)
+\ No newline at end of file
diff --git a/QEMU_EFI.fd b/QEMU_EFI.fd
Binary files differ.
diff --git a/hello.c b/hello.c
@@ -0,0 +1,30 @@
+#include "uefi.h"
+#include "utils.h"
+
+#include <stddef.h>
+
+EFI_STATUS
+EfiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
+{
+ // Output firmware bender.
+ SystemTable->ConOut->OutputString(SystemTable->ConOut, SystemTable->FirmwareVendor);
+
+ // Output memory map information.
+ UINTN mmsize = sizeof(EFI_MEMORY_DESCRIPTOR) * 32; // ?
+ EFI_MEMORY_DESCRIPTOR mmap[32];
+ UINTN mkey;
+ UINTN dsize;
+ UINT32 dver;
+
+ SystemTable->BootServices->GetMemoryMap(&mmsize, mmap, &mkey, &dsize, &dver);
+
+ // Echo back user input.
+ EFI_INPUT_KEY Key;
+ CHAR16 str[2] = {' ', '\0'};
+ while(1) {
+ SystemTable->ConIn->ReadKeyStroke(SystemTable->ConIn, &Key);
+ str[0] = Key.UnicodeChar;
+ SystemTable->ConOut->OutputString(SystemTable->ConOut, str);
+ }
+ return 0;
+}
diff --git a/test/Makefile b/test/Makefile
@@ -0,0 +1,11 @@
+CC = tcc
+SRC = utils_test.c ../utils.c
+
+all: test
+ ./test
+
+test: $(SRC)
+ $(CC) -O0 -g -o test $(SRC)
+
+clean:
+ rm -f test
+\ No newline at end of file
diff --git a/test/utils_test.c b/test/utils_test.c
@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../uefi.h"
+#include "../utils.h"
+
+int
+str16cmp(CHAR16 *s, CHAR16 *t)
+{
+ for (; *s != 0 && *t != 0; s++, t++) {
+ if (*s == *t) {
+ continue;
+ } else if (*s < *t) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ if (*s != 0) {
+ return 1;
+ } else if (*t != 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+// Strtostr16 converts string s to UTF16 string.
+// Caller should free the returned pointer.
+CHAR16 *
+strtostr16(char *s)
+{
+ int n;
+ CHAR16 *ss, *st;
+
+ n = strlen(s);
+ ss = st = (CHAR16 *) malloc((n+1) * sizeof(CHAR16));
+ if (!ss)
+ return NULL;
+ for (; *s; ) {
+ *ss++ = (CHAR16) *s++;
+ }
+ return st;
+}
+
+char *
+str16tostr(CHAR16 *s)
+{
+ int n = 0;
+ CHAR16 *t;
+ for (t = s; *t; t++) {
+ n++;
+ }
+ char *ss, *tt;
+ ss = tt = (char *)malloc((n + 1) * sizeof(char));
+ if (!ss) {
+ return NULL;
+ }
+ for (tt = ss, t = s; *t;) {
+ *tt++ = (char) (*t++ & 0xff);
+ }
+ *tt = '\0';
+ return ss;
+}
+
+int
+testSprinth()
+{
+ int nerr = 0;
+ struct test {
+ UINT64 input;
+ CHAR16 *want;
+ } tests[] = {
+ {0xdeadbeef, strtostr16("0x00000000deadbeef")},
+ {0xcafecafe, strtostr16("0x00000000cafecafe")},
+ {0, NULL},
+ };
+ struct test *t;
+ CHAR16 got[19];
+ for (t = tests; t->want; t++) {
+ if (str16cmp(t->want, sprinth(t->input, got)) != 0) {
+ fprintf(stderr, "sprinth(0x%x, got) = %s, want: %s\n",
+ t->input, str16tostr(got), str16tostr(t->want));
+ nerr++;
+ }
+ }
+ return nerr;
+}
+
+int
+main(void)
+{
+ testSprinth();
+}
+\ No newline at end of file
diff --git a/uefi.h b/uefi.h
@@ -0,0 +1,109 @@
+#define IN
+#define OUT
+#define OPTIONAL
+#define CONST
+#define EFIAPI
+
+typedef unsigned short CHAR16;
+typedef unsigned long long UINTN;
+typedef unsigned short UINT16;
+typedef unsigned UINT32;
+typedef unsigned long long UINT64;
+typedef unsigned long long EFI_STATUS;
+typedef void *EFI_HANDLE;
+typedef UINT64 EFI_PHYSICAL_ADDRESS;
+typedef UINT64 EFI_VIRTUAL_ADDRESS;
+
+typedef struct {
+ UINT16 ScanCode;
+ CHAR16 UnicodeChar;
+} EFI_INPUT_KEY;
+
+struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
+typedef
+EFI_STATUS (EFIAPI *EFI_INPUT_READ_KEY)(
+ IN struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
+ void *dummy;
+ EFI_INPUT_READ_KEY ReadKeyStroke;
+} EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
+
+struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
+typedef
+EFI_STATUS (EFIAPI *EFI_TEXT_STRING)(
+ IN struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ );
+
+typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
+ void *dummy;
+ EFI_TEXT_STRING OutputString;
+} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
+
+typedef struct { // TODO implement.
+ UINT32 Type;
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ EFI_VIRTUAL_ADDRESS VirtualStart;
+ UINT64 NumberOfPages;
+ UINT64 Attribute;
+} EFI_MEMORY_DESCRIPTOR;
+
+typedef
+EFI_STATUS (EFIAPI *EFI_GET_MEMORY_MAP)(
+ IN OUT UINTN *MemoryMapSize,
+ OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+typedef
+EFI_STATUS (EFIAPI *EFI_EXIT_BOOT_SERVICES)(
+ );
+
+typedef struct {
+} EFI_RUNTIME_SERVICES;
+
+typedef struct {
+ UINT64 Signature;
+ UINT32 Revision;
+ UINT32 HeaderSize;
+ UINT32 CRC32;
+ UINT32 Reserved;
+} EFI_TABLE_HEADER;
+
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+ // task priority services
+ void *task_priority_services[2];
+ // memory services
+ void *memory_services0[2];
+ EFI_GET_MEMORY_MAP GetMemoryMap;
+ void *memory_services1[2];
+ // event timer services
+ void *event_timer_services[6];
+ // protocol handler services
+ void *protocol_handler_services[9];
+ // image services
+ void *image_services0[4];
+ EFI_EXIT_BOOT_SERVICES ExitBootServices;
+ void *dummy[17];
+} EFI_BOOT_SERVICES;
+
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+ CHAR16 *FirmwareVendor;
+ char dummy1[4];
+ EFI_HANDLE ConsoleInHandle;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ EFI_HANDLE ConsoleOutHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+ EFI_HANDLE StandardErrorHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
+ EFI_RUNTIME_SERVICES *RuntimeServices;
+ EFI_BOOT_SERVICES *BootServices;
+ char dummy2[16];
+} EFI_SYSTEM_TABLE;
diff --git a/utils.c b/utils.c
@@ -0,0 +1,22 @@
+#include "uefi.h"
+#include "utils.h"
+
+#include <stdio.h>
+
+CHAR16 *
+sprinth(UINT64 n, CHAR16 s[19])
+{
+ int i;
+ int d;
+ s[0] = L'0';
+ s[1] = L'x';
+ for (i = 0; i < 16; i++) {
+ d = (n >> (64 - (i + 1) * 4)) & 0xf;
+ if (d <= 9)
+ s[i + 2] = L'0' + d;
+ else
+ s[i + 2] = L'a' + d - 10;
+ }
+ s[19] = L'\0';
+ return s;
+}
+\ No newline at end of file
diff --git a/utils.h b/utils.h
@@ -0,0 +1,6 @@
+// #include "uefi.h"
+
+// Printh converts the integer into a string of hex representation.
+// It returns the second argument.
+// The second argument should have length of 19 ("0x" + "0123456789abcdef" + "\0").
+CHAR16 *sprinth(UINT64, CHAR16[19]);
+\ No newline at end of file