Browse Source

重定位内核并加载 (#7)

未完成:退出BootServices
LoGin 5 months ago
parent
commit
823f049319

+ 7 - 1
.vscode/settings.json

@@ -38,6 +38,12 @@
         "stddef.h": "c",
         "stdbool.h": "c",
         "libfdt_env.h": "c",
-        "libfdt_internal.h": "c"
+        "libfdt_internal.h": "c",
+        "efiapi.h": "c",
+        "elfloader.h": "c",
+        "efidebug.h": "c",
+        "align.h": "c",
+        "math.h": "c",
+        "csr.h": "c"
     }
 }

+ 3 - 0
Makefile

@@ -113,6 +113,9 @@ clean:
 		fi; \
 	done
 
+gdb:
+	gdb-multiarch -n -x tools/.gdbinit
+
 install:
 	@set -e ; for d in $(SUBDIRS); do \
 		mkdir -p $(OBJDIR)/$$d; \

+ 2 - 1
apps/Makefile

@@ -87,7 +87,7 @@ endif
 
 
 
-DRAGON_STUB_FILES:= dragon_stub-main.c stub.c helper.c
+DRAGON_STUB_FILES:= dragon_stub-main.c stub.c helper.c fdt.c secureboot.c elf.c mem.c alignedmem.c random.c
 DRAGON_STUB_FILES += lib/vsprintf.c lib/hexdump.c lib/ctype.c lib/cmdline.c lib/string.c
 __LIBFDT_DIR=lib/libfdt
 DRAGON_STUB_FILES += $(__LIBFDT_DIR)/fdt_addresses.c $(__LIBFDT_DIR)/fdt_empty_tree.c $(__LIBFDT_DIR)/fdt_overlay.c $(__LIBFDT_DIR)/fdt_ro.c \
@@ -98,6 +98,7 @@ INCDIR += -I$(TOPDIR)/apps/lib/libfdt
 
 ifeq ($(ARCH), riscv64)
 	DRAGON_STUB_FILES += riscv-stub.c
+	INCDIR += -I$(TOPDIR)/inc/dragonstub/linux/arch/riscv
 endif
 
 # 把*.c的列表转换为*.o的列表

+ 58 - 0
apps/alignedmem.c

