Selaa lähdekoodia

设置镜像内存权限为rwx,并且退出bootservice (#9)

LoGin 5 kuukautta sitten
vanhempi
commit
2604d7835e
7 muutettua tiedostoa jossa 122 lisäystä ja 41 poistoa
  1. 3 1
      .vscode/settings.json
  2. 4 29
      apps/dragon_stub-main.c
  3. 83 0
      apps/elf.c
  4. 2 8
      apps/fdt.c
  5. 4 3
      apps/helper.c
  6. 22 0
      inc/dragonstub/dragonstub.h
  7. 4 0
      inc/efiapi.h

+ 3 - 1
.vscode/settings.json

@@ -44,6 +44,8 @@
         "efidebug.h": "c",
         "align.h": "c",
         "math.h": "c",
-        "csr.h": "c"
+        "csr.h": "c",
+        "efidevp.h": "c",
+        "efiprot.h": "c"
     }
 }

+ 4 - 29
apps/dragon_stub-main.c

@@ -1,3 +1,4 @@
+#include "dragonstub/riscv64.h"
 #include <efi.h>
 #include <efilib.h>
 #include <dragonstub/printk.h>
@@ -5,26 +6,6 @@
 
 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)
 {
@@ -33,21 +14,17 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
 	/* addr/point and size pairs for memory management*/
 	char *cmdline_ptr = NULL;
 
-	InitializeLib(image_handle, 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
 	 * line.
 	 */
-	status = uefi_call_wrapper(BS->OpenProtocol, 6, image_handle,
-				   &LoadedImageProtocol, (void **)&loaded_image,
-				   image_handle, NULL,
-				   EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	status = efi_bs_call(HandleProtocol, image_handle, &LoadedImageProtocol,
+			     (void *)&loaded_image);
 
 	if (EFI_ERROR(status)) {
 		efi_err("Could not open loaded image protocol: %d\n", status);
@@ -67,8 +44,6 @@ 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)) {

+ 83 - 0
apps/elf.c

@@ -1,7 +1,12 @@
 #include "elf.h"
+#include "dragonstub/linux-efi.h"
 #include "dragonstub/linux/align.h"
+#include "dragonstub/printk.h"
+#include "dragonstub/types.h"
+#include "efidef.h"
 #include <efi.h>
 #include <efiapi.h>
+#include <efidevp.h>
 #include <efilib.h>
 #include <dragonstub/dragonstub.h>
 #include <dragonstub/elfloader.h>
@@ -189,6 +194,72 @@ static bool check_image_region(u64 base, u64 size)
 
 	return ret;
 }
+
+/**
+ * efi_remap_image_all_rwx - Remap a loaded image with the appropriate permissions
+ *                   for code and data
+ *
+ * @image_base:	the base of the image in memory
+ * @alloc_size:	the size of the area in memory occupied by the image
+ *
+ * efi_remap_image() uses the EFI memory attribute protocol to remap the code
+ * region of the loaded image read-only/executable, and the remainder
+ * read-write/non-executable. The code region is assumed to start at the base
+ * of the image, and will therefore cover the PE/COFF header as well.
+ */
+void efi_remap_image_all_rwx(unsigned long image_base, unsigned alloc_size)
+{
+	efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
+	efi_memory_attribute_protocol_t *memattr;
+	efi_status_t status;
+	u64 attr;
+
+	/*
+	 * If the firmware implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL, let's
+	 * invoke it to remap the text/rodata region of the decompressed image
+	 * as read-only and the data/bss region as non-executable.
+	 */
+	status = efi_bs_call(LocateProtocol, &guid, NULL, (void **)&memattr);
+	if (status != EFI_SUCCESS)
+		return;
+
+	// Get the current attributes for the entire region
+	status = memattr->get_memory_attributes(memattr, image_base, alloc_size,
+						&attr);
+	if (status != EFI_SUCCESS) {
+		efi_warn(
+			"Failed to retrieve memory attributes for image region: 0x%lx\n",
+			status);
+		return;
+	}
+
+	efi_debug("Current attributes for image region: 0x%lx\n", attr);
+
+	// If the entire region was already mapped as non-exec, clear the
+	// attribute from the code region. Otherwise, set it on the data
+	// region.
+	if (attr & EFI_MEMORY_XP) {
+		status = memattr->clear_memory_attributes(
+			memattr, image_base, alloc_size, EFI_MEMORY_XP);
+		if (status != EFI_SUCCESS)
+			efi_warn("Failed to remap region executable\n");
+	}
+
+	if (attr & EFI_MEMORY_WP) {
+		status = memattr->clear_memory_attributes(
+			memattr, image_base, alloc_size, EFI_MEMORY_WP);
+		if (status != EFI_SUCCESS)
+			efi_warn("Failed to remap region writable\n");
+	}
+
+	if (attr & EFI_MEMORY_RP) {
+		status = memattr->clear_memory_attributes(
+			memattr, image_base, alloc_size, EFI_MEMORY_RP);
+		if (status != EFI_SUCCESS)
+			efi_warn("Failed to remap region readable\n");
+	}
+}
+
 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,
@@ -234,6 +305,8 @@ efi_status_t efi_allocate_kernel_memory(const Elf64_Phdr *phdr_start,
 	// zeroed the memory
 	memset((void *)(*ret_paddr), 0, mem_size);
 
+	efi_remap_image_all_rwx(*ret_paddr, mem_size);
+
 	return EFI_SUCCESS;
 }
 
@@ -346,5 +419,15 @@ efi_status_t load_elf(struct payload_info *payload_info)
 	payload_info->loaded_size = program_size;
 	payload_info->kernel_entry =
 		ehdr->e_entry - image_link_base_paddr + program_paddr;
+
+	// 处理权限问题
+
+	efi_remap_image_all_rwx(program_paddr, program_size);
+	extern void _start(void);
+	extern void _image_end(void);
+	u64 image_size = (u64)&_image_end - (u64)&_start;
+	efi_debug("image_size: %d\n", image_size);
+	efi_remap_image_all_rwx((u64)&_start, (image_size + 4095) & ~4095);
+
 	return EFI_SUCCESS;
 }

+ 2 - 8
apps/fdt.c

@@ -294,14 +294,9 @@ static efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
 	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;
+	status = efi_exit_boot_services(handle, &priv, exit_boot_func);
 
 	if (status == EFI_SUCCESS) {
-		efi_info("Boot services exited successfully.\n");
 		efi_set_virtual_address_map_t *svam;
 
 		if (efi_novamap)
@@ -378,8 +373,7 @@ efi_status_t efi_boot_kernel(efi_handle_t handle,
 #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 */

+ 4 - 3
apps/helper.c

@@ -1,3 +1,4 @@
+#include "dragonstub/printk.h"
 #include "efidef.h"
 #include <efi.h>
 #include <efilib.h>
@@ -376,10 +377,10 @@ efi_status_t efi_exit_boot_services(void *handle, void *priv,
 	}
 
 	efi_debug("before ExitBootServices, handle=%p, map_key=%p\n", handle, map->map_key);
-
+	efi_debug("BS->ExitBootServices=%p\n", BS->ExitBootServices);
+	efi_debug("ST->BS->ExitBootServices=%p\n", ST->BootServices->ExitBootServices);
 	status = efi_bs_call(ExitBootServices, handle, map->map_key);
-
-	efi_debug("after ExitBootServices, status: %d\n", status);
+	// exit之后不能再使用打印函数,否则会出现错误
 
 	if (status == EFI_INVALID_PARAMETER) {
 		/*

+ 22 - 0
inc/dragonstub/dragonstub.h

@@ -443,3 +443,25 @@ efi_status_t efi_exit_boot_services(void *handle, void *priv,
 void __noreturn efi_enter_kernel(struct payload_info *payload_info,
 				 unsigned long fdt, unsigned long fdt_size);
 
+typedef union efi_memory_attribute_protocol efi_memory_attribute_protocol_t;
+
+union efi_memory_attribute_protocol {
+	struct {
+		efi_status_t(__efiapi *get_memory_attributes)(
+			efi_memory_attribute_protocol_t *, efi_physical_addr_t,
+			u64, u64 *);
+
+		efi_status_t(__efiapi *set_memory_attributes)(
+			efi_memory_attribute_protocol_t *, efi_physical_addr_t,
+			u64, u64);
+
+		efi_status_t(__efiapi *clear_memory_attributes)(
+			efi_memory_attribute_protocol_t *, efi_physical_addr_t,
+			u64, u64);
+	};
+	struct {
+		u32 get_memory_attributes;
+		u32 set_memory_attributes;
+		u32 clear_memory_attributes;
+	} mixed_mode;
+};

+ 4 - 0
inc/efiapi.h

@@ -1,6 +1,10 @@
 #ifndef _EFI_API_H
 #define _EFI_API_H
 
+#include <efidevp.h>
+#include <efiprot.h>
+#include <eficon.h>
+
 /*++
 
 Copyright (c) 1998  Intel Corporation