[PATCH 2/5] x86_64 EFI support -v3: EFI boot support

From: Huang, Ying
Date: Mon Jul 30 2007 - 23:14:14 EST


This patch adds boot support for EFI x86_64 system.

Boot parameter setup file is updated for x86_64 EFI support. x86_64
EFI boot loader must conform to the EFI boot parameter offsets defined
in the file include/asm-x86_64/bootsetup.h (and x86_64 patches
submitted to ELILO bootloader conforms to this).

The EFI to E820 memory map conversion is done in bootloader. The ELILO
bootloader x86_64 support has been updated to pass E820 map to
kernel. To support EFI runtime service code memory segment, a new E820
memory segment type named E820_RUNTIME_CODE is added. NX bit is turned
off for EFI runtime service area so that EFI runtime code is
executable.

Signed-off-by: Chandramouli Narayanan <mouli@xxxxxxxxxxxxxxx>
Signed-off-by: Huang Ying <ying.huang@xxxxxxxxx>

---

arch/x86_64/kernel/aperture.c | 5 +++++
arch/x86_64/kernel/e820.c | 8 ++++++++
arch/x86_64/kernel/setup.c | 16 +++++++++++++++-
arch/x86_64/mm/init.c | 30 ++++++++++++++++++++----------
include/asm-x86_64/bootsetup.h | 6 ++++++
include/asm-x86_64/e820.h | 1 +
6 files changed, 55 insertions(+), 11 deletions(-)

Index: linux-2.6.23-rc1/include/asm-x86_64/bootsetup.h
===================================================================
--- linux-2.6.23-rc1.orig/include/asm-x86_64/bootsetup.h 2007-07-30 14:51:31.000000000 +0800
+++ linux-2.6.23-rc1/include/asm-x86_64/bootsetup.h 2007-07-30 14:53:58.000000000 +0800
@@ -17,6 +17,12 @@
#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
+#define EFI_SYSTAB (*((unsigned long *)(PARAM+0x1b8)))
+#define EFI_LOADER_SIG ((unsigned char *)(PARAM+0x1c0))
+#define EFI_MEMDESC_SIZE (*((unsigned int *) (PARAM+0x1c4)))
+#define EFI_MEMDESC_VERSION (*((unsigned int *) (PARAM+0x1c8)))
+#define EFI_MEMMAP_SIZE (*((unsigned int *) (PARAM+0x1cc)))
+#define EFI_MEMMAP (*((unsigned long *)(PARAM+0x1d0)))
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
#define SAVED_VIDEO_MODE (*(unsigned short *) (PARAM+0x1FA))
Index: linux-2.6.23-rc1/include/asm-x86_64/e820.h
===================================================================
--- linux-2.6.23-rc1.orig/include/asm-x86_64/e820.h 2007-07-30 14:51:31.000000000 +0800
+++ linux-2.6.23-rc1/include/asm-x86_64/e820.h 2007-07-30 14:53:58.000000000 +0800
@@ -19,6 +19,7 @@
#define E820_RESERVED 2
#define E820_ACPI 3
#define E820_NVS 4
+#define E820_RUNTIME_CODE 5 /* efi runtime code */

#ifndef __ASSEMBLY__
struct e820entry {
Index: linux-2.6.23-rc1/arch/x86_64/kernel/aperture.c
===================================================================
--- linux-2.6.23-rc1.orig/arch/x86_64/kernel/aperture.c 2007-07-30 14:51:31.000000000 +0800
+++ linux-2.6.23-rc1/arch/x86_64/kernel/aperture.c 2007-07-30 14:53:58.000000000 +0800
@@ -94,6 +94,11 @@
printk("Aperture pointing to e820 RAM. Ignoring.\n");
return 0;
}
+ if (e820_any_mapped(aper_base, aper_base + aper_size,
+ E820_RUNTIME_CODE)) {
+ printk("Aperture pointing to runtime code. Ignoring.\n");
+ return 0;
+ }
return 1;
}

Index: linux-2.6.23-rc1/arch/x86_64/kernel/e820.c
===================================================================
--- linux-2.6.23-rc1.orig/arch/x86_64/kernel/e820.c 2007-07-30 14:51:31.000000000 +0800
+++ linux-2.6.23-rc1/arch/x86_64/kernel/e820.c 2007-07-30 14:53:58.000000000 +0800
@@ -19,6 +19,7 @@
#include <linux/mm.h>
#include <linux/suspend.h>
#include <linux/pfn.h>
+#include <linux/efi.h>

#include <asm/pgtable.h>
#include <asm/page.h>
@@ -206,6 +207,7 @@
case E820_RAM: res->name = "System RAM"; break;
case E820_ACPI: res->name = "ACPI Tables"; break;
case E820_NVS: res->name = "ACPI Non-volatile Storage"; break;
+ case E820_RUNTIME_CODE: res->name = "EFI runtime code"; break;
default: res->name = "reserved";
}
res->start = e820.map[i].addr;
@@ -376,6 +378,9 @@
case E820_NVS:
printk("(ACPI NVS)\n");
break;
+ case E820_RUNTIME_CODE:
+ printk("(runtime code)\n");
+ break;
default: printk("type %u\n", e820.map[i].type);
break;
}
@@ -648,6 +653,9 @@
} else if (*p == '$') {
start_at = memparse(p+1, &p);
add_memory_region(start_at, mem_size, E820_RESERVED);
+ } else if (*p == '%') {
+ start_at = memparse(p+1, &p);
+ add_memory_region(start_at, mem_size, E820_RUNTIME_CODE);
} else {
end_user_pfn = (mem_size >> PAGE_SHIFT);
}
Index: linux-2.6.23-rc1/arch/x86_64/kernel/setup.c
===================================================================
--- linux-2.6.23-rc1.orig/arch/x86_64/kernel/setup.c 2007-07-30 14:51:31.000000000 +0800
+++ linux-2.6.23-rc1/arch/x86_64/kernel/setup.c 2007-07-30 14:54:09.000000000 +0800
@@ -44,6 +44,7 @@
#include <linux/dmi.h>
#include <linux/dma-mapping.h>
#include <linux/ctype.h>
+#include <linux/efi.h>