@@ -0,0 +1,58 @@
+#include <dragonstub/dragonstub.h>
+#include <dragonstub/linux/align.h>
+#include <dragonstub/linux/math.h>
+
+
+/**
+ * efi_allocate_pages_aligned() - Allocate memory pages
+ * @size:	minimum number of bytes to allocate
+ * @addr:	On return the address of the first allocated page. The first
+ *		allocated page has alignment EFI_ALLOC_ALIGN which is an
+ *		architecture dependent multiple of the page size.
+ * @max:	the address that the last allocated memory page shall not
+ *		exceed
+ * @align:	minimum alignment of the base of the allocation
+ *
+ * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
+ * to @align, which should be >= EFI_ALLOC_ALIGN. The last allocated page will
+ * not exceed the address given by @max.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
+					unsigned long max, unsigned long align,
+					int memory_type)
+{
+	efi_physical_addr_t alloc_addr;
+	efi_status_t status;
+	int slack;
+
+	max = min(max, EFI_ALLOC_LIMIT);
+
+	if (align < EFI_ALLOC_ALIGN)
+		align = EFI_ALLOC_ALIGN;
+
+	alloc_addr = ALIGN_DOWN(max + 1, align) - 1;
+	size = round_up(size, EFI_ALLOC_ALIGN);
+	slack = align / EFI_PAGE_SIZE - 1;
+
+	status = efi_bs_call(AllocatePages, EFI_ALLOCATE_MAX_ADDRESS,
+			     memory_type, size / EFI_PAGE_SIZE + slack,
+			     &alloc_addr);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	*addr = ALIGN_UP((unsigned long)alloc_addr, align);
+
+	if (slack > 0) {
+		int l = (alloc_addr & (align - 1)) / EFI_PAGE_SIZE;
+
+		if (l) {
+			efi_bs_call(FreePages, alloc_addr, slack - l + 1);
+			slack = l - 1;
+		}
+		if (slack)
+			efi_bs_call(FreePages, *addr + size, slack);
+	}
+	return EFI_SUCCESS;
+}

+ 25 - 2
apps/dragon_stub-main.c

@@ -5,6 +5,26 @@
 
 void print_dragonstub_banner(void);
 
+static EFI_STATUS test_exit_bs(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab){
+	EFI_STATUS status;
+	struct efi_boot_memmap *map;
+
+	status = efi_get_memory_map(&map, false);
+	if (status != EFI_SUCCESS)
+		return status;
+	efi_debug("before priv_func\n");
+	
+	efi_debug("map->map_size: %d\n", map->map_size);
+	efi_debug("before ExitBootServices, handle=%p, map_key=%p\n", image_handle,
+		  map->map_key);
+
+	status = efi_bs_call(ExitBootServices, image_handle, map->map_key);
+
+	efi_debug("after ExitBootServices, status: %d\n", status);
+
+	while(1);
+}
+
 EFI_STATUS
 efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
 {
@@ -18,7 +38,7 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
 	print_dragonstub_banner();
 
 	efi_info("EFI env initialized\n");
-
+	
 	/*
 	 * Get a handle to the loaded image protocol.  This is used to get
 	 * information about the running image, such as size and the command
@@ -28,6 +48,7 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
 				   &LoadedImageProtocol, (void **)&loaded_image,
 				   image_handle, NULL,
 				   EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
 	if (EFI_ERROR(status)) {
 		efi_err("Could not open loaded image protocol: %d\n", status);
 		return status;
@@ -46,6 +67,8 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
 	else
 		efi_info("Command line: %s\n", cmdline_ptr);
 
+	
+
 	struct payload_info payload;
 	status = find_payload(image_handle, loaded_image, &payload);
 	if (EFI_ERROR(status)) {
@@ -53,7 +76,7 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
 		return status;
 	}
 	efi_info("Booting DragonOS kernel...\n");
-	efi_stub_common(image_handle, &payload, cmdline_ptr);
+	efi_stub_common(image_handle, loaded_image, &payload, cmdline_ptr);
 	efi_todo("Boot DragonOS kernel");
 
 	return EFI_SUCCESS;

+ 350 - 0
apps/elf.c

@@ -0,0 +1,350 @@
+#include "elf.h"
+#include "dragonstub/linux/align.h"
+#include <efi.h>
+#include <efiapi.h>
+#include <efilib.h>
+#include <dragonstub/dragonstub.h>
+#include <dragonstub/elfloader.h>
+
+/// @brief 校验ELF文件头
+/// @param buf 缓冲区
+/// @param bufsize 缓冲区大小
+/// @return
+static bool verify_ident(const void *buf, u64 bufsize)
+{
+	if (bufsize < EI_NIDENT) {
+		// 太短,不是ELF
+		return false;
+	}
+	// 检查magic number
+	for (int i = 0; i < EI_CLASS; i++) {
+		u8 c = *(u8 *)(buf + i);
+		if (c != ELFMAG[i]) {
+			// 不是ELF magic number,跳过
+			efi_err("ELF magic number not match\n");
+			return false;
+		}
+	}
+
+	// verify ELF Version
+	u8 version = *(u8 *)(buf + EI_VERSION);
+	if (version != EV_CURRENT) {
+		efi_err("ELF version not match, expected EV_CURRENT(%d), got %d\n",
+			EV_CURRENT, version);
+		// 不是当前版本,跳过
+		return false;
+	}
+
+	// verify ELF Class
+	u8 class = *(u8 *)(buf + EI_CLASS);
+	if (class != ELFCLASS64) {
+		efi_err("ELF class not match, expected ELFCLASS64(%d), got %d\n",
+			ELFCLASS64, class);
+		// 不是64位,跳过
+		return false;
+	}
+
+	return true;
+}
+
+bool elf_check(const void *payload_start, u64 payload_size)
+{
+	// 校验ELF文件头
+	if (!verify_ident(payload_start, payload_size)) {
+		return false;
+	}
+	// 检查架构
+	Elf64_Ehdr *ehdr = (Elf64_Ehdr *)payload_start;
+#ifdef CONFIG_riscv64
+	if (ehdr->e_machine != EM_RISCV) {
+		efi_err("ELF machine not match, expected EM_RISCV(%d), got %d\n",
+			EM_RISCV, ehdr->e_machine);
+		return false;
+	}
+#else
+// 还没有对当前架构进行检查,抛出编译错误
+#error "Unimplement ELF arch test for current cross compile arch"
+#endif
+	return true;
+}
+
+/// @brief 获取ELF文件头
+/// @param payload_start 文件起始地址
+/// @param payload_size 文件大小
+/// @param ehdr 返回的ELF文件头
+/// @return
+efi_status_t elf_get_header(const void *payload_start, u64 payload_size,
+			    Elf64_Ehdr **ehdr)
+{
+	if (!verify_ident(payload_start, payload_size)) {
+		return EFI_INVALID_PARAMETER;
+	}
+	*ehdr = (Elf64_Ehdr *)payload_start;
+	return EFI_SUCCESS;
+}
+
+static void print_elf_info(Elf64_Ehdr *ehdr)
+{
+	efi_info("ELF header:\n");
+	efi_printk("  e_type: %d\n", ehdr->e_type);
+	efi_printk("  e_machine: %d\n", ehdr->e_machine);
+	efi_printk("  e_version: %d\n", ehdr->e_version);
+	efi_printk("  e_entry: %p\n", ehdr->e_entry);
+	efi_printk("  e_phoff: %p\n", ehdr->e_phoff);
+	efi_printk("  e_shoff: %p\n", ehdr->e_shoff);
+	efi_printk("  e_flags: %d\n", ehdr->e_flags);
+	efi_printk("  e_ehsize: %d\n", ehdr->e_ehsize);
+	efi_printk("  e_phentsize: %d\n", ehdr->e_phentsize);
+	efi_printk("  e_phnum: %d\n", ehdr->e_phnum);
+	efi_printk("  e_shentsize: %d\n", ehdr->e_shentsize);
+	efi_printk("  e_shnum: %d\n", ehdr->e_shnum);
+	efi_printk("  e_shstrndx: %d\n", ehdr->e_shstrndx);
+}
+
+static efi_status_t parse_phdrs(const void *payload_start, u64 payload_size,
+				const Elf64_Ehdr *ehdr, u32 *ret_segments_nr,
+				Elf64_Phdr **ret_phdr)
+{
+	if (ehdr->e_phnum == 0) {
+		efi_err("No program header\n");
+		return EFI_INVALID_PARAMETER;
+	}
+	if (ehdr->e_phentsize != sizeof(Elf64_Phdr)) {
+		efi_err("Invalid program header size: %d, expected %d\n",
+			ehdr->e_phentsize, sizeof(Elf64_Phdr));
+		return EFI_INVALID_PARAMETER;
+	}
+
+	u16 phnum = ehdr->e_phnum;
+	if (phnum == PN_XNUM) {
+		u64 shoff = ehdr->e_shoff;
+		if (shoff == 0) {
+			efi_err("No section header\n");
+			return EFI_INVALID_PARAMETER;
+		}
+
+		if (shoff + sizeof(Elf64_Shdr) > payload_size) {
+			efi_err("Section header out of range\n");
+			return EFI_INVALID_PARAMETER;
+		}
+
+		Elf64_Shdr *shdr = (Elf64_Shdr *)(payload_start + shoff);
+
+		phnum = shdr[0].sh_info;
+		if (phnum == 0) {
+			efi_err("shdr[0].sh_info indicates no program header\n");
+			return EFI_INVALID_PARAMETER;
+		}
+	}
+
+	size_t phoff = ehdr->e_phoff;
+	size_t phsize = ehdr->e_phentsize;
+	size_t total_size = phnum * phsize;
+	if (phoff + total_size > payload_size) {
+		efi_err("Program header out of range\n");
+		return EFI_INVALID_PARAMETER;
+	}
+
+	Elf64_Phdr *phdr = (Elf64_Phdr *)(payload_start + phoff);
+
+	*ret_segments_nr = phnum;
+	*ret_phdr = phdr;
+
+	return EFI_SUCCESS;
+}
+
+/*
+ * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
+ * to provide space, and fail to zero it). Check for this condition by double
+ * checking that the first and the last byte of the image are covered by the
+ * same EFI memory map entry.
+ */
+static bool check_image_region(u64 base, u64 size)
+{
+	struct efi_boot_memmap *map;
+	efi_status_t status;
+	bool ret = false;
+	u64 map_offset;
+
+	status = efi_get_memory_map(&map, false);
+	if (status != EFI_SUCCESS)
+		return false;
+
+	for (map_offset = 0; map_offset < map->map_size;
+	     map_offset += map->desc_size) {
+		efi_memory_desc_t *md = (void *)map->map + map_offset;
+		u64 end = md->PhysicalStart + md->NumberOfPages * EFI_PAGE_SIZE;
+
+		/*
+		 * Find the region that covers base, and return whether
+		 * it covers base+size bytes.
+		 */
+		if (base >= md->PhysicalStart && base < end) {
+			ret = (base + size) <= end;
+			break;
+		}
+	}
+
+	efi_bs_call(FreePool, map);
+
+	return ret;
+}
+efi_status_t efi_allocate_kernel_memory(const Elf64_Phdr *phdr_start,
+					u32 phdrs_nr, u64 *ret_paddr,
+					u64 *ret_size, u64 *ret_min_paddr,
+					u64 *ret_max_paddr)
+{
+	efi_status_t status = EFI_SUCCESS;
+
+	const Elf64_Phdr *phdr = phdr_start;
+
+	u64 min_paddr = UINT64_MAX;
+	u64 max_paddr = 0;
+	for (u32 i = 0; i < phdrs_nr; ++i, ++phdr) {
+		if (phdr->p_type != PT_LOAD) {
+			continue;
+		}
+
+		if (phdr->p_align & !EFI_PAGE_SIZE) {
+			efi_err("ELF segment alignment should be multiple of EFI_PAGE_SIZE(%d), but got %d\n",
+				EFI_PAGE_SIZE, phdr->p_align);
+			return EFI_INVALID_PARAMETER;
+		}
+		min_paddr = min(min_paddr, (u64)phdr->p_paddr);
+		max_paddr =
+			max(max_paddr, (u64)(phdr->p_paddr + phdr->p_memsz));
+	}
+
+	u64 mem_size = ALIGN_UP(max_paddr - min_paddr, EFI_PAGE_SIZE);
+
+	status = efi_allocate_pages_aligned(mem_size, ret_paddr, UINT64_MAX,
+					    EFI_PAGE_SIZE, EfiLoaderData);
+	// status = efi_allocate_pages_exact(mem_size, paddr);
+	if (status != EFI_SUCCESS) {
+		efi_err("Failed to allocate pages for ELF segment: status: %d, page_size=%d, min_paddr=%p, max_paddr=%p, mem_size=%d. Maybe an OOM error or section overlaps.\n",
+			status, EFI_PAGE_SIZE, ret_paddr, max_paddr, mem_size);
+		return status;
+	}
+
+	*ret_size = mem_size;
+	*ret_min_paddr = min_paddr;
+	*ret_max_paddr = max_paddr;
+	efi_info("Allocated kernel memory: paddr=%p, mem_size= %d bytes\n",
+		 *ret_paddr, mem_size);
+	// zeroed the memory
+	memset((void *)(*ret_paddr), 0, mem_size);
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t load_program(const void *payload_start, u64 payload_size,
+				 const Elf64_Phdr *phdr_start, u32 phdrs_nr,
+				 u64 *ret_program_mem_paddr,
+				 u64 *ret_program_mem_size, u64 *ret_min_paddr)
+{
+	efi_status_t status = EFI_SUCCESS;
+
+	u64 allocated_paddr = 0;
+	u64 allocated_size = 0;
+	u64 min_paddr = 0;
+	u64 max_paddr = 0;
+	status = efi_allocate_kernel_memory(phdr_start, phdrs_nr,
+					    &allocated_paddr, &allocated_size,
+					    &min_paddr, &max_paddr);
+	if (status != EFI_SUCCESS) {
+		efi_err("Failed to allocate kernel memory\n");
+		return status;
+	}
+	const Elf64_Phdr *phdr = phdr_start;
+
+	for (u32 i = 0; i < phdrs_nr; ++i, ++phdr) {
+		if (phdr->p_type != PT_LOAD) {
+			continue;
+		}
+
+		if (phdr->p_align & !EFI_PAGE_SIZE) {
+			efi_err("ELF segment alignment should be multiple of EFI_PAGE_SIZE(%d), but got %d\n",
+				EFI_PAGE_SIZE, phdr->p_align);
+			status = EFI_INVALID_PARAMETER;
+			goto failed;
+		}
+
+		u64 paddr = phdr->p_paddr;
+
+		u64 mem_size = phdr->p_memsz;
+		u64 file_size = phdr->p_filesz;
+		u64 file_offset = phdr->p_offset;
+		// efi_debug(
+		// 	"loading segment: paddr=%p, mem_size=%d, file_size=%d\n",
+		// 	paddr, mem_size, file_size);
+
+		if (file_offset + file_size > payload_size) {
+			status = EFI_INVALID_PARAMETER;
+			goto failed;
+		}
+
+		if (mem_size < file_size) {
+			status = EFI_INVALID_PARAMETER;
+			goto failed;
+		}
+
+		if (mem_size == 0) {
+			continue;
+		}
+
+		memcpy((void *)(allocated_paddr + (paddr - min_paddr)),
+		       payload_start + file_offset, file_size);
+
+		// efi_debug(
+		// 	"segment loaded: paddr=%p, mem_size=%d, file_size=%d\n",
+		// 	paddr, mem_size, file_size);
+	}
+
+	*ret_program_mem_paddr = allocated_paddr;
+	*ret_program_mem_size = allocated_size;
+	*ret_min_paddr = min_paddr;
+
+	return EFI_SUCCESS;
+failed:
+	efi_free(allocated_size, allocated_paddr);
+	return status;
+}
+
+efi_status_t load_elf(struct payload_info *payload_info)
+{
+	const void *payload_start = (void *)payload_info->payload_addr;
+	u64 payload_size = payload_info->payload_size;
+	Elf64_Ehdr *ehdr = NULL;
+	efi_status_t status =
+		elf_get_header(payload_start, payload_size, &ehdr);
+	if (status != EFI_SUCCESS) {
+		efi_err("Failed to get ELF header\n");
+		return status;
+	}
+	ASSERT(ehdr != NULL);
+
+	print_elf_info(ehdr);
+
+	u32 phdrs_nr = 0;
+	Elf64_Phdr *phdr_start = NULL;
+
+	status = parse_phdrs(payload_start, payload_size, ehdr, &phdrs_nr,
+			     &phdr_start);
+	if (status != EFI_SUCCESS) {
+		efi_err("Failed to parse ELF segments\n");
+		return status;
+	}
+
+	efi_debug("program headers: %d\n", phdrs_nr);
+
+	u64 program_paddr = 0;
+	u64 program_size = 0;
+	u64 image_link_base_paddr = 0;
+	load_program(payload_start, payload_size, phdr_start, phdrs_nr,
+		     &program_paddr, &program_size, &image_link_base_paddr);
+	payload_info->loaded_paddr = program_paddr;
+	payload_info->loaded_size = program_size;
+	payload_info->kernel_entry =
+		ehdr->e_entry - image_link_base_paddr + program_paddr;
+	return EFI_SUCCESS;
+}

+ 403 - 0
apps/fdt.c

@@ -0,0 +1,403 @@
+#include "dragonstub/elfloader.h"
+#include "dragonstub/printk.h"
+#include "efidef.h"
+#include <dragonstub/dragonstub.h>
+#include <libfdt.h>
+#include <libfdt_internal.h>
+
+struct exit_boot_struct {
+	struct efi_boot_memmap *boot_memmap;
+	efi_memory_desc_t *runtime_map;
+	int runtime_entry_count;
+	void *new_fdt_addr;
+};
+
+#define EFI_DT_ADDR_CELLS_DEFAULT 2
+#define EFI_DT_SIZE_CELLS_DEFAULT 2
+
+static void fdt_update_cell_size(void *fdt)
+{
+	int offset;
+
+	offset = fdt_path_offset(fdt, "/");
+	/* Set the #address-cells and #size-cells values for an empty tree */
+
+	fdt_setprop_u32(fdt, offset, "#address-cells",
+			EFI_DT_ADDR_CELLS_DEFAULT);
+	fdt_setprop_u32(fdt, offset, "#size-cells", EFI_DT_SIZE_CELLS_DEFAULT);
+}
+
+static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
+{
+	int node = fdt_path_offset(fdt, "/chosen");
+	u64 fdt_val64;
+	u32 fdt_val32;
+	int err;
+
+	if (node < 0)
+		return EFI_LOAD_ERROR;
+
+	fdt_val64 = cpu_to_fdt64((unsigned long)map->map);
+
+	err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-start",
+				      fdt_val64);
+	if (err)
+		return EFI_LOAD_ERROR;
+
+	fdt_val32 = cpu_to_fdt32(map->map_size);
+
+	err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-size",
+				      fdt_val32);
+	if (err)
+		return EFI_LOAD_ERROR;
+
+	fdt_val32 = cpu_to_fdt32(map->desc_size);
+
+	err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-desc-size",
+				      fdt_val32);
+	if (err)
+		return EFI_LOAD_ERROR;
+
+	fdt_val32 = cpu_to_fdt32(map->desc_ver);
+
+	err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-desc-ver",
+				      fdt_val32);
+	if (err)
+		return EFI_LOAD_ERROR;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
+			       void *fdt, int new_fdt_size, char *cmdline_ptr)
+{
+	int node, num_rsv;
+	int status;
+	u32 fdt_val32;
+	u64 fdt_val64;
+
+	/* Do some checks on provided FDT, if it exists: */
+	if (orig_fdt) {
+		if (fdt_check_header(orig_fdt)) {
+			efi_err("Device Tree header not valid!\n");
+			return EFI_LOAD_ERROR;
+		}
+		/*
+		 * We don't get the size of the FDT if we get if from a
+		 * configuration table:
+		 */
+		if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) {
+			efi_err("Truncated device tree! foo!\n");
+			return EFI_LOAD_ERROR;
+		}
+	}
+
+	if (orig_fdt) {
+		status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
+	} else {
+		status = fdt_create_empty_tree(fdt, new_fdt_size);
+		if (status == 0) {
+			/*
+			 * Any failure from the following function is
+			 * non-critical:
+			 */
+			fdt_update_cell_size(fdt);
+		}
+	}
+
+	if (status != 0)
+		goto fdt_set_fail;
+
+	/*
+	 * Delete all memory reserve map entries. When booting via UEFI,
+	 * kernel will use the UEFI memory map to find reserved regions.
+	 */
+	num_rsv = fdt_num_mem_rsv(fdt);
+	while (num_rsv-- > 0)
+		fdt_del_mem_rsv(fdt, num_rsv);
+
+	node = fdt_subnode_offset(fdt, 0, "chosen");
+	if (node < 0) {
+		node = fdt_add_subnode(fdt, 0, "chosen");
+		if (node < 0) {
+			/* 'node' is an error code when negative: */
+			status = node;
+			goto fdt_set_fail;
+		}
+	}
+
+	if (cmdline_ptr != NULL && strlen(cmdline_ptr) > 0) {
+		status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
+				     strlen(cmdline_ptr) + 1);
+		if (status)
+			goto fdt_set_fail;
+	}
+
+	/* Add FDT entries for EFI runtime services in chosen node. */
+	node = fdt_subnode_offset(fdt, 0, "chosen");
+	fdt_val64 = cpu_to_fdt64((u64)(unsigned long)ST);
+
+	status = fdt_setprop_var(fdt, node, "linux,uefi-system-table",
+				 fdt_val64);
+	if (status)
+		goto fdt_set_fail;
+
+	fdt_val64 = UINT64_MAX; /* placeholder */
+
+	status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-start", fdt_val64);
+	if (status)
+		goto fdt_set_fail;
+
+	fdt_val32 = UINT32_MAX; /* placeholder */
+
+	status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-size", fdt_val32);
+	if (status)
+		goto fdt_set_fail;
+
+	status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-desc-size",
+				 fdt_val32);
+	if (status)
+		goto fdt_set_fail;
+
+	status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-desc-ver",
+				 fdt_val32);
+	if (status)
+		goto fdt_set_fail;
+
+	bool enalbed_ramdomize_base = false;
+#ifdef CONFIG_RANDOMIZE_BASE
+	enalbed_ramdomize_base = true;
+#endif
+	if (enalbed_ramdomize_base && !efi_nokaslr) {
+		efi_status_t efi_status;
+
+		efi_status = efi_get_random_bytes(sizeof(fdt_val64),
+						  (u8 *)&fdt_val64);
+		if (efi_status == EFI_SUCCESS) {
+			status = fdt_setprop_var(fdt, node, "kaslr-seed",
+						 fdt_val64);
+			if (status)
+				goto fdt_set_fail;
+		}
+	}
+
+	/* Shrink the FDT back to its minimum size: */
+	fdt_pack(fdt);
+
+	return EFI_SUCCESS;
+
+fdt_set_fail:
+	if (status == -FDT_ERR_NOSPACE)
+		return EFI_BUFFER_TOO_SMALL;
+
+	return EFI_LOAD_ERROR;
+}
+
+static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
+{
+	struct exit_boot_struct *p = priv;
+
+	p->boot_memmap = map;
+
+	/*
+	 * Update the memory map with virtual addresses. The function will also
+	 * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME
+	 * entries so that we can pass it straight to SetVirtualAddressMap()
+	 */
+	efi_get_virtmap(map->map, map->map_size, map->desc_size, p->runtime_map,
+			&p->runtime_entry_count);
+
+	return update_fdt_memmap(p->new_fdt_addr, map);
+}
+
+/*
+ * Allocate memory for a new FDT, then add EFI and commandline related fields
+ * to the FDT.  This routine increases the FDT allocation size until the
+ * allocated memory is large enough.  EFI allocations are in EFI_PAGE_SIZE
+ * granules, which are fixed at 4K bytes, so in most cases the first allocation
+ * should succeed.  EFI boot services are exited at the end of this function.
+ * There must be no allocations between the get_memory_map() call and the
+ * exit_boot_services() call, so the exiting of boot services is very tightly
+ * tied to the creation of the FDT with the final memory map in it.
+ */
+static efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
+						   efi_loaded_image_t *image,
+						   unsigned long *new_fdt_addr,
+						   char *cmdline_ptr)
+{
+	unsigned long desc_size;
+	u32 desc_ver;
+	efi_status_t status;
+	struct exit_boot_struct priv = { 0 };
+	unsigned long fdt_addr = 0;
+	unsigned long fdt_size = 0;
+	if (!efi_novamap) {
+		status = efi_alloc_virtmap(&priv.runtime_map, &desc_size,
+					   &desc_ver);
+		if (status != EFI_SUCCESS) {
+			efi_err("Unable to retrieve UEFI memory map.\n");
+			return status;
+		}
+	}
+	/*
+	 * Unauthenticated device tree data is a security hazard, so ignore
+	 * 'dtb=' unless UEFI Secure Boot is disabled.  We assume that secure
+	 * boot is enabled if we can't determine its state.
+	 */
+	bool config_efi_armstub_dtb_loader = false;
+#ifdef CONFIG_EFI_ARMSTUB_DTB_LOADER
+	config_efi_armstub_dtb_loader = true;
+#endif
+	print_efi_secureboot_mode(efi_get_secureboot());
+
+	if (!config_efi_armstub_dtb_loader ||
+	    efi_get_secureboot() != efi_secureboot_mode_disabled) {
+		if (strstr(cmdline_ptr, "dtb="))
+			efi_err("Ignoring DTB from command line.\n");
+	} else {
+		efi_todo("Load DTB from command line\n");
+		// status = efi_load_dtb(image, &fdt_addr, &fdt_size);
+
+		// if (status != EFI_SUCCESS && status != EFI_NOT_READY) {
+		// 	efi_err("Failed to load device tree!\n");
+		// 	goto fail;
+		// }
+	}
+
+	if (fdt_addr) {
+		efi_info("Using DTB from command line\n");
+	} else {
+		/* Look for a device tree configuration table entry. */
+		fdt_addr = (uintptr_t)get_fdt(&fdt_size);
+		if (fdt_addr)
+			efi_info("Using DTB from configuration table\n");
+	}
+
+	if (!fdt_addr)
+		efi_info("Generating empty DTB\n");
+
+	status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, ULONG_MAX);
+	if (status != EFI_SUCCESS) {
+		efi_err("Unable to allocate memory for new device tree.\n");
+		goto fail;
+	}
+	efi_debug("New FDT address: 0x%lx\n", *new_fdt_addr);
+	efi_info("Generating new FDT...\n");
+	status = update_fdt((void *)fdt_addr, fdt_size, (void *)*new_fdt_addr,
+			    MAX_FDT_SIZE, cmdline_ptr);
+
+	if (status != EFI_SUCCESS) {
+		efi_err("Unable to construct new device tree.\n");
+		goto fail_free_new_fdt;
+	}
+
+	priv.new_fdt_addr = (void *)*new_fdt_addr;
+
+	efi_info("Exiting boot services...\n");
+	efi_warn("CURRENTLY NOT EXITING BOOT SERVICES\n");
+	// status = efi_exit_boot_services(handle, &priv, exit_boot_func);
+	status = EFI_SUCCESS;
+
+	return status;
+
+	if (status == EFI_SUCCESS) {
+		efi_info("Boot services exited successfully.\n");
+		efi_set_virtual_address_map_t *svam;
+
+		if (efi_novamap)
+			return EFI_SUCCESS;
+
+		/* Install the new virtual address map */
+		svam = ST->RuntimeServices->SetVirtualAddressMap;
+		status = svam(priv.runtime_entry_count * desc_size, desc_size,
+			      desc_ver, priv.runtime_map);
+
+		/*
+			 * We are beyond the point of no return here, so if the call to
+			 * SetVirtualAddressMap() failed, we need to signal that to the
+			 * incoming kernel but proceed normally otherwise.
+			 */
+		if (status != EFI_SUCCESS) {
+			efi_memory_desc_t *p;
+			int l;
+
+			/*
+				 * Set the virtual address field of all
+				 * EFI_MEMORY_RUNTIME entries to U64_MAX. This will
+				 * signal the incoming kernel that no virtual
+				 * translation has been installed.
+				 */
+			for (l = 0; l < priv.boot_memmap->map_size;
+			     l += priv.boot_memmap->desc_size) {
+				p = (void *)priv.boot_memmap->map + l;
+
+				if (p->Attribute & EFI_MEMORY_RUNTIME)
+					p->VirtualStart = UINT64_MAX;
+			}
+		}
+		return EFI_SUCCESS;
+	}
+
+	efi_err("Exit boot services failed.\n");
+
+fail_free_new_fdt:
+	efi_free(MAX_FDT_SIZE, *new_fdt_addr);
+
+fail:
+	efi_free(fdt_size, fdt_addr);
+
+	efi_bs_call(FreePool, priv.runtime_map);
+
+	return EFI_LOAD_ERROR;
+}
+
+efi_status_t efi_boot_kernel(efi_handle_t handle,
+			     efi_loaded_image_t *loaded_image,
+			     struct payload_info *payload_info,
+			     char *cmdline_ptr)
+{
+	unsigned long fdt_addr;
+	efi_status_t status;
+
+	efi_info("Loading ELF payload...\n");
+	// 加载ELF
+	status = load_elf(payload_info);
+
+	if (status != EFI_SUCCESS) {
+		efi_err("Failed to load ELF payload, efi error code: %d\n",
+			status);
+		return status;
+	}
+
+	status = allocate_new_fdt_and_exit_boot(handle, loaded_image, &fdt_addr,
+						cmdline_ptr);
+	if (status != EFI_SUCCESS) {
+		efi_err("Failed to update FDT and exit boot services\n");
+		return status;
+	}
+#ifdef CONFIG_ARM
+	efi_handle_post_ebs_state();
+#endif
+	// efi_todo("efi_enter_kernel");
+	efi_info("Entering kernel...\n");
+	efi_enter_kernel(payload_info, fdt_addr,
+			 fdt_totalsize((void *)fdt_addr));
+	/* not reached */
+}
+
+void *get_fdt(unsigned long *fdt_size)
+{
+	void *fdt;
+
+	fdt = get_efi_config_table(DEVICE_TREE_GUID);
+
+	if (!fdt)
+		return NULL;
+
+	if (fdt_check_header(fdt) != 0) {
+		efi_err("Invalid header detected on UEFI supplied FDT, ignoring ...\n");
+		return NULL;
+	}
+	*fdt_size = fdt_totalsize(fdt);
+	return fdt;
+}

+ 78 - 1
apps/helper.c

@@ -7,7 +7,7 @@
 bool efi_nochunk;
 bool efi_nokaslr = true;
 // bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);
-bool efi_novamap;
+bool efi_novamap = false;
 
 static bool efi_noinitrd;
 static bool efi_nosoftreserve;
@@ -336,4 +336,81 @@ void *get_efi_config_table(efi_guid_t guid)
 		tables++;
 	}
 	return NULL;
+}
+
+/**
+ * efi_exit_boot_services() - Exit boot services
+ * @handle:	handle of the exiting image
+ * @priv:	argument to be passed to @priv_func
+ * @priv_func:	function to process the memory map before exiting boot services
+ *
+ * Handle calling ExitBootServices according to the requirements set out by the
+ * spec.  Obtains the current memory map, and returns that info after calling
+ * ExitBootServices.  The client must specify a function to perform any
+ * processing of the memory map data prior to ExitBootServices.  A client
+ * specific structure may be passed to the function via priv.  The client
+ * function may be called multiple times.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_exit_boot_services(void *handle, void *priv,
+				    efi_exit_boot_map_processing priv_func)
+{
+	struct efi_boot_memmap *map;
+	efi_status_t status;
+
+	if (efi_disable_pci_dma) {
+		efi_todo("efi_exit_boot_services:: efi_disable_pci_dma: efi_pci_disable_bridge_busmaster");
+		// efi_pci_disable_bridge_busmaster();
+	}
+
+	status = efi_get_memory_map(&map, true);
+	if (status != EFI_SUCCESS)
+		return status;
+	efi_debug("before priv_func\n");
+	status = priv_func(map, priv);
+	if (status != EFI_SUCCESS) {
+		
+		efi_bs_call(FreePool, map);
+		return status;
+	}
+
+	efi_debug("before ExitBootServices, handle=%p, map_key=%p\n", handle, map->map_key);
+
+	status = efi_bs_call(ExitBootServices, handle, map->map_key);
+
+	efi_debug("after ExitBootServices, status: %d\n", status);
+
+	if (status == EFI_INVALID_PARAMETER) {
+		/*
+		 * The memory map changed between efi_get_memory_map() and
+		 * exit_boot_services().  Per the UEFI Spec v2.6, Section 6.4:
+		 * EFI_BOOT_SERVICES.ExitBootServices we need to get the
+		 * updated map, and try again.  The spec implies one retry
+		 * should be sufficent, which is confirmed against the EDK2
+		 * implementation.  Per the spec, we can only invoke
+		 * get_memory_map() and exit_boot_services() - we cannot alloc
+		 * so efi_get_memory_map() cannot be used, and we must reuse
+		 * the buffer.  For all practical purposes, the headroom in the
+		 * buffer should account for any changes in the map so the call
+		 * to get_memory_map() is expected to succeed here.
+		 */
+		map->map_size = map->buff_size;
+		status = efi_bs_call(GetMemoryMap, &map->map_size, &map->map,
+				     &map->map_key, &map->desc_size,
+				     &map->desc_ver);
+
+		/* exit_boot_services() was called, thus cannot free */
+		if (status != EFI_SUCCESS)
+			return status;
+
+		status = priv_func(map, priv);
+		/* exit_boot_services() was called, thus cannot free */
+		if (status != EFI_SUCCESS)
+			return status;
+
+		status = efi_bs_call(ExitBootServices, handle, map->map_key);
+	}
+
+	return status;
 }

+ 22 - 0
apps/lib/string.c

@@ -163,4 +163,26 @@ char *strchr(const char *s, int c)
 {
 	char *r = __strchrnul(s, c);
 	return *(unsigned char *)r == (unsigned char)c ? r : 0;
+}
+
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2)
+{
+	size_t l1, l2;
+
+	l2 = strlen(s2);
+	if (!l2)
+		return (char *)s1;
+	l1 = strlen(s1);
+	while (l1 >= l2) {
+		l1--;
+		if (!memcmp(s1, s2, l2))
+			return (char *)s1;
+		s1++;
+	}
+	return NULL;
 }

+ 160 - 0
apps/mem.c

@@ -0,0 +1,160 @@
+#include <dragonstub/dragonstub.h>
+#include <dragonstub/linux/math.h>
+#include <dragonstub/linux/align.h>
+#include <dragonstub/minmax.h>
+
+/**
+ * efi_get_memory_map() - get memory map
+ * @map:		pointer to memory map pointer to which to assign the
+ *			newly allocated memory map
+ * @install_cfg_tbl:	whether or not to install the boot memory map as a
+ *			configuration table
+ *
+ * Retrieve the UEFI memory map. The allocated memory leaves room for
+ * up to EFI_MMAP_NR_SLACK_SLOTS additional memory map entries.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_get_memory_map(struct efi_boot_memmap **map,
+				bool install_cfg_tbl)
+{
+	int memtype = install_cfg_tbl ? EfiACPIReclaimMemory : EfiLoaderData;
+	efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
+	struct efi_boot_memmap *m, tmp;
+	efi_status_t status;
+	unsigned long size;
+
+	tmp.map_size = 0;
+	status = efi_bs_call(GetMemoryMap, &tmp.map_size, NULL, &tmp.map_key,
+			     &tmp.desc_size, &tmp.desc_ver);
+	if (status != EFI_BUFFER_TOO_SMALL)
+		return EFI_LOAD_ERROR;
+
+	size = tmp.map_size + tmp.desc_size * EFI_MMAP_NR_SLACK_SLOTS;
+	status = efi_bs_call(AllocatePool, memtype, sizeof(*m) + size,
+			     (void **)&m);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	if (install_cfg_tbl) {
+		/*
+		 * Installing a configuration table might allocate memory, and
+		 * this may modify the memory map. This means we should install
+		 * the configuration table first, and re-install or delete it
+		 * as needed.
+		 */
+		status = efi_bs_call(InstallConfigurationTable, &tbl_guid, m);
+		if (status != EFI_SUCCESS)
+			goto free_map;
+	}
+
+	m->buff_size = m->map_size = size;
+	status = efi_bs_call(GetMemoryMap, &m->map_size, m->map, &m->map_key,
+			     &m->desc_size, &m->desc_ver);
+	if (status != EFI_SUCCESS)
+		goto uninstall_table;
+
+	*map = m;
+	return EFI_SUCCESS;
+
+uninstall_table:
+	if (install_cfg_tbl)
+		efi_bs_call(InstallConfigurationTable, &tbl_guid, NULL);
+free_map:
+	efi_bs_call(FreePool, m);
+	return status;
+}
+
+/**
+ * efi_allocate_pages() - Allocate memory pages
+ * @size:	minimum number of bytes to allocate
+ * @addr:	On return the address of the first allocated page. The first
+ *		allocated page has alignment EFI_ALLOC_ALIGN which is an
+ *		architecture dependent multiple of the page size.
+ * @max:	the address that the last allocated memory page shall not
+ *		exceed
+ *
+ * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
+ * to EFI_ALLOC_ALIGN. The last allocated page will not exceed the address
+ * given by @max.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
+				unsigned long max)
+{
+	efi_physical_addr_t alloc_addr;
+	efi_status_t status;
+
+	max = min(max, EFI_ALLOC_LIMIT);
+
+	// if (EFI_ALLOC_ALIGN > EFI_PAGE_SIZE)
+	// 	return efi_allocate_pages_aligned(
+	// 		size, addr, max, EFI_ALLOC_ALIGN, EfiLoaderData);
+
+	alloc_addr = ALIGN_DOWN(max + 1, EFI_ALLOC_ALIGN) - 1;
+	status = efi_bs_call(AllocatePages, EFI_ALLOCATE_MAX_ADDRESS,
+			     EfiLoaderData, DIV_ROUND_UP(size, EFI_PAGE_SIZE),
+			     &alloc_addr);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	*addr = alloc_addr;
+	return EFI_SUCCESS;
+}
+
+/**
+ * efi_allocate_pages_exact() - Allocate memory pages at a specific address
+ * @size:	minimum number of bytes to allocate
+ * @addr:	The address of the first allocated page.
+ *
+ * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
+ * to EFI_ALLOC_ALIGN.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_allocate_pages_exact(unsigned long size, unsigned long addr)
+{
+	efi_status_t status;
+
+	u64 addr_rounded = addr & ~(EFI_ALLOC_ALIGN - 1);
+	size += addr - addr_rounded;
+
+	u32 pagecount = DIV_ROUND_UP(size, EFI_PAGE_SIZE);
+	efi_debug(
+		"efi_allocate_pages_exact: size=%d, addr=%p, addr_rounded=%p, pagecount=%d\n",
+		size, addr, addr_rounded, pagecount);
+
+	status = efi_bs_call(AllocatePages, AllocateAddress, EfiLoaderData,
+			     pagecount, (EFI_PHYSICAL_ADDRESS *)&addr);
+
+	// status = efi_bs_call(AllocatePages, AllocateAddress, EfiLoaderData,
+	// 		     DIV_ROUND_UP(size, EFI_PAGE_SIZE),
+	// 		     (EFI_PHYSICAL_ADDRESS *)&addr);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	return EFI_SUCCESS;
+}
+
+/**
+ * efi_free() - free memory pages
+ * @size:	size of the memory area to free in bytes
+ * @addr:	start of the memory area to free (must be EFI_PAGE_SIZE
+ *		aligned)
+ *
+ * @size is rounded up to a multiple of EFI_ALLOC_ALIGN which is an
+ * architecture specific multiple of EFI_PAGE_SIZE. So this function should
+ * only be used to return pages allocated with efi_allocate_pages() or
+ * efi_low_alloc_above().
+ */
+void efi_free(unsigned long size, unsigned long addr)
+{
+	unsigned long nr_pages;
+
+	if (!size)
+		return;
+
+	nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
+	efi_bs_call(FreePages, addr, nr_pages);
+}

+ 43 - 0
apps/random.c