#include <asm/mtrr.h>
#include <asm/uaccess.h>
@@ -69,6 +70,10 @@
* Machine setup..
*/

+#ifdef CONFIG_EFI
+int efi_enabled;
+EXPORT_SYMBOL(efi_enabled);
+#endif
struct cpuinfo_x86 boot_cpu_data __read_mostly;
EXPORT_SYMBOL(boot_cpu_data);

@@ -236,6 +241,12 @@
rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
#endif
+#ifdef CONFIG_EFI
+ if (!strncmp(EFI_LOADER_SIG, "EFIL", 4)) {
+ efi_enabled = 1;
+ efi_init();
+ }
+#endif
setup_memory_region();
copy_edd();

@@ -273,6 +284,8 @@
discover_ebda();

init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
+ if (efi_enabled)
+ efi_map_memmap();

dmi_scan_machine();

@@ -411,7 +424,8 @@

#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
- conswitchp = &vga_con;
+ if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
+ conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
Index: linux-2.6.23-rc1/arch/x86_64/mm/init.c
===================================================================
--- linux-2.6.23-rc1.orig/arch/x86_64/mm/init.c 2007-07-30 14:51:31.000000000 +0800
+++ linux-2.6.23-rc1/arch/x86_64/mm/init.c 2007-07-30 14:53:58.000000000 +0800
@@ -28,6 +28,7 @@
#include <linux/module.h>
#include <linux/memory_hotplug.h>
#include <linux/nmi.h>
+#include <linux/efi.h>

#include <asm/processor.h>
#include <asm/system.h>
@@ -52,6 +53,8 @@
EXPORT_SYMBOL(dma_ops);

static unsigned long dma_reserve __initdata;
+/* Flag indicating EFI runtime executable code area */
+static int efi_runtime_code_area;

DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);

@@ -199,7 +202,7 @@
static __meminit void unmap_low_page(void *adr)
{

- if (after_bootmem)
+ if (after_bootmem || efi_runtime_code_area)
return;

early_iounmap(adr, PAGE_SIZE);
@@ -259,16 +262,21 @@
pmd_t *pmd = pmd_page + pmd_index(address);

if (address >= end) {
- if (!after_bootmem)
+ if (!after_bootmem && !efi_runtime_code_area)
for (; i < PTRS_PER_PMD; i++, pmd++)
set_pmd(pmd, __pmd(0));
break;
}

- if (pmd_val(*pmd))
+ if (pmd_val(*pmd) && !efi_runtime_code_area)
continue;

- entry = _PAGE_NX|_PAGE_PSE|_KERNPG_TABLE|_PAGE_GLOBAL|address;
+ if (efi_runtime_code_area) {
+ entry = pmd_val(*pmd);
+ entry &= ~_PAGE_NX;
+ } else
+ entry = _PAGE_NX | _PAGE_PSE | _KERNPG_TABLE | \
+ _PAGE_GLOBAL | address;
entry &= __supported_pte_mask;
set_pmd(pmd, __pmd(entry));
}
@@ -296,8 +304,8 @@

if (addr >= end)
break;
-
- if (!after_bootmem && !e820_any_mapped(addr,addr+PUD_SIZE,0)) {
+ if (!after_bootmem && !efi_enabled &&
+ !e820_any_mapped(addr, addr+PUD_SIZE, 0)) {
set_pud(pud, __pud(0));
continue;
}
@@ -344,7 +352,8 @@

/* Setup the direct mapping of the physical memory at PAGE_OFFSET.
This runs before bootmem is initialized and gets pages directly from the
- physical memory. To access them they are temporarily mapped. */
+ physical memory. To access them they are temporarily mapped.
+ This code can also be called to map EFI runtime code. */
void __meminit init_memory_mapping(unsigned long start, unsigned long end)
{
unsigned long next;
@@ -357,7 +366,8 @@
* mapped. Unfortunately this is done currently before the nodes are
* discovered.
*/
- if (!after_bootmem)
+ efi_runtime_code_area = e820_all_mapped(start, end, E820_RUNTIME_CODE);
+ if (!after_bootmem && !efi_runtime_code_area)
find_early_table_space(end);

start = (unsigned long)__va(start);
@@ -368,7 +378,7 @@
pgd_t *pgd = pgd_offset_k(start);
pud_t *pud;

- if (after_bootmem)
+ if (after_bootmem || efi_runtime_code_area)
pud = pud_offset(pgd, start & PGDIR_MASK);
else
pud = alloc_low_page(&pud_phys);
@@ -377,7 +387,7 @@
if (next > end)
next = end;
phys_pud_init(pud, __pa(start), __pa(next));
- if (!after_bootmem)
+ if (!after_bootmem && !efi_runtime_code_area)
set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys));
unmap_low_page(pud);
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/