@@ -0,0 +1,43 @@
+#include <dragonstub/dragonstub.h>
+
+
+typedef union efi_rng_protocol efi_rng_protocol_t;
+
+union efi_rng_protocol {
+	struct {
+		efi_status_t (__efiapi *get_info)(efi_rng_protocol_t *,
+						  unsigned long *,
+						  efi_guid_t *);
+		efi_status_t (__efiapi *get_rng)(efi_rng_protocol_t *,
+						 efi_guid_t *, unsigned long,
+						 u8 *out);
+	};
+	struct {
+		u32 get_info;
+		u32 get_rng;
+	} mixed_mode;
+};
+
+/**
+ * efi_get_random_bytes() - fill a buffer with random bytes
+ * @size:	size of the buffer
+ * @out:	caller allocated buffer to receive the random bytes
+ *
+ * The call will fail if either the firmware does not implement the
+ * EFI_RNG_PROTOCOL or there are not enough random bytes available to fill
+ * the buffer.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)
+{
+	efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
+	efi_status_t status;
+	efi_rng_protocol_t *rng = NULL;
+
+	status = efi_bs_call(LocateProtocol, &rng_proto, NULL, (void **)&rng);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	return efi_call_proto(rng, get_rng, NULL, size, out);
+}

+ 20 - 1
apps/riscv-stub.c

@@ -2,17 +2,20 @@
 #include <dragonstub/linux/unaligned.h>
 #include "efilib.h"
 #include <libfdt.h>
+#include <asm/csr.h>
 
 /// @brief 当前的hartid
 static unsigned long hartid;
 
+typedef void __noreturn (*jump_kernel_func)(unsigned long, unsigned long);
+
 static efi_status_t get_boot_hartid_from_fdt(void)
 {
 	const void *fdt;
 	int chosen_node, len;
 	const void *prop;
 
-    // efi_guid_t device_tree_guid = *(efi_guid_t *)&tmp;
+	// efi_guid_t device_tree_guid = *(efi_guid_t *)&tmp;
 	fdt = get_efi_config_table(DEVICE_TREE_GUID);
 	if (!fdt) {
 		efi_err("Failed to get FDT from EFI config table\n");
@@ -75,4 +78,20 @@ efi_status_t check_platform_features(void)
 
 	efi_info("Boot hartid: %ld\n", hartid);
 	return EFI_SUCCESS;
+}
+
+void __noreturn efi_enter_kernel(struct payload_info *payload_info,
+				 unsigned long fdt, unsigned long fdt_size)
+{
+	unsigned long kernel_entry = payload_info->kernel_entry;
+	jump_kernel_func jump_kernel = (jump_kernel_func)kernel_entry;
+
+	/*
+	 * Jump to real kernel here with following constraints.
+	 * 1. MMU should be disabled.
+	 * 2. a0 should contain hartid
+	 * 3. a1 should DT address
+	 */
+	csr_write(CSR_SATP, 0);
+	jump_kernel(hartid, fdt);
 }

+ 71 - 0
apps/secureboot.c

@@ -0,0 +1,71 @@
+#include <dragonstub/dragonstub.h>
+
+/* SHIM variables */
+static const efi_guid_t shim_guid = EFI_SHIM_LOCK_GUID;
+static const efi_char16_t shim_MokSBState_name[] = L"MokSBStateRT";
+
+static efi_status_t get_var(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+			    unsigned long *data_size, void *data)
+{
+	return get_efi_var(name, vendor, attr, data_size, data);
+}
+
+/*
+ * Determine whether we're in secure boot mode.
+ */
+enum efi_secureboot_mode efi_get_secureboot(void)
+{
+	u32 attr;
+	unsigned long size;
+	enum efi_secureboot_mode mode;
+	efi_status_t status;
+	u8 moksbstate;
+
+	mode = efi_get_secureboot_mode(get_var);
+	if (mode == efi_secureboot_mode_unknown) {
+		efi_err("Could not determine UEFI Secure Boot status.\n");
+		return efi_secureboot_mode_unknown;
+	}
+	if (mode != efi_secureboot_mode_enabled)
+		return mode;
+
+	/*
+	 * See if a user has put the shim into insecure mode. If so, and if the
+	 * variable doesn't have the non-volatile attribute set, we might as
+	 * well honor that.
+	 */
+	size = sizeof(moksbstate);
+	status = get_efi_var(shim_MokSBState_name, &shim_guid, &attr, &size,
+			     &moksbstate);
+
+	/* If it fails, we don't care why. Default to secure */
+	if (status != EFI_SUCCESS)
+		goto secure_boot_enabled;
+	if (!(attr & EFI_VARIABLE_NON_VOLATILE) && moksbstate == 1)
+		return efi_secureboot_mode_disabled;
+
+secure_boot_enabled:
+	efi_info("UEFI Secure Boot is enabled.\n");
+	return efi_secureboot_mode_enabled;
+}
+
+/// @brief 打印efi_secureboot_mode
+void print_efi_secureboot_mode(enum efi_secureboot_mode mode)
+{
+	switch (mode) {
+	case efi_secureboot_mode_unknown:
+		efi_info("efi_secureboot_mode: efi_secureboot_mode_unknown\n");
+		break;
+	case efi_secureboot_mode_disabled:
+		efi_info("efi_secureboot_mode: efi_secureboot_mode_disabled\n");
+		break;
+	case efi_secureboot_mode_enabled:
+		efi_info("efi_secureboot_mode: efi_secureboot_mode_enabled\n");
+		break;
+	case efi_secureboot_mode_unset:
+		efi_info("efi_secureboot_mode: efi_secureboot_mode_unset\n");
+		break;
+	default:
+		break;
+	}
+}

+ 184 - 21
apps/stub.c

@@ -1,7 +1,42 @@
+#include "dragonstub/printk.h"
+#include "efidef.h"
 #include <efi.h>
 #include <efilib.h>
 #include <elf.h>
 #include <dragonstub/dragonstub.h>
+#include <dragonstub/elfloader.h>
+#include <dragonstub/linux/math.h>
+#include <dragonstub/linux/align.h>
+
+/*
+ * This is the base address at which to start allocating virtual memory ranges
+ * for UEFI Runtime Services.
+ *
+ * For ARM/ARM64:
+ * This is in the low TTBR0 range so that we can use
+ * any allocation we choose, and eliminate the risk of a conflict after kexec.
+ * The value chosen is the largest non-zero power of 2 suitable for this purpose
+ * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
+ * be mapped efficiently.
+ * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split,
+ * map everything below 1 GB. (512 MB is a reasonable upper bound for the
+ * entire footprint of the UEFI runtime services memory regions)
+ *
+ * For RISC-V:
+ * There is no specific reason for which, this address (512MB) can't be used
+ * EFI runtime virtual address for RISC-V. It also helps to use EFI runtime
+ * services on both RV32/RV64. Keep the same runtime virtual address for RISC-V
+ * as well to minimize the code churn.
+ */
+#define EFI_RT_VIRTUAL_BASE SZ_512M
+
+/*
+ * Some architectures map the EFI regions into the kernel's linear map using a
+ * fixed offset.
+ */
+#ifndef EFI_RT_VIRTUAL_OFFSET
+#define EFI_RT_VIRTUAL_OFFSET 0
+#endif
 
 extern void _image_end(void);
 
@@ -9,6 +44,9 @@ static u64 image_base = 0;
 static u64 image_size = 0;
 static u64 image_end = 0;
 
+static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
+static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);
+
 EFI_STATUS efi_handle_cmdline(EFI_LOADED_IMAGE *image, char **cmdline_ptr)
 {
 	int cmdline_size = 0;
@@ -68,7 +106,10 @@ static efi_status_t init_efi_program_info(efi_loaded_image_t *loaded_image)
 static struct payload_info payload_info_new(u64 payload_addr, u64 payload_size)
 {
 	struct payload_info info = { .payload_addr = payload_addr,
-				     .payload_size = payload_size };
+				     .payload_size = payload_size,
+				     .loaded_paddr = 0,
+				     .loaded_size = 0,
+				     .kernel_entry = 0 };
 	return info;
 }
 static efi_status_t find_elf(struct payload_info *info)
@@ -90,21 +131,13 @@ static efi_status_t find_elf(struct payload_info *info)
 		return EFI_NOT_FOUND;
 	}
 
-	efi_debug("Checking payload's ELF header...\n");
-	bool found = true;
-	for (int i = 0; i < 4; i++) {
-		u8 c = *(u8 *)(payload_start + i);
-		if (c != ELFMAG[i]) {
-			// 不是ELF magic number,跳过
-			found = false;
-			break;
-		}
-	}
+	efi_info("Checking payload's ELF header...\n");
+	bool found = elf_check((void *)payload_start, payload_size);
 
-	// 如果找到了ELF magic number,就认为找到了ELF header,稍后再验证
 	if (found) {
 		info->payload_addr = payload_start;
 		info->payload_size = payload_size;
+		efi_info("Found payload ELF header\n");
 		return EFI_SUCCESS;
 	}
 
@@ -135,13 +168,141 @@ efi_status_t find_payload(efi_handle_t handle, efi_loaded_image_t *loaded_image,
 		return status;
 	}
 
-    *ret_info = info;
-    return EFI_SUCCESS;
+	*ret_info = info;
+	return EFI_SUCCESS;
+}
+
+/*
+ * efi_allocate_virtmap() - create a pool allocation for the virtmap
+ *
+ * Create an allocation that is of sufficient size to hold all the memory
+ * descriptors that will be passed to SetVirtualAddressMap() to inform the
+ * firmware about the virtual mapping that will be used under the OS to call
+ * into the firmware.
+ */
+efi_status_t efi_alloc_virtmap(efi_memory_desc_t **virtmap,
+			       unsigned long *desc_size, u32 *desc_ver)
+{
+	unsigned long size, mmap_key;
+	efi_status_t status;
+
+	/*
+	 * Use the size of the current memory map as an upper bound for the
+	 * size of the buffer we need to pass to SetVirtualAddressMap() to
+	 * cover all EFI_MEMORY_RUNTIME regions.
+	 */
+	size = 0;
+	status = efi_bs_call(GetMemoryMap, &size, NULL, &mmap_key, desc_size,
+			     desc_ver);
+	if (status != EFI_BUFFER_TOO_SMALL)
+		return EFI_LOAD_ERROR;
+
+	return efi_bs_call(AllocatePool, EfiLoaderData, size, (void **)virtmap);
+}
+
+/*
+ * efi_get_virtmap() - create a virtual mapping for the EFI memory map
+ *
+ * This function populates the virt_addr fields of all memory region descriptors
+ * in @memory_map whose EFI_MEMORY_RUNTIME attribute is set. Those descriptors
+ * are also copied to @runtime_map, and their total count is returned in @count.
+ */
+void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
+		     unsigned long desc_size, efi_memory_desc_t *runtime_map,
+		     int *count)
+{
+	u64 efi_virt_base = virtmap_base;
+	efi_memory_desc_t *in, *out = runtime_map;
+	int l;
+
+	*count = 0;
+
+	for (l = 0; l < map_size; l += desc_size) {
+		u64 paddr, size;
+
+		in = (void *)memory_map + l;
+		if (!(in->Attribute & EFI_MEMORY_RUNTIME))
+			continue;
+
+		paddr = in->PhysicalStart;
+		size = in->NumberOfPages * EFI_PAGE_SIZE;
+
+		in->VirtualStart = in->PhysicalStart + EFI_RT_VIRTUAL_OFFSET;
+		if (efi_novamap) {
+			continue;
+		}
+
+		/*
+		 * Make the mapping compatible with 64k pages: this allows
+		 * a 4k page size kernel to kexec a 64k page size kernel and
+		 * vice versa.
+		 */
+		if (!flat_va_mapping) {
+			paddr = round_down(in->PhysicalStart, SZ_64K);
+			size += in->PhysicalStart - paddr;
+
+			/*
+			 * Avoid wasting memory on PTEs by choosing a virtual
+			 * base that is compatible with section mappings if this
+			 * region has the appropriate size and physical
+			 * alignment. (Sections are 2 MB on 4k granule kernels)
+			 */
+			if (IS_ALIGNED(in->PhysicalStart, SZ_2M) &&
+			    size >= SZ_2M)
+				efi_virt_base = round_up(efi_virt_base, SZ_2M);
+			else
+				efi_virt_base = round_up(efi_virt_base, SZ_64K);
+
+			in->VirtualStart += efi_virt_base - paddr;
+			efi_virt_base += size;
+		}
+
+		memcpy(out, in, desc_size);
+		out = (void *)out + desc_size;
+		++*count;
+	}
+}
+
+/// @brief 设置内存保留表
+/// @param
+static void install_memreserve_table(void)
+{
+	struct linux_efi_memreserve *rsv;
+	efi_guid_t memreserve_table_guid = LINUX_EFI_MEMRESERVE_TABLE_GUID;
+	efi_status_t status;
+
+	status = efi_bs_call(AllocatePool, EfiLoaderData, sizeof(*rsv),
+			     (void **)&rsv);
+	if (status != EFI_SUCCESS) {
+		efi_err("Failed to allocate memreserve entry!\n");
+		return;
+	}
+
+	rsv->next = 0;
+	rsv->size = 0;
+	rsv->count = 0;
+
+	status = efi_bs_call(InstallConfigurationTable, &memreserve_table_guid,
+			     rsv);
+	if (status != EFI_SUCCESS)
+		efi_err("Failed to install memreserve config table!\n");
 }
 
+static u32 get_supported_rt_services(void)
+{
+	const efi_rt_properties_table_t *rt_prop_table;
+	u32 supported = EFI_RT_SUPPORTED_ALL;
+
+	rt_prop_table = get_efi_config_table(EFI_RT_PROPERTIES_TABLE_GUID);
+	if (rt_prop_table)
+		supported &= rt_prop_table->runtime_services_supported;
+
+	return supported;
+}
 
 efi_status_t efi_stub_common(efi_handle_t handle,
-			     struct payload_info* payload_info,
+			     efi_loaded_image_t *loaded_image,
+			     struct payload_info *payload_info,
 			     char *cmdline_ptr)
 {
 	struct screen_info *si;
@@ -163,13 +324,15 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 
 	// efi_random_get_seed();
 
-	// /* force efi_novamap if SetVirtualAddressMap() is unsupported */
-	// efi_novamap |= !(get_supported_rt_services() &
-	// 		 EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP);
-
-	// install_memreserve_table();
+	/* force efi_novamap if SetVirtualAddressMap() is unsupported */
+	efi_novamap |= !(get_supported_rt_services() &
+			 EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP);
 
-	// status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
+	install_memreserve_table();
+	efi_info("Memreserve table installed\n");
+	efi_info("Booting DragonOS kernel...\n");
+	status = efi_boot_kernel(handle, loaded_image, payload_info,
+				 cmdline_ptr);
 
 	// free_screen_info(si);
 	return status;

+ 237 - 12
inc/dragonstub/dragonstub.h

@@ -8,9 +8,11 @@
 #include "linux/ctype.h"
 #include <lib.h>
 #include <dragonstub/linux/hex.h>
+#include <dragonstub/minmax.h>
 #include "types.h"
 #include "linux/div64.h"
 #include "limits.h"
+#include "linux/sizes.h"
 
 /// @brief
 /// @param image
@@ -128,16 +130,16 @@ typedef EFI_LOADED_IMAGE efi_loaded_image_t;
 		efi_fn_call(__inst, func, __inst, ##__VA_ARGS__); \
 	})
 
-/*
- * This function handles the architcture specific differences between arm and
- * arm64 regarding where the kernel image must be loaded and any memory that
- * must be reserved. On failure it is required to free all
- * all allocations it has made.
- */
-efi_status_t
-handle_kernel_image(unsigned long *image_addr, unsigned long *image_size,
-		    unsigned long *reserve_addr, unsigned long *reserve_size,
-		    efi_loaded_image_t *image, efi_handle_t image_handle);
+#define efi_rt_call(func, ...) \
+	efi_fn_call(efi_table_attr(ST, RuntimeServices), func, ##__VA_ARGS__)
+
+#define get_efi_var(name, vendor, ...)                   \
+	efi_rt_call(GetVariable, (efi_char16_t *)(name), \
+		    (efi_guid_t *)(vendor), __VA_ARGS__)
+
+#define set_efi_var(name, vendor, ...)                   \
+	efi_rt_call(SetVariable, (efi_char16_t *)(name), \
+		    (efi_guid_t *)(vendor), __VA_ARGS__)
 
 char *skip_spaces(const char *str);
 long simple_strtol(const char *cp, char **endp, unsigned int base);
@@ -163,6 +165,13 @@ size_t strlen(const char *s);
 int strncmp(const char *cs, const char *ct, size_t count);
 int strcmp(const char *str1, const char *str2);
 char *strchr(const char *s, int c);
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2);
+
 char *next_arg(char *args, char **param, char **val);
 
 /**
@@ -183,6 +192,12 @@ struct payload_info {
 	u64 payload_addr;
 	/// @brief 负载大小
 	u64 payload_size;
+	/// @brief 被加载到的物理地址
+	u64 loaded_paddr;
+	/// @brief 加载了多大
+	u64 loaded_size;
+	/// @brief 加载的内核的入口物理地址
+	u64 kernel_entry;
 };
 
 /// @brief 寻找要加载的内核负载
@@ -194,7 +209,11 @@ efi_status_t find_payload(efi_handle_t handle, efi_loaded_image_t *loaded_image,
 			  struct payload_info *ret_info);
 
 /* shared entrypoint between the normal stub and the zboot stub */
-efi_status_t efi_stub_common(efi_handle_t handle,
+efi_status_t efi_stub_common(efi_handle_t handle, efi_loaded_image_t *image,
+			     struct payload_info *payload_info,
+			     char *cmdline_ptr);
+
+efi_status_t efi_boot_kernel(efi_handle_t handle, efi_loaded_image_t *image,
 			     struct payload_info *payload_info,
 			     char *cmdline_ptr);
 
@@ -217,4 +236,210 @@ static inline void print_efi_guid(efi_guid_t *guid)
 {
 	efi_info("GUID: data1: %p data2: %p data3: %p data4: %p\n", guid->Data1,
 		 guid->Data2, guid->Data3, guid->Data4);
-}
+}
+
+/*
+ * efi_allocate_virtmap() - create a pool allocation for the virtmap
+ *
+ * Create an allocation that is of sufficient size to hold all the memory
+ * descriptors that will be passed to SetVirtualAddressMap() to inform the
+ * firmware about the virtual mapping that will be used under the OS to call
+ * into the firmware.
+ */
+efi_status_t efi_alloc_virtmap(efi_memory_desc_t **virtmap,
+			       unsigned long *desc_size, u32 *desc_ver);
+
+/*
+ * efi_get_virtmap() - create a virtual mapping for the EFI memory map
+ *
+ * This function populates the virt_addr fields of all memory region descriptors
+ * in @memory_map whose EFI_MEMORY_RUNTIME attribute is set. Those descriptors
+ * are also copied to @runtime_map, and their total count is returned in @count.
+ */
+void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
+		     unsigned long desc_size, efi_memory_desc_t *runtime_map,
+		     int *count);
+
+extern bool efi_nochunk;
+extern bool efi_nokaslr;
+extern bool efi_novamap;
+
+/*
+ * Determine whether we're in secure boot mode.
+ */
+enum efi_secureboot_mode efi_get_secureboot(void);
+void *get_fdt(unsigned long *fdt_size);
+
+/*
+ * Allow the platform to override the allocation granularity: this allows
+ * systems that have the capability to run with a larger page size to deal
+ * with the allocations for initrd and fdt more efficiently.
+ */
+#ifndef EFI_ALLOC_ALIGN
+#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
+#endif
+
+#ifndef EFI_ALLOC_LIMIT
+#define EFI_ALLOC_LIMIT ULONG_MAX
+#endif
+
+/*
+ * Allocation types for calls to boottime->allocate_pages.
+ */
+#define EFI_ALLOCATE_ANY_PAGES 0
+#define EFI_ALLOCATE_MAX_ADDRESS 1
+#define EFI_ALLOCATE_ADDRESS 2
+#define EFI_MAX_ALLOCATE_TYPE 3
+
+/**
+ * efi_allocate_pages_aligned() - Allocate memory pages
+ * @size:	minimum number of bytes to allocate
+ * @addr:	On return the address of the first allocated page. The first
+ *		allocated page has alignment EFI_ALLOC_ALIGN which is an
+ *		architecture dependent multiple of the page size.
+ * @max:	the address that the last allocated memory page shall not
+ *		exceed
+ * @align:	minimum alignment of the base of the allocation
+ *
+ * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
+ * to @align, which should be >= EFI_ALLOC_ALIGN. The last allocated page will
+ * not exceed the address given by @max.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
+					unsigned long max, unsigned long align,
+					int memory_type);
+
+/**
+ * efi_allocate_pages() - Allocate memory pages
+ * @size:	minimum number of bytes to allocate
+ * @addr:	On return the address of the first allocated page. The first
+ *		allocated page has alignment EFI_ALLOC_ALIGN which is an
+ *		architecture dependent multiple of the page size.
+ * @max:	the address that the last allocated memory page shall not
+ *		exceed
+ *
+ * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
+ * to EFI_ALLOC_ALIGN. The last allocated page will not exceed the address
+ * given by @max.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
+				unsigned long max);
+
+/**
+ * efi_allocate_pages_exact() - Allocate memory pages at a specific address
+ * @size:	minimum number of bytes to allocate
+ * @addr:	The address of the first allocated page.
+ *
+ * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
+ * to EFI_ALLOC_ALIGN.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_allocate_pages_exact(unsigned long size, unsigned long addr);
+
+/**
+ * efi_free() - free memory pages
+ * @size:	size of the memory area to free in bytes
+ * @addr:	start of the memory area to free (must be EFI_PAGE_SIZE
+ *		aligned)
+ *
+ * @size is rounded up to a multiple of EFI_ALLOC_ALIGN which is an
+ * architecture specific multiple of EFI_PAGE_SIZE. So this function should
+ * only be used to return pages allocated with efi_allocate_pages() or
+ * efi_low_alloc_above().
+ */
+void efi_free(unsigned long size, unsigned long addr);
+
+/*
+ * An efi_boot_memmap is used by efi_get_memory_map() to return the
+ * EFI memory map in a dynamically allocated buffer.
+ *
+ * The buffer allocated for the EFI memory map includes extra room for
+ * a minimum of EFI_MMAP_NR_SLACK_SLOTS additional EFI memory descriptors.
+ * This facilitates the reuse of the EFI memory map buffer when a second
+ * call to ExitBootServices() is needed because of intervening changes to
+ * the EFI memory map. Other related structures, e.g. x86 e820ext, need
+ * to factor in this headroom requirement as well.
+ */
+#define EFI_MMAP_NR_SLACK_SLOTS 8
+
+/**
+ * efi_get_memory_map() - get memory map
+ * @map:		pointer to memory map pointer to which to assign the
+ *			newly allocated memory map
+ * @install_cfg_tbl:	whether or not to install the boot memory map as a
+ *			configuration table
+ *
+ * Retrieve the UEFI memory map. The allocated memory leaves room for
+ * up to EFI_MMAP_NR_SLACK_SLOTS additional memory map entries.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_get_memory_map(struct efi_boot_memmap **map,
+				bool install_cfg_tbl);
+
+#ifdef CONFIG_64BIT
+#define MAX_FDT_SIZE (1UL << 21)
+#else
+#error "MAX_FDT_SIZE not yet defined for 32-bit"
+#endif
+
+/* Helper macros for the usual case of using simple C variables: */
+#ifndef fdt_setprop_inplace_var
+#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
+	fdt_setprop_inplace((fdt), (node_offset), (name), &(var), sizeof(var))
+#endif
+
+#ifndef fdt_setprop_var
+#define fdt_setprop_var(fdt, node_offset, name, var) \
+	fdt_setprop((fdt), (node_offset), (name), &(var), sizeof(var))
+#endif
+
+#define efi_get_handle_at(array, idx)     \
+	(efi_is_native() ? (array)[idx] : \
+			   (efi_handle_t)(unsigned long)((u32 *)(array))[idx])
+
+#define efi_get_handle_num(size) \
+	((size) / (efi_is_native() ? sizeof(efi_handle_t) : sizeof(u32)))
+
+/**
+ * efi_get_random_bytes() - fill a buffer with random bytes
+ * @size:	size of the buffer
+ * @out:	caller allocated buffer to receive the random bytes
+ *
+ * The call will fail if either the firmware does not implement the
+ * EFI_RNG_PROTOCOL or there are not enough random bytes available to fill
+ * the buffer.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_get_random_bytes(unsigned long size, u8 *out);
+
+typedef efi_status_t (*efi_exit_boot_map_processing)(
+	struct efi_boot_memmap *map, void *priv);
+
+/**
+ * efi_exit_boot_services() - Exit boot services
+ * @handle:	handle of the exiting image
+ * @priv:	argument to be passed to @priv_func
+ * @priv_func:	function to process the memory map before exiting boot services
+ *
+ * Handle calling ExitBootServices according to the requirements set out by the
+ * spec.  Obtains the current memory map, and returns that info after calling
+ * ExitBootServices.  The client must specify a function to perform any
+ * processing of the memory map data prior to ExitBootServices.  A client
+ * specific structure may be passed to the function via priv.  The client
+ * function may be called multiple times.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_exit_boot_services(void *handle, void *priv,
+				    efi_exit_boot_map_processing priv_func);
+
+void __noreturn efi_enter_kernel(struct payload_info *payload_info,
+				 unsigned long fdt, unsigned long fdt_size);
+

+ 18 - 0
inc/dragonstub/elfloader.h

@@ -0,0 +1,18 @@
+#pragma once
+
+#include <elf.h>
+#include "types.h"
+
+struct payload_info;
+
+bool elf_check(const void *payload_start, u64 payload_size);
+
+/// @brief 获取ELF文件头
+/// @param payload_start 文件起始地址
+/// @param payload_size 文件大小
+/// @param ehdr 返回的ELF文件头
+/// @return
+efi_status_t elf_get_header(const void *payload_start, u64 payload_size,
+			    Elf64_Ehdr **ehdr);
+
+efi_status_t load_elf(struct payload_info *payload_info);

+ 180 - 0
inc/dragonstub/linux-efi.h

@@ -2,6 +2,8 @@
 #include <efidef.h>
 #include "compiler_attributes.h"
 #include "types.h"
+#include <efiapi.h>
+#include <efierr.h>
 #include "linux/pfn.h"
 #if defined(CONFIG_riscv64)
 #include "riscv64.h"
@@ -11,6 +13,10 @@
 #define efi_guid_t EFI_GUID
 #define efi_runtime_services_t EFI_RUNTIME_SERVICES
 #define efi_boot_services_t EFI_BOOT_SERVICES
+#define efi_memory_desc_t EFI_MEMORY_DESCRIPTOR
+#define efi_capsule_header_t EFI_CAPSULE_HEADER
+#define efi_time_t EFI_TIME
+#define efi_time_cap_t EFI_TIME_CAPABILITIES
 
 #define MAKE_EFI_GUID(a, b, c, d...)       \
 	(efi_guid_t)                       \
@@ -204,6 +210,47 @@
 	MAKE_EFI_GUID(0x067b1f5f, 0xcf26, 0x44c5, 0x85, 0x54, 0x93, 0xd7, \
 		      0x77, 0x91, 0x2d, 0x42)
 
+/*
+ * This GUID is used to pass to the kernel proper the struct screen_info
+ * structure that was populated by the stub based on the GOP protocol instance
+ * associated with ConOut
+ */
+#define LINUX_EFI_SCREEN_INFO_TABLE_GUID                                  \
+	MAKE_EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, \
+		      0x02, 0x37, 0x1d, 0x95)
+#define LINUX_EFI_ARM_CPU_STATE_TABLE_GUID                                \
+	MAKE_EFI_GUID(0xef79e4aa, 0x3c3d, 0x4989, 0xb9, 0x02, 0x07, 0xa9, \
+		      0x43, 0xe5, 0x50, 0xd2)
+#define LINUX_EFI_LOADER_ENTRY_GUID                                       \
+	MAKE_EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, \
+		      0x29, 0xbb, 0x8c, 0x4f)
+#define LINUX_EFI_RANDOM_SEED_TABLE_GUID                                  \
+	MAKE_EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, \
+		      0xf1, 0x80, 0xf5, 0x7b)
+#define LINUX_EFI_TPM_EVENT_LOG_GUID                                      \
+	MAKE_EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, \
+		      0x07, 0xb7, 0x47, 0xfa)
+#define LINUX_EFI_TPM_FINAL_LOG_GUID                                      \
+	MAKE_EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, \
+		      0xbe, 0xf8, 0x23, 0x25)
+#define LINUX_EFI_MEMRESERVE_TABLE_GUID                                   \
+	MAKE_EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, \
+		      0x5c, 0xb9, 0x77, 0xc2)
+#define LINUX_EFI_INITRD_MEDIA_GUID                                       \
+	MAKE_EFI_GUID(0x5568e427, 0x68fc, 0x4f3d, 0xac, 0x74, 0xca, 0x55, \
+		      0x52, 0x31, 0xcc, 0x68)
+#define LINUX_EFI_MOK_VARIABLE_TABLE_GUID                                 \
+	MAKE_EFI_GUID(0xc451ed2b, 0x9694, 0x45d3, 0xba, 0xba, 0xed, 0x9f, \
+		      0x89, 0x88, 0xa3, 0x89)
+#define LINUX_EFI_COCO_SECRET_AREA_GUID                                   \
+	MAKE_EFI_GUID(0xadf956ad, 0xe98c, 0x484c, 0xae, 0x11, 0xb5, 0x1c, \
+		      0x7d, 0x33, 0x64, 0x47)
+#define LINUX_EFI_BOOT_MEMMAP_GUID                                        \
+	MAKE_EFI_GUID(0x800f683f, 0xd08b, 0x423a, 0xa2, 0x93, 0x96, 0x5c, \
+		      0x3c, 0x6f, 0xe2, 0xb4)
+#define LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID                               \
+	MAKE_EFI_GUID(0xd5d1de3c, 0x105c, 0x44f9, 0x9e, 0xa9, 0xbc, 0xef, \
+		      0x98, 0x12, 0x00, 0x31)
 #define RISCV_EFI_BOOT_PROTOCOL_GUID                                      \
 	MAKE_EFI_GUID(0xccd15fec, 0x6f73, 0x4eec, 0x83, 0x95, 0x3e, 0x69, \
 		      0xe4, 0xb9, 0x40, 0xbf)
@@ -320,3 +367,136 @@ static inline void memrange_efi_to_native(u64 *addr, u64 *npages)
 	*npages = PFN_UP(*addr + (*npages << EFI_PAGE_SHIFT)) - PFN_DOWN(*addr);
 	*addr &= PAGE_MASK;
 }
+
+struct linux_efi_memreserve {
+	int size; // allocated size of the array
+	int count; // number of entries used
+	phys_addr_t next; // pa of next struct instance
+	struct {
+		phys_addr_t base;
+		phys_addr_t size;
+	} entry[];
+};
+
+#define EFI_MEMRESERVE_COUNT(size)                        \
+	(((size) - sizeof(struct linux_efi_memreserve)) / \
+	 sizeof_field(struct linux_efi_memreserve, entry[0]))
+
+enum efi_secureboot_mode {
+	efi_secureboot_mode_unset,
+	efi_secureboot_mode_unknown,
+	efi_secureboot_mode_disabled,
+	efi_secureboot_mode_enabled,
+};
+
+/// @brief 打印efi_secureboot_mode
+void print_efi_secureboot_mode(enum efi_secureboot_mode mode);
+
+typedef efi_status_t efi_get_time_t(efi_time_t *tm, efi_time_cap_t *tc);
+typedef efi_status_t efi_set_time_t(efi_time_t *tm);
+typedef efi_status_t efi_get_wakeup_time_t(efi_bool_t *enabled,
+					   efi_bool_t *pending, efi_time_t *tm);
+typedef efi_status_t efi_set_wakeup_time_t(efi_bool_t enabled, efi_time_t *tm);
+typedef efi_status_t efi_get_variable_t(efi_char16_t *name, efi_guid_t *vendor,
+					u32 *attr, unsigned long *data_size,
+					void *data);
+typedef efi_status_t efi_get_next_variable_t(unsigned long *name_size,
+					     efi_char16_t *name,
+					     efi_guid_t *vendor);
+typedef efi_status_t efi_set_variable_t(efi_char16_t *name, efi_guid_t *vendor,
+					u32 attr, unsigned long data_size,
+					void *data);
+typedef efi_status_t efi_get_next_high_mono_count_t(u32 *count);
+typedef void efi_reset_system_t(int reset_type, efi_status_t status,
+				unsigned long data_size, efi_char16_t *data);
+typedef efi_status_t efi_set_virtual_address_map_t(
+	unsigned long memory_map_size, unsigned long descriptor_size,
+	u32 descriptor_version, efi_memory_desc_t *virtual_map);
+typedef efi_status_t efi_query_variable_info_t(u32 attr, u64 *storage_space,
+					       u64 *remaining_space,
+					       u64 *max_variable_size);
+typedef efi_status_t efi_update_capsule_t(efi_capsule_header_t **capsules,
+					  unsigned long count,
+					  unsigned long sg_list);
+typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
+					      unsigned long count,
+					      u64 *max_size, int *reset_type);
+typedef efi_status_t efi_query_variable_store_t(u32 attributes,
+						unsigned long size,
+						bool nonblocking);
+
+static inline enum efi_secureboot_mode
+efi_get_secureboot_mode(efi_get_variable_t *get_var)
+{
+	u8 secboot, setupmode = 0;
+	efi_status_t status;
+	unsigned long size;
+
+	size = sizeof(secboot);
+	status = get_var(L"SecureBoot", &EFI_GLOBAL_VARIABLE_GUID, NULL, &size,
+			 &secboot);
+	if (status == EFI_NOT_FOUND)
+		return efi_secureboot_mode_disabled;
+	if (status != EFI_SUCCESS)
+		return efi_secureboot_mode_unknown;
+
+	size = sizeof(setupmode);
+	get_var(L"SetupMode", &EFI_GLOBAL_VARIABLE_GUID, NULL, &size,
+		&setupmode);
+	if (secboot == 0 || setupmode == 1)
+		return efi_secureboot_mode_disabled;
+	return efi_secureboot_mode_enabled;
+}
+
+struct efi_boot_memmap {
+	unsigned long map_size;
+	unsigned long desc_size;
+	u32 desc_ver;
+	unsigned long map_key;
+	unsigned long buff_size;
+	efi_memory_desc_t map[];
+};
+
+#define EFI_RT_SUPPORTED_GET_TIME 0x0001
+#define EFI_RT_SUPPORTED_SET_TIME 0x0002
+#define EFI_RT_SUPPORTED_GET_WAKEUP_TIME 0x0004
+#define EFI_RT_SUPPORTED_SET_WAKEUP_TIME 0x0008
+#define EFI_RT_SUPPORTED_GET_VARIABLE 0x0010
+#define EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME 0x0020
+#define EFI_RT_SUPPORTED_SET_VARIABLE 0x0040
+#define EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP 0x0080
+#define EFI_RT_SUPPORTED_CONVERT_POINTER 0x0100
+#define EFI_RT_SUPPORTED_GET_NEXT_HIGH_MONOTONIC_COUNT 0x0200
+#define EFI_RT_SUPPORTED_RESET_SYSTEM 0x0400
+#define EFI_RT_SUPPORTED_UPDATE_CAPSULE 0x0800
+#define EFI_RT_SUPPORTED_QUERY_CAPSULE_CAPABILITIES 0x1000
+#define EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO 0x2000
+
+#define EFI_RT_SUPPORTED_ALL 0x3fff
+
+#define EFI_RT_SUPPORTED_TIME_SERVICES 0x0003
+#define EFI_RT_SUPPORTED_WAKEUP_SERVICES 0x000c
+#define EFI_RT_SUPPORTED_VARIABLE_SERVICES 0x0070
+
+typedef struct {
+	u32 version;
+	u32 length;
+	u64 memory_protection_attribute;
+} efi_properties_table_t;
+
+#define EFI_PROPERTIES_TABLE_VERSION 0x00010000
+#define EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA 0x1
+
+typedef struct {
+	u16 version;
+	u16 length;
+	u32 runtime_services_supported;
+} efi_rt_properties_table_t;
+
+#define EFI_RT_PROPERTIES_TABLE_VERSION 0x1
+
+#define EFI_INVALID_TABLE_ADDR (~0UL)
+
+// BIT0 implies that Runtime code includes the forward control flow guard
+// instruction, such as X86 CET-IBT or ARM BTI.
+#define EFI_MEMORY_ATTRIBUTES_FLAGS_RT_FORWARD_CONTROL_FLOW_GUARD 0x1

+ 15 - 0
inc/dragonstub/linux/align.h

@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_ALIGN_H
+#define _LINUX_ALIGN_H
+
+#include "const.h"
+
+/* @a is a power of 2 value */
+#define ALIGN_UP(x, a)		__ALIGN_KERNEL((x), (a))
+#define ALIGN_DOWN(x, a)	__ALIGN_KERNEL((x) - ((a) - 1), (a))
+#define __ALIGN_MASK(x, mask)	__ALIGN_KERNEL_MASK((x), (mask))
+#define PTR_ALIGN(p, a)		((typeof(p))ALIGN_UP((unsigned long)(p), (a)))
+#define PTR_ALIGN_DOWN(p, a)	((typeof(p))ALIGN_DOWN((unsigned long)(p), (a)))
+#define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
+
+#endif	/* _LINUX_ALIGN_H */

+ 147 - 0
inc/dragonstub/linux/arch/riscv/asm/asm.h

@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2015 Regents of the University of California
+ */
+
+#ifndef _ASM_RISCV_ASM_H
+#define _ASM_RISCV_ASM_H
+
+#ifdef __ASSEMBLY__
+#define __ASM_STR(x)	x
+#else
+#define __ASM_STR(x)	#x
+#endif
+
+#if __riscv_xlen == 64
+#define __REG_SEL(a, b)	__ASM_STR(a)
+#elif __riscv_xlen == 32
+#define __REG_SEL(a, b)	__ASM_STR(b)
+#else
+#error "Unexpected __riscv_xlen"
+#endif
+
+#define REG_L		__REG_SEL(ld, lw)
+#define REG_S		__REG_SEL(sd, sw)
+#define REG_SC		__REG_SEL(sc.d, sc.w)
+#define REG_AMOSWAP_AQ	__REG_SEL(amoswap.d.aq, amoswap.w.aq)
+#define REG_ASM		__REG_SEL(.dword, .word)
+#define SZREG		__REG_SEL(8, 4)
+#define LGREG		__REG_SEL(3, 2)
+
+#if __SIZEOF_POINTER__ == 8
+#ifdef __ASSEMBLY__
+#define RISCV_PTR		.dword
+#define RISCV_SZPTR		8
+#define RISCV_LGPTR		3
+#else
+#define RISCV_PTR		".dword"
+#define RISCV_SZPTR		"8"
+#define RISCV_LGPTR		"3"
+#endif
+#elif __SIZEOF_POINTER__ == 4
+#ifdef __ASSEMBLY__
+#define RISCV_PTR		.word
+#define RISCV_SZPTR		4
+#define RISCV_LGPTR		2
+#else
+#define RISCV_PTR		".word"
+#define RISCV_SZPTR		"4"
+#define RISCV_LGPTR		"2"
+#endif
+#else
+#error "Unexpected __SIZEOF_POINTER__"
+#endif
+
+#if (__SIZEOF_INT__ == 4)
+#define RISCV_INT		__ASM_STR(.word)
+#define RISCV_SZINT		__ASM_STR(4)
+#define RISCV_LGINT		__ASM_STR(2)
+#else
+#error "Unexpected __SIZEOF_INT__"
+#endif
+
+#if (__SIZEOF_SHORT__ == 2)
+#define RISCV_SHORT		__ASM_STR(.half)
+#define RISCV_SZSHORT		__ASM_STR(2)
+#define RISCV_LGSHORT		__ASM_STR(1)
+#else
+#error "Unexpected __SIZEOF_SHORT__"
+#endif
+
+#ifdef __ASSEMBLY__
+#include <asm/asm-offsets.h>
+
+/* Common assembly source macros */
+
+/*
+ * NOP sequence
+ */
+.macro	nops, num
+	.rept	\num
+	nop
+	.endr
+.endm
+
+	/* save all GPs except x1 ~ x5 */
+	.macro save_from_x6_to_x31
+	REG_S x6,  PT_T1(sp)
+	REG_S x7,  PT_T2(sp)
+	REG_S x8,  PT_S0(sp)
+	REG_S x9,  PT_S1(sp)
+	REG_S x10, PT_A0(sp)
+	REG_S x11, PT_A1(sp)
+	REG_S x12, PT_A2(sp)
+	REG_S x13, PT_A3(sp)
+	REG_S x14, PT_A4(sp)
+	REG_S x15, PT_A5(sp)
+	REG_S x16, PT_A6(sp)
+	REG_S x17, PT_A7(sp)
+	REG_S x18, PT_S2(sp)
+	REG_S x19, PT_S3(sp)
+	REG_S x20, PT_S4(sp)
+	REG_S x21, PT_S5(sp)
+	REG_S x22, PT_S6(sp)
+	REG_S x23, PT_S7(sp)
+	REG_S x24, PT_S8(sp)
+	REG_S x25, PT_S9(sp)
+	REG_S x26, PT_S10(sp)
+	REG_S x27, PT_S11(sp)
+	REG_S x28, PT_T3(sp)
+	REG_S x29, PT_T4(sp)
+	REG_S x30, PT_T5(sp)
+	REG_S x31, PT_T6(sp)
+	.endm
+
+	/* restore all GPs except x1 ~ x5 */
+	.macro restore_from_x6_to_x31
+	REG_L x6,  PT_T1(sp)
+	REG_L x7,  PT_T2(sp)
+	REG_L x8,  PT_S0(sp)
+	REG_L x9,  PT_S1(sp)
+	REG_L x10, PT_A0(sp)
+	REG_L x11, PT_A1(sp)
+	REG_L x12, PT_A2(sp)
+	REG_L x13, PT_A3(sp)
+	REG_L x14, PT_A4(sp)
+	REG_L x15, PT_A5(sp)
+	REG_L x16, PT_A6(sp)
+	REG_L x17, PT_A7(sp)
+	REG_L x18, PT_S2(sp)
+	REG_L x19, PT_S3(sp)
+	REG_L x20, PT_S4(sp)
+	REG_L x21, PT_S5(sp)
+	REG_L x22, PT_S6(sp)
+	REG_L x23, PT_S7(sp)
+	REG_L x24, PT_S8(sp)
+	REG_L x25, PT_S9(sp)
+	REG_L x26, PT_S10(sp)
+	REG_L x27, PT_S11(sp)
+	REG_L x28, PT_T3(sp)
+	REG_L x29, PT_T4(sp)
+	REG_L x30, PT_T5(sp)
+	REG_L x31, PT_T6(sp)
+	.endm
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_RISCV_ASM_H */

+ 518 - 0
inc/dragonstub/linux/arch/riscv/asm/csr.h

@@ -0,0 +1,518 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2015 Regents of the University of California
+ */
+
+#ifndef _ASM_RISCV_CSR_H
+#define _ASM_RISCV_CSR_H
+
+#include <asm/asm.h>
+// #include <dragonstub/linux/bits.h>
+
+/* Status register flags */
+#define SR_SIE		_AC(0x00000002, UL) /* Supervisor Interrupt Enable */
+#define SR_MIE		_AC(0x00000008, UL) /* Machine Interrupt Enable */
+#define SR_SPIE		_AC(0x00000020, UL) /* Previous Supervisor IE */
+#define SR_MPIE		_AC(0x00000080, UL) /* Previous Machine IE */
+#define SR_SPP		_AC(0x00000100, UL) /* Previously Supervisor */
+#define SR_MPP		_AC(0x00001800, UL) /* Previously Machine */
+#define SR_SUM		_AC(0x00040000, UL) /* Supervisor User Memory Access */
+
+#define SR_FS		_AC(0x00006000, UL) /* Floating-point Status */
+#define SR_FS_OFF	_AC(0x00000000, UL)
+#define SR_FS_INITIAL	_AC(0x00002000, UL)
+#define SR_FS_CLEAN	_AC(0x00004000, UL)
+#define SR_FS_DIRTY	_AC(0x00006000, UL)
+
+#define SR_VS		_AC(0x00000600, UL) /* Vector Status */
+#define SR_VS_OFF	_AC(0x00000000, UL)
+#define SR_VS_INITIAL	_AC(0x00000200, UL)
+#define SR_VS_CLEAN	_AC(0x00000400, UL)
+#define SR_VS_DIRTY	_AC(0x00000600, UL)
+
+#define SR_XS		_AC(0x00018000, UL) /* Extension Status */
+#define SR_XS_OFF	_AC(0x00000000, UL)
+#define SR_XS_INITIAL	_AC(0x00008000, UL)
+#define SR_XS_CLEAN	_AC(0x00010000, UL)
+#define SR_XS_DIRTY	_AC(0x00018000, UL)
+
+#define SR_FS_VS	(SR_FS | SR_VS) /* Vector and Floating-Point Unit */
+
+#ifndef CONFIG_64BIT
+#define SR_SD		_AC(0x80000000, UL) /* FS/VS/XS dirty */
+#else
+#define SR_SD		_AC(0x8000000000000000, UL) /* FS/VS/XS dirty */
+#endif
+
+#ifdef CONFIG_64BIT
+#define SR_UXL		_AC(0x300000000, UL) /* XLEN mask for U-mode */
+#define SR_UXL_32	_AC(0x100000000, UL) /* XLEN = 32 for U-mode */
+#define SR_UXL_64	_AC(0x200000000, UL) /* XLEN = 64 for U-mode */
+#endif
+
+/* SATP flags */
+#ifndef CONFIG_64BIT
+#define SATP_PPN	_AC(0x003FFFFF, UL)
+#define SATP_MODE_32	_AC(0x80000000, UL)
+#define SATP_MODE_SHIFT	31
+#define SATP_ASID_BITS	9
+#define SATP_ASID_SHIFT	22
+#define SATP_ASID_MASK	_AC(0x1FF, UL)
+#else
+#define SATP_PPN	_AC(0x00000FFFFFFFFFFF, UL)
+#define SATP_MODE_39	_AC(0x8000000000000000, UL)
+#define SATP_MODE_48	_AC(0x9000000000000000, UL)
+#define SATP_MODE_57	_AC(0xa000000000000000, UL)
+#define SATP_MODE_SHIFT	60
+#define SATP_ASID_BITS	16
+#define SATP_ASID_SHIFT	44
+#define SATP_ASID_MASK	_AC(0xFFFF, UL)
+#endif
+
+/* Exception cause high bit - is an interrupt if set */
+#define CAUSE_IRQ_FLAG		(_AC(1, UL) << (__riscv_xlen - 1))
+
+/* Interrupt causes (minus the high bit) */
+#define IRQ_S_SOFT		1
+#define IRQ_VS_SOFT		2
+#define IRQ_M_SOFT		3
+#define IRQ_S_TIMER		5
+#define IRQ_VS_TIMER		6
+#define IRQ_M_TIMER		7
+#define IRQ_S_EXT		9
+#define IRQ_VS_EXT		10
+#define IRQ_M_EXT		11
+#define IRQ_S_GEXT		12
+#define IRQ_PMU_OVF		13
+#define IRQ_LOCAL_MAX		(IRQ_PMU_OVF + 1)
+#define IRQ_LOCAL_MASK		GENMASK((IRQ_LOCAL_MAX - 1), 0)
+
+/* Exception causes */
+#define EXC_INST_MISALIGNED	0
+#define EXC_INST_ACCESS		1
+#define EXC_INST_ILLEGAL	2
+#define EXC_BREAKPOINT		3
+#define EXC_LOAD_MISALIGNED	4
+#define EXC_LOAD_ACCESS		5
+#define EXC_STORE_MISALIGNED	6
+#define EXC_STORE_ACCESS	7
+#define EXC_SYSCALL		8
+#define EXC_HYPERVISOR_SYSCALL	9
+#define EXC_SUPERVISOR_SYSCALL	10
+#define EXC_INST_PAGE_FAULT	12
+#define EXC_LOAD_PAGE_FAULT	13
+#define EXC_STORE_PAGE_FAULT	15
+#define EXC_INST_GUEST_PAGE_FAULT	20
+#define EXC_LOAD_GUEST_PAGE_FAULT	21
+#define EXC_VIRTUAL_INST_FAULT		22
+#define EXC_STORE_GUEST_PAGE_FAULT	23
+
+/* PMP configuration */
+#define PMP_R			0x01
+#define PMP_W			0x02
+#define PMP_X			0x04
+#define PMP_A			0x18
+#define PMP_A_TOR		0x08
+#define PMP_A_NA4		0x10
+#define PMP_A_NAPOT		0x18
+#define PMP_L			0x80
+
+/* HSTATUS flags */
+#ifdef CONFIG_64BIT
+#define HSTATUS_VSXL		_AC(0x300000000, UL)
+#define HSTATUS_VSXL_SHIFT	32
+#endif
+#define HSTATUS_VTSR		_AC(0x00400000, UL)
+#define HSTATUS_VTW		_AC(0x00200000, UL)
+#define HSTATUS_VTVM		_AC(0x00100000, UL)
+#define HSTATUS_VGEIN		_AC(0x0003f000, UL)
+#define HSTATUS_VGEIN_SHIFT	12
+#define HSTATUS_HU		_AC(0x00000200, UL)
+#define HSTATUS_SPVP		_AC(0x00000100, UL)
+#define HSTATUS_SPV		_AC(0x00000080, UL)
+#define HSTATUS_GVA		_AC(0x00000040, UL)
+#define HSTATUS_VSBE		_AC(0x00000020, UL)
+
+/* HGATP flags */
+#define HGATP_MODE_OFF		_AC(0, UL)
+#define HGATP_MODE_SV32X4	_AC(1, UL)
+#define HGATP_MODE_SV39X4	_AC(8, UL)
+#define HGATP_MODE_SV48X4	_AC(9, UL)
+#define HGATP_MODE_SV57X4	_AC(10, UL)
+
+#define HGATP32_MODE_SHIFT	31
+#define HGATP32_VMID_SHIFT	22
+#define HGATP32_VMID		GENMASK(28, 22)
+#define HGATP32_PPN		GENMASK(21, 0)
+
+#define HGATP64_MODE_SHIFT	60
+#define HGATP64_VMID_SHIFT	44
+#define HGATP64_VMID		GENMASK(57, 44)
+#define HGATP64_PPN		GENMASK(43, 0)
+
+#define HGATP_PAGE_SHIFT	12
+
+#ifdef CONFIG_64BIT
+#define HGATP_PPN		HGATP64_PPN
+#define HGATP_VMID_SHIFT	HGATP64_VMID_SHIFT
+#define HGATP_VMID		HGATP64_VMID
+#define HGATP_MODE_SHIFT	HGATP64_MODE_SHIFT
+#else
+#define HGATP_PPN		HGATP32_PPN
+#define HGATP_VMID_SHIFT	HGATP32_VMID_SHIFT
+#define HGATP_VMID		HGATP32_VMID
+#define HGATP_MODE_SHIFT	HGATP32_MODE_SHIFT
+#endif
+
+/* VSIP & HVIP relation */
+#define VSIP_TO_HVIP_SHIFT	(IRQ_VS_SOFT - IRQ_S_SOFT)
+#define VSIP_VALID_MASK		((_AC(1, UL) << IRQ_S_SOFT) | \
+				 (_AC(1, UL) << IRQ_S_TIMER) | \
+				 (_AC(1, UL) << IRQ_S_EXT))
+
+/* AIA CSR bits */
+#define TOPI_IID_SHIFT		16
+#define TOPI_IID_MASK		GENMASK(11, 0)
+#define TOPI_IPRIO_MASK		GENMASK(7, 0)
+#define TOPI_IPRIO_BITS		8
+
+#define TOPEI_ID_SHIFT		16
+#define TOPEI_ID_MASK		GENMASK(10, 0)
+#define TOPEI_PRIO_MASK		GENMASK(10, 0)
+
+#define ISELECT_IPRIO0		0x30
+#define ISELECT_IPRIO15		0x3f
+#define ISELECT_MASK		GENMASK(8, 0)
+
+#define HVICTL_VTI		BIT(30)
+#define HVICTL_IID		GENMASK(27, 16)
+#define HVICTL_IID_SHIFT	16
+#define HVICTL_DPR		BIT(9)
+#define HVICTL_IPRIOM		BIT(8)
+#define HVICTL_IPRIO		GENMASK(7, 0)
+
+/* xENVCFG flags */
+#define ENVCFG_STCE			(_AC(1, ULL) << 63)
+#define ENVCFG_PBMTE			(_AC(1, ULL) << 62)
+#define ENVCFG_CBZE			(_AC(1, UL) << 7)
+#define ENVCFG_CBCFE			(_AC(1, UL) << 6)
+#define ENVCFG_CBIE_SHIFT		4
+#define ENVCFG_CBIE			(_AC(0x3, UL) << ENVCFG_CBIE_SHIFT)
+#define ENVCFG_CBIE_ILL			_AC(0x0, UL)
+#define ENVCFG_CBIE_FLUSH		_AC(0x1, UL)
+#define ENVCFG_CBIE_INV			_AC(0x3, UL)
+#define ENVCFG_FIOM			_AC(0x1, UL)
+
+/* symbolic CSR names: */
+#define CSR_CYCLE		0xc00
+#define CSR_TIME		0xc01
+#define CSR_INSTRET		0xc02
+#define CSR_HPMCOUNTER3		0xc03
+#define CSR_HPMCOUNTER4		0xc04
+#define CSR_HPMCOUNTER5		0xc05
+#define CSR_HPMCOUNTER6		0xc06
+#define CSR_HPMCOUNTER7		0xc07
+#define CSR_HPMCOUNTER8		0xc08
+#define CSR_HPMCOUNTER9		0xc09
+#define CSR_HPMCOUNTER10	0xc0a
+#define CSR_HPMCOUNTER11	0xc0b
+#define CSR_HPMCOUNTER12	0xc0c
+#define CSR_HPMCOUNTER13	0xc0d
+#define CSR_HPMCOUNTER14	0xc0e
+#define CSR_HPMCOUNTER15	0xc0f
+#define CSR_HPMCOUNTER16	0xc10
+#define CSR_HPMCOUNTER17	0xc11
+#define CSR_HPMCOUNTER18	0xc12
+#define CSR_HPMCOUNTER19	0xc13
+#define CSR_HPMCOUNTER20	0xc14
+#define CSR_HPMCOUNTER21	0xc15
+#define CSR_HPMCOUNTER22	0xc16
+#define CSR_HPMCOUNTER23	0xc17
+#define CSR_HPMCOUNTER24	0xc18
+#define CSR_HPMCOUNTER25	0xc19
+#define CSR_HPMCOUNTER26	0xc1a
+#define CSR_HPMCOUNTER27	0xc1b
+#define CSR_HPMCOUNTER28	0xc1c
+#define CSR_HPMCOUNTER29	0xc1d
+#define CSR_HPMCOUNTER30	0xc1e
+#define CSR_HPMCOUNTER31	0xc1f
+#define CSR_CYCLEH		0xc80
+#define CSR_TIMEH		0xc81
+#define CSR_INSTRETH		0xc82
+#define CSR_HPMCOUNTER3H	0xc83
+#define CSR_HPMCOUNTER4H	0xc84
+#define CSR_HPMCOUNTER5H	0xc85
+#define CSR_HPMCOUNTER6H	0xc86
+#define CSR_HPMCOUNTER7H	0xc87
+#define CSR_HPMCOUNTER8H	0xc88
+#define CSR_HPMCOUNTER9H	0xc89
+#define CSR_HPMCOUNTER10H	0xc8a
+#define CSR_HPMCOUNTER11H	0xc8b
+#define CSR_HPMCOUNTER12H	0xc8c
+#define CSR_HPMCOUNTER13H	0xc8d
+#define CSR_HPMCOUNTER14H	0xc8e
+#define CSR_HPMCOUNTER15H	0xc8f
+#define CSR_HPMCOUNTER16H	0xc90
+#define CSR_HPMCOUNTER17H	0xc91
+#define CSR_HPMCOUNTER18H	0xc92
+#define CSR_HPMCOUNTER19H	0xc93
+#define CSR_HPMCOUNTER20H	0xc94
+#define CSR_HPMCOUNTER21H	0xc95
+#define CSR_HPMCOUNTER22H	0xc96
+#define CSR_HPMCOUNTER23H	0xc97
+#define CSR_HPMCOUNTER24H	0xc98
+#define CSR_HPMCOUNTER25H	0xc99
+#define CSR_HPMCOUNTER26H	0xc9a
+#define CSR_HPMCOUNTER27H	0xc9b
+#define CSR_HPMCOUNTER28H	0xc9c
+#define CSR_HPMCOUNTER29H	0xc9d
+#define CSR_HPMCOUNTER30H	0xc9e
+#define CSR_HPMCOUNTER31H	0xc9f
+
+#define CSR_SSCOUNTOVF		0xda0
+
+#define CSR_SSTATUS		0x100
+#define CSR_SIE			0x104
+#define CSR_STVEC		0x105
+#define CSR_SCOUNTEREN		0x106
+#define CSR_SSCRATCH		0x140
+#define CSR_SEPC		0x141
+#define CSR_SCAUSE		0x142
+#define CSR_STVAL		0x143
+#define CSR_SIP			0x144
+#define CSR_SATP		0x180
+
+#define CSR_STIMECMP		0x14D
+#define CSR_STIMECMPH		0x15D
+
+/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
+#define CSR_SISELECT		0x150
+#define CSR_SIREG		0x151
+
+/* Supervisor-Level Interrupts (AIA) */
+#define CSR_STOPEI		0x15c
+#define CSR_STOPI		0xdb0
+
+/* Supervisor-Level High-Half CSRs (AIA) */
+#define CSR_SIEH		0x114
+#define CSR_SIPH		0x154
+
+#define CSR_VSSTATUS		0x200
+#define CSR_VSIE		0x204
+#define CSR_VSTVEC		0x205
+#define CSR_VSSCRATCH		0x240
+#define CSR_VSEPC		0x241
+#define CSR_VSCAUSE		0x242
+#define CSR_VSTVAL		0x243
+#define CSR_VSIP		0x244
+#define CSR_VSATP		0x280
+#define CSR_VSTIMECMP		0x24D
+#define CSR_VSTIMECMPH		0x25D
+
+#define CSR_HSTATUS		0x600
+#define CSR_HEDELEG		0x602
+#define CSR_HIDELEG		0x603
+#define CSR_HIE			0x604
+#define CSR_HTIMEDELTA		0x605
+#define CSR_HCOUNTEREN		0x606
+#define CSR_HGEIE		0x607
+#define CSR_HENVCFG		0x60a
+#define CSR_HTIMEDELTAH		0x615
+#define CSR_HENVCFGH		0x61a
+#define CSR_HTVAL		0x643
+#define CSR_HIP			0x644
+#define CSR_HVIP		0x645
+#define CSR_HTINST		0x64a
+#define CSR_HGATP		0x680
+#define CSR_HGEIP		0xe12
+
+/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
+#define CSR_HVIEN		0x608
+#define CSR_HVICTL		0x609
+#define CSR_HVIPRIO1		0x646
+#define CSR_HVIPRIO2		0x647
+
+/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
+#define CSR_VSISELECT		0x250
+#define CSR_VSIREG		0x251
+
+/* VS-Level Interrupts (H-extension with AIA) */
+#define CSR_VSTOPEI		0x25c
+#define CSR_VSTOPI		0xeb0
+
+/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
+#define CSR_HIDELEGH		0x613
+#define CSR_HVIENH		0x618
+#define CSR_HVIPH		0x655
+#define CSR_HVIPRIO1H		0x656
+#define CSR_HVIPRIO2H		0x657
+#define CSR_VSIEH		0x214
+#define CSR_VSIPH		0x254
+
+#define CSR_MSTATUS		0x300
+#define CSR_MISA		0x301
+#define CSR_MIDELEG		0x303
+#define CSR_MIE			0x304
+#define CSR_MTVEC		0x305
+#define CSR_MENVCFG		0x30a
+#define CSR_MENVCFGH		0x31a
+#define CSR_MSCRATCH		0x340
+#define CSR_MEPC		0x341
+#define CSR_MCAUSE		0x342
+#define CSR_MTVAL		0x343
+#define CSR_MIP			0x344
+#define CSR_PMPCFG0		0x3a0
+#define CSR_PMPADDR0		0x3b0
+#define CSR_MVENDORID		0xf11
+#define CSR_MARCHID		0xf12
+#define CSR_MIMPID		0xf13
+#define CSR_MHARTID		0xf14
+
+/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
+#define CSR_MISELECT		0x350
+#define CSR_MIREG		0x351
+
+/* Machine-Level Interrupts (AIA) */
+#define CSR_MTOPEI		0x35c
+#define CSR_MTOPI		0xfb0
+
+/* Virtual Interrupts for Supervisor Level (AIA) */
+#define CSR_MVIEN		0x308
+#define CSR_MVIP		0x309
+
+/* Machine-Level High-Half CSRs (AIA) */
+#define CSR_MIDELEGH		0x313
+#define CSR_MIEH		0x314
+#define CSR_MVIENH		0x318
+#define CSR_MVIPH		0x319
+#define CSR_MIPH		0x354
+
+#define CSR_VSTART		0x8
+#define CSR_VCSR		0xf
+#define CSR_VL			0xc20
+#define CSR_VTYPE		0xc21
+#define CSR_VLENB		0xc22
+
+#ifdef CONFIG_RISCV_M_MODE
+# define CSR_STATUS	CSR_MSTATUS
+# define CSR_IE		CSR_MIE
+# define CSR_TVEC	CSR_MTVEC
+# define CSR_SCRATCH	CSR_MSCRATCH
+# define CSR_EPC	CSR_MEPC
+# define CSR_CAUSE	CSR_MCAUSE
+# define CSR_TVAL	CSR_MTVAL
+# define CSR_IP		CSR_MIP
+
+# define CSR_IEH		CSR_MIEH
+# define CSR_ISELECT	CSR_MISELECT
+# define CSR_IREG	CSR_MIREG
+# define CSR_IPH		CSR_MIPH
+# define CSR_TOPEI	CSR_MTOPEI
+# define CSR_TOPI	CSR_MTOPI
+
+# define SR_IE		SR_MIE
+# define SR_PIE		SR_MPIE
+# define SR_PP		SR_MPP
+
+# define RV_IRQ_SOFT		IRQ_M_SOFT
+# define RV_IRQ_TIMER	IRQ_M_TIMER
+# define RV_IRQ_EXT		IRQ_M_EXT
+#else /* CONFIG_RISCV_M_MODE */
+# define CSR_STATUS	CSR_SSTATUS
+# define CSR_IE		CSR_SIE
+# define CSR_TVEC	CSR_STVEC
+# define CSR_SCRATCH	CSR_SSCRATCH
+# define CSR_EPC	CSR_SEPC
+# define CSR_CAUSE	CSR_SCAUSE
+# define CSR_TVAL	CSR_STVAL
+# define CSR_IP		CSR_SIP
+
+# define CSR_IEH		CSR_SIEH
+# define CSR_ISELECT	CSR_SISELECT
+# define CSR_IREG	CSR_SIREG
+# define CSR_IPH		CSR_SIPH
+# define CSR_TOPEI	CSR_STOPEI
+# define CSR_TOPI	CSR_STOPI
+
+# define SR_IE		SR_SIE
+# define SR_PIE		SR_SPIE
+# define SR_PP		SR_SPP
+
+# define RV_IRQ_SOFT		IRQ_S_SOFT
+# define RV_IRQ_TIMER	IRQ_S_TIMER
+# define RV_IRQ_EXT		IRQ_S_EXT
+# define RV_IRQ_PMU	IRQ_PMU_OVF
+# define SIP_LCOFIP     (_AC(0x1, UL) << IRQ_PMU_OVF)
+
+#endif /* !CONFIG_RISCV_M_MODE */
+
+/* IE/IP (Supervisor/Machine Interrupt Enable/Pending) flags */
+#define IE_SIE		(_AC(0x1, UL) << RV_IRQ_SOFT)
+#define IE_TIE		(_AC(0x1, UL) << RV_IRQ_TIMER)
+#define IE_EIE		(_AC(0x1, UL) << RV_IRQ_EXT)
+
+#ifndef __ASSEMBLY__
+
+#define csr_swap(csr, val)					\
+({								\
+	unsigned long __v = (unsigned long)(val);		\
+	__asm__ __volatile__ ("csrrw %0, " __ASM_STR(csr) ", %1"\
+			      : "=r" (__v) : "rK" (__v)		\
+			      : "memory");			\
+	__v;							\
+})
+
+#define csr_read(csr)						\
+({								\
+	register unsigned long __v;				\
+	__asm__ __volatile__ ("csrr %0, " __ASM_STR(csr)	\
+			      : "=r" (__v) :			\
+			      : "memory");			\
+	__v;							\
+})
+
+#define csr_write(csr, val)					\
+({								\
+	unsigned long __v = (unsigned long)(val);		\
+	__asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0"	\
+			      : : "rK" (__v)			\
+			      : "memory");			\
+})
+
+#define csr_read_set(csr, val)					\
+({								\
+	unsigned long __v = (unsigned long)(val);		\
+	__asm__ __volatile__ ("csrrs %0, " __ASM_STR(csr) ", %1"\
+			      : "=r" (__v) : "rK" (__v)		\
+			      : "memory");			\
+	__v;							\
+})
+
+#define csr_set(csr, val)					\
+({								\
+	unsigned long __v = (unsigned long)(val);		\
+	__asm__ __volatile__ ("csrs " __ASM_STR(csr) ", %0"	\
+			      : : "rK" (__v)			\
+			      : "memory");			\
+})
+
+#define csr_read_clear(csr, val)				\
+({								\
+	unsigned long __v = (unsigned long)(val);		\
+	__asm__ __volatile__ ("csrrc %0, " __ASM_STR(csr) ", %1"\
+			      : "=r" (__v) : "rK" (__v)		\
+			      : "memory");			\
+	__v;							\
+})
+
+#define csr_clear(csr, val)					\
+({								\
+	unsigned long __v = (unsigned long)(val);		\
+	__asm__ __volatile__ ("csrc " __ASM_STR(csr) ", %0"	\
+			      : : "rK" (__v)			\
+			      : "memory");			\
+})
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_RISCV_CSR_H */

+ 104 - 0
inc/dragonstub/linux/math.h

@@ -0,0 +1,104 @@
+#pragma once
+
+#include "../types.h"
+#include "div64.h"
+
+/*
+ * This looks more complex than it should be. But we need to
+ * get the type for the ~ right in round_down (it needs to be
+ * as wide as the result!), and we want to evaluate the macro
+ * arguments just once each.
+ */
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+
+/**
+ * round_up - round up to next specified power of 2
+ * @x: the value to round
+ * @y: multiple to round up to (must be a power of 2)
+ *
+ * Rounds @x up to next multiple of @y (which must be a power of 2).
+ * To perform arbitrary rounding up, use roundup() below.
+ */
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y)) + 1)
+
+/**
+ * round_down - round down to next specified power of 2
+ * @x: the value to round
+ * @y: multiple to round down to (must be a power of 2)
+ *
+ * Rounds @x down to next multiple of @y (which must be a power of 2).
+ * To perform arbitrary rounding down, use rounddown() below.
+ */
+#define round_down(x, y) ((x) & ~__round_mask(x, y))
+
+#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP
+
+#define DIV_ROUND_DOWN_ULL(ll, d)               \
+	({                                      \
+		unsigned long long _tmp = (ll); \
+		do_div(_tmp, d);                \
+		_tmp;                           \
+	})
+
+#define DIV_ROUND_UP_ULL(ll, d) \
+	DIV_ROUND_DOWN_ULL((unsigned long long)(ll) + (d)-1, (d))
+
+#if BITS_PER_LONG == 32
+#define DIV_ROUND_UP_SECTOR_T(ll, d) DIV_ROUND_UP_ULL(ll, d)
+#else
+#define DIV_ROUND_UP_SECTOR_T(ll, d) DIV_ROUND_UP(ll, d)
+#endif
+
+/**
+ * roundup - round up to the next specified multiple
+ * @x: the value to up
+ * @y: multiple to round up to
+ *
+ * Rounds @x up to next multiple of @y. If @y will always be a power
+ * of 2, consider using the faster round_up().
+ */
+#define roundup(x, y)                            \
+	({                                       \
+		typeof(y) __y = y;               \
+		(((x) + (__y - 1)) / __y) * __y; \
+	})
+/**
+ * rounddown - round down to next specified multiple
+ * @x: the value to round
+ * @y: multiple to round down to
+ *
+ * Rounds @x down to next multiple of @y. If @y will always be a power
+ * of 2, consider using the faster round_down().
+ */
+#define rounddown(x, y)              \
+	({                           \
+		typeof(x) __x = (x); \
+		__x - (__x % (y));   \
+	})
+
+/*
+ * Divide positive or negative dividend by positive or negative divisor
+ * and round to closest integer. Result is undefined for negative
+ * divisors if the dividend variable type is unsigned and for negative
+ * dividends if the divisor variable type is unsigned.
+ */
+#define DIV_ROUND_CLOSEST(x, divisor)                                \
+	({                                                           \
+		typeof(x) __x = x;                                   \
+		typeof(divisor) __d = divisor;                       \
+		(((typeof(x))-1) > 0 || ((typeof(divisor))-1) > 0 || \
+		 (((__x) > 0) == ((__d) > 0))) ?                     \
+			(((__x) + ((__d) / 2)) / (__d)) :            \
+			(((__x) - ((__d) / 2)) / (__d));             \
+	})
+/*
+ * Same as above but for u64 dividends. divisor must be a 32-bit
+ * number.
+ */
+#define DIV_ROUND_CLOSEST_ULL(x, divisor)                  \
+	({                                                 \
+		typeof(divisor) __d = divisor;             \
+		unsigned long long _tmp = (x) + (__d) / 2; \
+		do_div(_tmp, __d);                         \
+		_tmp;                                      \
+	})

+ 54 - 0
inc/dragonstub/linux/sizes.h

@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * include/linux/sizes.h
+ */
+#ifndef __LINUX_SIZES_H__
+#define __LINUX_SIZES_H__
+
+#include "const.h"
+
+#define SZ_1				0x00000001
+#define SZ_2				0x00000002
+#define SZ_4				0x00000004
+#define SZ_8				0x00000008
+#define SZ_16				0x00000010
+#define SZ_32				0x00000020
+#define SZ_64				0x00000040
+#define SZ_128				0x00000080
+#define SZ_256				0x00000100
+#define SZ_512				0x00000200
+
+#define SZ_1K				0x00000400
+#define SZ_2K				0x00000800
+#define SZ_4K				0x00001000
+#define SZ_8K				0x00002000
+#define SZ_16K				0x00004000
+#define SZ_32K				0x00008000
+#define SZ_64K				0x00010000
+#define SZ_128K				0x00020000
+#define SZ_256K				0x00040000
+#define SZ_512K				0x00080000
+
+#define SZ_1M				0x00100000
+#define SZ_2M				0x00200000
+#define SZ_4M				0x00400000
+#define SZ_8M				0x00800000
+#define SZ_16M				0x01000000
+#define SZ_32M				0x02000000
+#define SZ_64M				0x04000000
+#define SZ_128M				0x08000000
+#define SZ_256M				0x10000000
+#define SZ_512M				0x20000000
+
+#define SZ_1G				0x40000000
+#define SZ_2G				0x80000000
+
+#define SZ_4G				_AC(0x100000000, ULL)
+#define SZ_8G				_AC(0x200000000, ULL)
+#define SZ_16G				_AC(0x400000000, ULL)
+#define SZ_32G				_AC(0x800000000, ULL)
+
+#define SZ_1T				_AC(0x10000000000, ULL)
+#define SZ_64T				_AC(0x400000000000, ULL)
+
+#endif /* __LINUX_SIZES_H__ */

+ 1 - 1
inc/dragonstub/types.h

@@ -52,7 +52,7 @@ typedef u8 efi_bool_t;
 typedef u16 efi_char16_t; /* UNICODE character */
 typedef u64 efi_physical_addr_t;
 typedef void *efi_handle_t;
-
+typedef u64 phys_addr_t;
 typedef _Bool bool;
 
 enum { false = 0, true = 1 };

+ 4 - 0
tools/.gdbinit

@@ -0,0 +1,4 @@
+set architecture riscv
+target remote localhost:1234
+# file bin/kernel/kernel.elf
+#set follow-fork-mode child