LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 2.6.21 0/3] x86_64 EFI64 support Try #2
@ 2007-07-02 17:06 Chandramouli Narayanan
2007-07-02 17:06 ` [PATCH 2.6.21 1/3] " Chandramouli Narayanan
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Chandramouli Narayanan @ 2007-07-02 17:06 UTC (permalink / raw)
To: linux-kernel; +Cc: ak, akpm
--
This is Try #2 of x86_64 of EFI64 support with changes implemented based on
feedback received. Details can be found in the patch files. These changes
have been tested on UEFI platforms. No issues to report.
Looking forward to your comments,
thanks,
Chandramouli Narayanan <mouli@linux.intel.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2.6.21 1/3] x86_64 EFI64 support Try #2
2007-07-02 17:06 [PATCH 2.6.21 0/3] x86_64 EFI64 support Try #2 Chandramouli Narayanan
@ 2007-07-02 17:06 ` Chandramouli Narayanan
2007-07-03 23:25 ` Andrew Morton
2007-07-02 17:06 ` [PATCH 2.6.21 2/3] " Chandramouli Narayanan
2007-07-02 17:06 ` [PATCH 2.6.21 3/3] " Chandramouli Narayanan
2 siblings, 1 reply; 9+ messages in thread
From: Chandramouli Narayanan @ 2007-07-02 17:06 UTC (permalink / raw)
To: linux-kernel; +Cc: ak, akpm
[-- Attachment #1: patch1 --]
[-- Type: text/plain, Size: 35146 bytes --]
EFI x86_64 support Patch 1 of 3 (try #2)
----------------------------------------
- Being experimental, dropped default option for CONFIG_EFI.
- Implemented EFI to E820 memory map conversion. This is based on
bootloader support. The ELILO bootloader x86_64 support has been
updated to pass E820 map to kernel. This simplified kernel efi code.
Also the duplicate code for setting up page table for
EFI run time is gotten rid of with simpler patch.
------------------------------------------------------------------
NOTE: The ELILO patch to perform EFI to E820 map conversion is being
submitted to sourceforge project maintainer.
------------------------------------------------------------------
- UEFI wrapper code in earlier patch is now replaced with code adapted from
NDIS wrapper sourceforge project.
- Parameters in EFI calls are cast to (u64) to rid build warnings.
- Code that is supposed to be __init only in arch/x86_64/kernel/efi.c
is prefixed as such.
- Documentation/x86_64/uefi.txt adds instructions on how to set up EFI64
system.
- Documentation/i386/zero-page.txt notes differences in the boot parameters
for x86_64. The efi init code uses these parameters passed by the bootloader.
- Added missing KERN_ prefixes in EFI code. probe_kernel_address() used for
checking firmware vendor in efi init code.
- The dependency on X86_64 in the configuration of EFI_RTC is dropped
since we have hardware realtime clock support
Issues _not_ addressed (per feedback from Eric Biederman)
- Virtual mode support is still retained in this patch. On looking at the
configuration options, the EFI variable support is required at runtime.
For instance, the firmware driver configuration support with EFI variable
via sysfs would require this. I'm not sure if virtual mode support
can be killed altogether. More investigation needed here.
- The variable efi_enabled is used throughout across architecutres if
CONFIG_EFI option is enabled. The i386 code also uses this variable.
This is something that can be revisited with code consolidation across
architectures.
Signed-off-by: Chandramouli Narayanan <mouli@linux.intel.com>
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/Documentation/i386/zero-page.txt linux-2.6.21-uefi-finaltest4/Documentation/i386/zero-page.txt
--- linux-2.6.21-orig/Documentation/i386/zero-page.txt 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/Documentation/i386/zero-page.txt 2007-06-21 17:22:49.000000000 -0700
@@ -31,11 +31,11 @@ Offset Type Description
0xb0 - 0x13f Free. Add more parameters here if you really need them.
0x140- 0x1be EDID_INFO Video mode setup
-0x1c4 unsigned long EFI system table pointer
-0x1c8 unsigned long EFI memory descriptor size
-0x1cc unsigned long EFI memory descriptor version
+0x1c4 unsigned long EFI system table pointer*
+0x1c8 unsigned long EFI memory descriptor size*
+0x1cc unsigned long EFI memory descriptor version*
0x1d0 unsigned long EFI memory descriptor map pointer
-0x1d4 unsigned long EFI memory descriptor map size
+0x1d4 unsigned long EFI memory descriptor map size*
0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb
0x1e8 char number of entries in E820MAP (below)
0x1e9 unsigned char number of entries in EDDBUF (below)
@@ -86,3 +86,13 @@ Offset Type Description
0x2d0 - 0xd00 E820MAP
0xd00 - 0xeff EDDBUF (edd.S) for disk signature read sector
0xd00 - 0xeeb EDDBUF (edd.S) for edd data
+
+Changes for x86_64 implementation:
+---------------------------------
+For alignment purposes, the following parameters are rearranged.
+
+0x1b8 unsigned long EFI system table pointer
+0x1c0 unsigned long EFI Loader signature
+0x1c4 unsigned long EFI memory descriptor size
+0x1c8 unsigned long EFI memory descriptor version
+0x1cc unsigned long EFI memory descriptor map size
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/Documentation/x86_64/uefi.txt linux-2.6.21-uefi-finaltest4/Documentation/x86_64/uefi.txt
--- linux-2.6.21-orig/Documentation/x86_64/uefi.txt 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.21-uefi-finaltest4/Documentation/x86_64/uefi.txt 2007-06-25 14:47:24.000000000 -0700
@@ -0,0 +1,42 @@
+General note on [U]EFI x86_64 support
+-------------------------------------
+
+This provides documentation on [U]EFI support for x86_64 architecture.
+The nomenclature EFI and UEFI are used intechangeably in this document.
+
+Although the tools below are _not_ needed for building the kernel,
+the needed bootloader support and associated tools for x86_64 platforms
+with EFI firmware and specifications are listed below.
+
+1. UEFI specification: http://www.uefi.org
+
+2. Booting EFI64 enabled kernel requires boot loader support.
+Patches to elilo and gnu-efi library with x86_64 support and documentation
+have been submitted to respective project maintainers.
+ elilo: http://sourceforge.net/projects/elilo
+ gnu-efi library: http://sourceforge.net/projects/gnu-efi/
+ gnu-efi-3.0d release now supports [U]EFI x86_64.
+
+3. The tool to convert ELF to PE-COFF image:
+ binutils-2.17.50.0.14 supports Intel64 EFI.
+ see http://www.kernel.org/pub/linux/devel/binutils/
+ [ elilo/gnu-efi with x86_64 support need this binutils support ]
+
+4. x86_64 platform with EFI/UEFI firmware.
+
+Mechanics:
+---------
+- Apply the EFI64 kernel patches and build with the following configuration.
+ CONFIG_EFI=y
+ EFI_FB=y
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+ CONFIG_EFI_VARS=y
+
+- Create a VFAT partition on the disk
+- Copy the following to the VFAT partition:
+ elilo bootloader with x86_64 support and elilo configuration file
+ efi64 kernel image and initrd. Instructions on building elilo
+ and its dependencies can be found in the elilo sourceforge project.
+- Boot to EFI shell and invoke elilo choosing efi64 kernel image
+- On UEFI2.0 firmware systems, pass vga=normal for boot messages to show up
+ console. You can pass along the 'resume' boot option to test suspend/resume.
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/Kconfig linux-2.6.21-uefi-finaltest4/arch/x86_64/Kconfig
--- linux-2.6.21-orig/arch/x86_64/Kconfig 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/arch/x86_64/Kconfig 2007-06-26 16:55:30.000000000 -0700
@@ -254,6 +254,19 @@ config X86_HT
depends on SMP && !MK8
default y
+config EFI
+ bool "Boot from EFI support (EXPERIMENTAL)"
+ ---help---
+ This enables the the kernel to boot on EFI platforms using
+ system configuration information passed to it from the firmware.
+ This also enables the kernel to use any EFI runtime services that are
+ available (such as the EFI variable services).
+ This option is only useful on systems that have EFI firmware
+ and will result in a kernel image that is ~8k larger. However,
+ even with this option, the resultant kernel should continue to
+ boot on existing non-EFI platforms. For more information on
+ how to set up [U]EFI64 system, see Documentation/x86_64/uefi.txt.
+
config MATH_EMULATION
bool
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/include/asm-x86_64/bootsetup.h linux-2.6.21-uefi-finaltest4/include/asm-x86_64/bootsetup.h
--- linux-2.6.21-orig/include/asm-x86_64/bootsetup.h 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/include/asm-x86_64/bootsetup.h 2007-06-12 16:16:12.000000000 -0700
@@ -17,6 +17,12 @@ extern char x86_boot_params[BOOT_PARAM_S
#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))
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/include/asm-x86_64/eficallwrap.h linux-2.6.21-uefi-finaltest4/include/asm-x86_64/eficallwrap.h
--- linux-2.6.21-orig/include/asm-x86_64/eficallwrap.h 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.21-uefi-finaltest4/include/asm-x86_64/eficallwrap.h 2007-06-25 14:36:18.000000000 -0700
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2006 Giridhar Pemmasani
+ * Copyright (C) 2007-2010 Intel Corp
+ * Contributed by Chandramouli Narayanan<mouli@linux.intel.com>
+ * Adapted NDIS wrapper macros from http://ndiswrapper.sourceforge.net
+ * for EFI x86_64 linux support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+extern efi_status_t LIN2WIN0(void *fp);
+extern efi_status_t LIN2WIN1(void *fp, u64 arg1);
+extern efi_status_t LIN2WIN2(void *fp, u64 arg1, u64 arg2);
+extern efi_status_t LIN2WIN3(void *fp, u64 arg1, u64 arg2, u64 arg3);
+extern efi_status_t LIN2WIN4(void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4);
+extern efi_status_t LIN2WIN5(
+ void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5);
+extern efi_status_t LIN2WIN6(
+ void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6);
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/include/asm-x86_64/e820.h linux-2.6.21-uefi-finaltest4/include/asm-x86_64/e820.h
--- linux-2.6.21-orig/include/asm-x86_64/e820.h 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/include/asm-x86_64/e820.h 2007-06-25 13:32:33.000000000 -0700
@@ -21,6 +21,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 {
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/Makefile linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/Makefile
--- linux-2.6.21-orig/arch/x86_64/kernel/Makefile 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/Makefile 2007-06-21 12:33:43.000000000 -0700
@@ -37,6 +37,7 @@ obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o
obj-$(CONFIG_X86_VSMP) += vsmp.o
obj-$(CONFIG_K8_NB) += k8.o
obj-$(CONFIG_AUDIT) += audit.o
+obj-$(CONFIG_EFI) += efi.o efi_callwrap.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_PCI) += early-quirks.o
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/efi.c linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/efi.c
--- linux-2.6.21-orig/arch/x86_64/kernel/efi.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/efi.c 2007-06-26 14:39:27.000000000 -0700
@@ -0,0 +1,531 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ * David Mosberger-Tang <davidm@hpl.hp.com>
+ * Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2005-2008 Intel Co.
+ * Fenghua Yu <fenghua.yu@intel.com>
+ * Bibo Mao <bibo.mao@intel.com>
+ * Chandramouli Narayanan <mouli@linux.intel.com>
+ *
+ * Code to convert EFI to E820 map has been implemented in elilo bootloader
+ * based on a EFI patch by Edgar Hucek. Based on the E820 map, the page table
+ * is setup appropriately for EFI runtime code. NDIS wrapper code from
+ * sourceforge project is adapted here for UEFI wrapper call.
+ * - mouli 06/14/2007.
+ *
+ * All EFI Runtime Services are not implemented yet as EFI only
+ * supports physical mode addressing on SoftSDV. This is to be fixed
+ * in a future version. --drummond 1999-07-20
+ *
+ * Implemented EFI runtime services and virtual mode calls. --davidm
+ *
+ * Goutham Rao: <goutham.rao@intel.com>
+ * Skip non-WB memory and ignore empty memory ranges.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/spinlock.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/efi.h>
+#include <linux/uaccess.h>
+
+#include <asm/setup.h>
+#include <asm/bootsetup.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/e820.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/proto.h>
+#include <asm-x86_64/eficallwrap.h>
+
+#define EFI_DEBUG 0
+#define PFX "EFI: "
+
+struct efi efi;
+EXPORT_SYMBOL(efi);
+
+extern void (*machine_emergency_restart_func)(void);
+
+struct efi efi_phys __initdata;
+struct efi_memory_map memmap;
+static efi_system_table_t efi_systab __initdata;
+
+static unsigned long efi_rt_eflags;
+/* efi_rt_lock protects efi physical mode call */
+static spinlock_t efi_rt_lock = SPIN_LOCK_UNLOCKED;
+static pgd_t save_pgd;
+
+static efi_status_t _efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+ return LIN2WIN2((void*)efi.systab->runtime->get_time,
+ (u64)tm,
+ (u64)tc);
+}
+
+static efi_status_t _efi_set_time(efi_time_t *tm)
+{
+ return LIN2WIN1((void*)efi.systab->runtime->set_time,
+ (u64)tm);
+}
+
+static efi_status_t _efi_get_wakeup_time(
+ efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
+{
+ return LIN2WIN3((void*)efi.systab->runtime->get_wakeup_time,
+ (u64)enabled,
+ (u64)pending,
+ (u64)tm);
+}
+
+static efi_status_t _efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+{
+ return LIN2WIN2((void*)efi.systab->runtime->set_wakeup_time,
+ (u64)enabled,
+ (u64)tm);
+}
+
+static efi_status_t _efi_get_variable(
+ efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+ unsigned long *data_size, void *data)
+{
+ return LIN2WIN5((void*)efi.systab->runtime->get_variable,
+ (u64)name,
+ (u64)vendor,
+ (u64)attr,
+ (u64)data_size,
+ (u64)data);
+}
+
+static efi_status_t _efi_get_next_variable(
+ unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)
+{
+ return LIN2WIN3((void*)efi.systab->runtime->get_next_variable,
+ (u64)name_size,
+ (u64)name,
+ (u64)vendor);
+}
+
+static efi_status_t _efi_set_variable(
+ efi_char16_t *name, efi_guid_t *vendor,
+ u64 attr, u64 data_size, void *data)
+{
+ return LIN2WIN5((void*)efi.systab->runtime->set_variable,
+ (u64)name,
+ (u64)vendor,
+ (u64)attr,
+ (u64)data_size,
+ (u64)data);
+}
+
+static efi_status_t _efi_get_next_high_mono_count(u32 *count)
+{
+ return LIN2WIN1((void*)efi.systab->runtime->get_next_high_mono_count,
+ (u64)count);
+}
+
+static efi_status_t _efi_reset_system(
+ int reset_type, efi_status_t status,
+ unsigned long data_size, efi_char16_t *data)
+{
+ return LIN2WIN4((void*)efi.systab->runtime->reset_system,
+ (u64)reset_type,
+ (u64)status,
+ (u64)data_size,
+ (u64)data);
+}
+
+static efi_status_t _efi_set_virtual_address_map(
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ u32 descriptor_version, efi_memory_desc_t *virtual_map)
+{
+ return LIN2WIN4((void*)efi.systab->runtime->set_virtual_address_map,
+ (u64)memory_map_size,
+ (u64)descriptor_size,
+ (u64)descriptor_version,
+ (u64)virtual_map);
+}
+
+static void __init efi_call_phys_prelog(void) __acquires(efi_rt_lock)
+{
+ unsigned long vaddress;
+
+ spin_lock(&efi_rt_lock);
+ local_irq_save(efi_rt_eflags);
+
+ vaddress = (unsigned long)__va(0x0UL);
+ pgd_val(save_pgd) = pgd_val(*pgd_offset_k(0x0UL));
+ set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
+
+ global_flush_tlb();
+}
+
+static void __init efi_call_phys_epilog(void) __releases(efi_rt_lock)
+{
+ /*
+ * After the lock is released, the original page table is restored.
+ */
+ set_pgd(pgd_offset_k(0x0UL), save_pgd);
+ global_flush_tlb();
+ local_irq_restore(efi_rt_eflags);
+ spin_unlock(&efi_rt_lock);
+}
+
+static efi_status_t __init phys_efi_set_virtual_address_map(
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ u32 descriptor_version, efi_memory_desc_t *virtual_map)
+{
+ efi_status_t status;
+
+ efi_call_phys_prelog();
+ status = LIN2WIN4(efi_phys.set_virtual_address_map,
+ (u64)memory_map_size,
+ (u64)descriptor_size,
+ (u64)descriptor_version,
+ (u64)virtual_map);
+ efi_call_phys_epilog();
+ return status;
+}
+
+static efi_status_t __init phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+
+ efi_status_t status;
+
+ efi_call_phys_prelog();
+ status = LIN2WIN2(efi_phys.get_time,
+ (u64)tm,
+ (u64)tc);
+ efi_call_phys_epilog();
+ return status;
+}
+
+inline int efi_set_rtc_mmss(unsigned long nowtime)
+{
+ int real_seconds, real_minutes;
+ efi_status_t status;
+ efi_time_t eft;
+ efi_time_cap_t cap;
+
+ spin_lock(&efi_rt_lock);
+ status = efi.get_time(&eft, &cap);
+ spin_unlock(&efi_rt_lock);
+ if (status != EFI_SUCCESS) {
+ printk(KERN_ERR PFX "Oops: efitime: can't read time!\n");
+ return -1;
+ }
+
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
+ real_minutes += 30;
+ real_minutes %= 60;
+ eft.minute = real_minutes;
+ eft.second = real_seconds;
+
+ spin_lock(&efi_rt_lock);
+ status = efi.set_time(&eft);
+ spin_unlock(&efi_rt_lock);
+ if (status != EFI_SUCCESS) {
+ printk(KERN_ERR PFX "Oops: efitime: can't write time!\n");
+ return -1;
+ }
+ return 0;
+}
+/*
+ * This is used during kernel init before runtime
+ * services have been remapped and also during suspend, therefore,
+ * we'll need to call both in physical and virtual modes.
+ */
+inline unsigned long efi_get_time(void)
+{
+ efi_status_t status;
+ efi_time_t eft;
+ efi_time_cap_t cap;
+
+ if (efi.get_time) {
+ /* if we are in virtual mode use remapped function */
+ status = efi.get_time(&eft, &cap);
+ } else {
+ /* we are in physical mode */
+ status = phys_efi_get_time(&eft, &cap);
+ }
+ if (status != EFI_SUCCESS)
+ printk(KERN_ERR PFX "Oops: efitime: can't read time status: 0x%lx\n",status);
+
+ return mktime(eft.year, eft.month, eft.day, eft.hour,
+ eft.minute, eft.second);
+}
+
+/*
+ * We need to map the EFI memory map again after paging_init().
+ */
+void __init efi_map_memmap(void)
+{
+ int i;
+
+ memmap.map = __va((unsigned long)memmap.phys_map);
+ memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+
+ /* Make EFI runtime code area executable */
+ for (i = 0; i < e820.nr_map; i++) {
+ switch (e820.map[i].type) {
+ case E820_RUNTIME_CODE:
+ init_memory_mapping(
+ e820.map[i].addr,
+ e820.map[i].addr + e820.map[i].size);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/* Override function for emergency restart on EFI enabled systems */
+static void efi_emergency_restart(void)
+{
+ /* If EFI enabled, reset system through EFI protocol. */
+ efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
+ return;
+}
+
+void __init efi_init(void)
+{
+ efi_config_table_t *config_tables;
+ efi_runtime_services_t *runtime;
+ efi_char16_t *c16;
+ char vendor[100] = "unknown";
+ int i = 0;
+
+ memset(&efi, 0, sizeof(efi) );
+ memset(&efi_phys, 0, sizeof(efi_phys));
+
+ efi_phys.systab = (efi_system_table_t *)EFI_SYSTAB;
+ memmap.phys_map = (void*)EFI_MEMMAP;
+ memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE;
+ memmap.desc_version = EFI_MEMDESC_VERSION;
+ memmap.desc_size = EFI_MEMDESC_SIZE;
+
+ efi.systab = (efi_system_table_t *) early_ioremap(
+ (unsigned long)efi_phys.systab,
+ sizeof(efi_system_table_t));
+ memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
+ efi.systab = &efi_systab;
+ /*
+ * Verify the EFI Table
+ */
+ if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+ printk(KERN_ERR PFX "Woah! EFI system table signature incorrect\n");
+ if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
+ printk(KERN_ERR PFX
+ "Warning: EFI system table major version mismatch: "
+ "got %d.%02d, expected %d.%02d\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff,
+ EFI_SYSTEM_TABLE_REVISION >> 16,
+ EFI_SYSTEM_TABLE_REVISION & 0xffff);
+ /*
+ * Grab some details from the system table
+ */
+ config_tables = (efi_config_table_t *)efi.systab->tables;
+ runtime = efi.systab->runtime;
+
+ /*
+ * Show what we know for posterity
+ */
+ c16 = (efi_char16_t *) early_ioremap(efi.systab->fw_vendor, 2);
+ if (!probe_kernel_address(c16, i)) {
+ for (i = 0; i < sizeof(vendor) && *c16; ++i)
+ vendor[i] = *c16++;
+ vendor[i] = '\0';
+ }
+
+ printk(KERN_INFO PFX "EFI v%u.%.02u by %s \n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff, vendor);
+
+ /*
+ * Let's see what config tables the firmware passed to us.
+ */
+ config_tables = (efi_config_table_t *)early_ioremap( efi.systab->tables,
+ efi.systab->nr_tables * sizeof(efi_config_table_t));
+ if (config_tables == NULL)
+ printk(KERN_ERR PFX "Could not map EFI Configuration Table!\n");
+
+ for (i = 0; i < efi.systab->nr_tables; i++) {
+ if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
+ efi.mps = config_tables[i].table;
+ printk(KERN_INFO " MPS=0x%lx ", config_tables[i].table);
+ } else
+ if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
+ efi.acpi20 = config_tables[i].table;
+ printk(KERN_INFO " ACPI 2.0=0x%lx ", config_tables[i].table);
+ } else
+ if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
+ efi.acpi = config_tables[i].table;
+ printk(KERN_INFO " ACPI=0x%lx ", config_tables[i].table);
+ } else
+ if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
+ efi.smbios = config_tables[i].table;
+ printk(KERN_INFO " SMBIOS=0x%lx ", config_tables[i].table);
+ } else
+ if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
+ efi.hcdp = config_tables[i].table;
+ printk(KERN_INFO " HCDP=0x%lx ", config_tables[i].table);
+ } else
+ if (efi_guidcmp(config_tables[i].guid, UGA_IO_PROTOCOL_GUID) == 0) {
+ efi.uga = config_tables[i].table;
+ printk(KERN_INFO " UGA=0x%lx ", config_tables[i].table);
+ }
+ }
+ printk(KERN_INFO "\n");
+
+ /*
+ * Check out the runtime services table. We need to map
+ * the runtime services table so that we can grab the physical
+ * address of several of the EFI runtime functions, needed to
+ * set the firmware into virtual mode.
+ */
+ runtime = (efi_runtime_services_t *) early_ioremap((unsigned long)
+ efi.systab->runtime,
+ sizeof(efi_runtime_services_t));
+ if (runtime != NULL) {
+ /*
+ * We will only need *early* access to the following
+ * two EFI runtime services before set_virtual_address_map
+ * is invoked.
+ */
+ efi_phys.get_time = (efi_get_time_t *) runtime->get_time;
+ efi_phys.set_virtual_address_map =
+ (efi_set_virtual_address_map_t *)runtime->set_virtual_address_map;
+ } else
+ printk(KERN_ERR PFX "Could not map the runtime service table!\n");
+ /* Map the EFI memory map for use until paging_init() */
+ memmap.map = (efi_memory_desc_t *) early_ioremap(
+ (unsigned long) EFI_MEMMAP,
+ EFI_MEMMAP_SIZE);
+ if (memmap.map == NULL)
+ printk(KERN_ERR PFX "Could not map the EFI memory map!\n");
+ if (EFI_MEMDESC_SIZE != sizeof(efi_memory_desc_t)) {
+ printk(KERN_WARNING PFX "Kernel-defined memdesc"
+ "doesn't match the one from EFI!\n");
+ }
+ memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+ /* Override the emergency restart function */
+ machine_emergency_restart_func = efi_emergency_restart;
+}
+
+/*
+ * This function will switch the EFI runtime services to virtual mode.
+ * Essentially, look through the EFI memmap and map every region that
+ * has the runtime attribute bit set in its memory descriptor and update
+ * that memory descriptor with the virtual address obtained from ioremap().
+ * This enables the runtime services to be called without having to
+ * thunk back into physical mode for every invocation.
+ */
+void __init efi_enter_virtual_mode(void)
+{
+ efi_memory_desc_t *md;
+ efi_status_t status;
+ unsigned long end;
+ void *p;
+
+ efi.systab = NULL;
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
+ if (!(md->attribute & EFI_MEMORY_RUNTIME))
+ continue;
+ if (md->attribute & EFI_MEMORY_WB)
+ md->virt_addr = (unsigned long)__va(md->phys_addr);
+ else if (md->attribute & (EFI_MEMORY_UC | EFI_MEMORY_WC))
+ md->virt_addr = (unsigned long)ioremap(md->phys_addr,
+ md->num_pages << EFI_PAGE_SHIFT);
+ end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+ if ((md->phys_addr <= (unsigned long)efi_phys.systab) &&
+ ((unsigned long)efi_phys.systab < end))
+ efi.systab = (efi_system_table_t *)
+ (md->virt_addr - md->phys_addr +
+ (unsigned long)efi_phys.systab);
+ }
+
+ if (!efi.systab)
+ BUG();
+
+ status = phys_efi_set_virtual_address_map(
+ memmap.desc_size * memmap.nr_map,
+ memmap.desc_size,
+ memmap.desc_version,
+ memmap.phys_map);
+
+ if (status != EFI_SUCCESS) {
+ printk (KERN_ALERT "You are screwed! "
+ "Unable to switch EFI into virtual mode "
+ "(status=%lx)\n", status);
+ panic("EFI call to SetVirtualAddressMap() failed!");
+ }
+ /*
+ * Now that EFI is in virtual mode, update the function
+ * pointers in the runtime service table to the new virtual addresses.
+ *
+ * Call EFI services through wrapper functions.
+ */
+
+ efi.get_time = (efi_get_time_t *)_efi_get_time;
+ efi.set_time = (efi_set_time_t *)_efi_set_time;
+ efi.get_wakeup_time = (efi_get_wakeup_time_t *)_efi_get_wakeup_time;
+ efi.set_wakeup_time = (efi_set_wakeup_time_t *)_efi_set_wakeup_time;
+ efi.get_variable = (efi_get_variable_t *)_efi_get_variable;
+ efi.get_next_variable = (efi_get_next_variable_t *)_efi_get_next_variable;
+ efi.set_variable = (efi_set_variable_t *)_efi_set_variable;
+ efi.get_next_high_mono_count = (efi_get_next_high_mono_count_t *)
+ _efi_get_next_high_mono_count;
+ efi.reset_system = (efi_reset_system_t *)_efi_reset_system;
+ efi.set_virtual_address_map = (efi_set_virtual_address_map_t *)
+ _efi_set_virtual_address_map;
+}
+
+/*
+ * Convenience functions to obtain memory types and attributes
+ */
+u32 efi_mem_type(unsigned long phys_addr)
+{
+ efi_memory_desc_t *md;
+ void *p;
+
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
+ if ((md->phys_addr <= phys_addr) && (phys_addr <
+ (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) ))
+ return md->type;
+ }
+ return 0;
+}
+
+u64 efi_mem_attributes(unsigned long phys_addr)
+{
+ efi_memory_desc_t *md;
+ void *p;
+
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
+ if ((md->phys_addr <= phys_addr) && (phys_addr <
+ (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT))))
+ return md->attribute;
+ }
+ return 0;
+}
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/efi_callwrap.c linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/efi_callwrap.c
--- linux-2.6.21-orig/arch/x86_64/kernel/efi_callwrap.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/efi_callwrap.c 2007-06-25 14:36:32.000000000 -0700
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2006 Giridhar Pemmasani
+ * Copyright (C) 2007-2010 Intel Corp
+ * Contributed by Chandramouli Narayanan<mouli@linux.intel.com>
+ * Adapted NDIS wrapper macros from http://ndiswrapper.sourceforge.net
+ * for EFI x86_64 linux support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/spinlock.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/efi.h>
+
+#define alloc_win_stack_frame(argc) \
+ "subq $" #argc "*8, %%rsp\n\t"
+#define free_win_stack_frame(argc) \
+ "addq $" #argc "*8, %%rsp\n\t"
+
+/* m is index of Windows arg required, n is total number of args to
+ * function Windows arg 1 should be at 0(%rsp), arg 2 at 8(%rsp) and
+ * so on, after stack frame is allocated, which starts at -n*8(%rsp)
+ * when stack frame is allocated. 4 > m >= n.
+*/
+
+#define lin2win_win_arg(m,n) "(" #m "-1-" #n ")*8(%%rsp)"
+
+/* volatile args for Windows function must be in clobber / output list */
+
+efi_status_t LIN2WIN0(void *func)
+{
+ u64 ret, dummy;
+ register u64 r8 __asm__("r8");
+ register u64 r9 __asm__("r9");
+ register u64 r10 __asm__("r10");
+ register u64 r11 __asm__("r11");
+ __asm__ __volatile__(
+ alloc_win_stack_frame(4)
+ "call *%[fptr]\n\t"
+ free_win_stack_frame(4)
+ : "=a" (ret), "=c" (dummy), "=d" (dummy),
+ "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+ : [fptr] "r" (func));
+ return ret;
+}
+
+efi_status_t LIN2WIN1(void *func, u64 arg1)
+{
+ u64 ret, dummy;
+ register u64 r8 __asm__("r8");
+ register u64 r9 __asm__("r9");
+ register u64 r10 __asm__("r10");
+ register u64 r11 __asm__("r11");
+ __asm__ __volatile__(
+ alloc_win_stack_frame(4)
+ "call *%[fptr]\n\t"
+ free_win_stack_frame(4)
+ : "=a" (ret), "=c" (dummy), "=d" (dummy),
+ "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+ : "c" (arg1),
+ [fptr] "r" (func));
+ return ret;
+}
+
+efi_status_t LIN2WIN2(void *func, u64 arg1, u64 arg2)
+{
+ u64 ret, dummy;
+ register u64 r8 __asm__("r8");
+ register u64 r9 __asm__("r9");
+ register u64 r10 __asm__("r10");
+ register u64 r11 __asm__("r11");
+ __asm__ __volatile__(
+ alloc_win_stack_frame(4)
+ "call *%[fptr]\n\t"
+ free_win_stack_frame(4)
+ : "=a" (ret), "=c" (dummy), "=d" (dummy),
+ "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+ : "c" (arg1), "d" (arg2),
+ [fptr] "r" (func));
+ return ret;
+}
+
+efi_status_t LIN2WIN3(
+ void *func,
+ u64 arg1,
+ u64 arg2,
+ u64 arg3)
+{
+ u64 ret, dummy;
+ register u64 r8 __asm__("r8") = (u64)arg3;
+ register u64 r9 __asm__("r9");
+ register u64 r10 __asm__("r10");
+ register u64 r11 __asm__("r11");
+ __asm__ __volatile__(
+ alloc_win_stack_frame(4)
+ "call *%[fptr]\n\t"
+ free_win_stack_frame(4)
+ : "=a" (ret), "=c" (dummy), "=d" (dummy),
+ "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+ : "c" (arg1), "d" (arg2), "r" (r8),
+ [fptr] "r" (func));
+ return ret;
+}
+
+efi_status_t LIN2WIN4(
+ void *func,
+ u64 arg1,
+ u64 arg2,
+ u64 arg3,
+ u64 arg4)
+{
+ u64 ret, dummy;
+ register u64 r8 __asm__("r8") = (u64)arg3;
+ register u64 r9 __asm__("r9") = (u64)arg4;
+ register u64 r10 __asm__("r10");
+ register u64 r11 __asm__("r11");
+ __asm__ __volatile__(
+ alloc_win_stack_frame(4)
+ "call *%[fptr]\n\t"
+ free_win_stack_frame(4)
+ : "=a" (ret), "=c" (dummy), "=d" (dummy),
+ "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+ : "c" (arg1), "d" (arg2), "r" (r8), "r" (r9),
+ [fptr] "r" (func));
+ return ret;
+}
+
+efi_status_t LIN2WIN5(
+ void *func,
+ u64 arg1,
+ u64 arg2,
+ u64 arg3,
+ u64 arg4,
+ u64 arg5)
+{
+ u64 ret, dummy;
+ register u64 r8 __asm__("r8") = (u64)arg3;
+ register u64 r9 __asm__("r9") = (u64)arg4;
+ register u64 r10 __asm__("r10");
+ register u64 r11 __asm__("r11");
+ __asm__ __volatile__(
+ "mov %[rarg5], " lin2win_win_arg(5,6) "\n\t"
+ alloc_win_stack_frame(6)
+ "call *%[fptr]\n\t"
+ free_win_stack_frame(6)
+ : "=a" (ret), "=c" (dummy), "=d" (dummy),
+ "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+ : "c" (arg1), "d" (arg2), "r" (r8), "r" (r9),
+ [rarg5] "r" ((unsigned long long)arg5),
+ [fptr] "r" (func));
+ return ret;
+}
+
+efi_status_t LIN2WIN6(
+ void *func,
+ u64 arg1,
+ u64 arg2,
+ u64 arg3,
+ u64 arg4,
+ u64 arg5,
+ u64 arg6)
+{
+ u64 ret, dummy;
+ register u64 r8 __asm__("r8") = (u64)arg3;
+ register u64 r9 __asm__("r9") = (u64)arg4;
+ register u64 r10 __asm__("r10");
+ register u64 r11 __asm__("r11");
+ __asm__ __volatile__(
+ "movq %[rarg5], " lin2win_win_arg(5,6) "\n\t"
+ "movq %[rarg6], " lin2win_win_arg(6,6) "\n\t"
+ alloc_win_stack_frame(6)
+ "call *%[fptr]\n\t"
+ free_win_stack_frame(6)
+ : "=a" (ret), "=c" (dummy), "=d" (dummy),
+ "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+ : "c" (arg1), "d" (arg2), "r" (r8), "r" (r9),
+ [rarg5] "r" ((u64)arg5), [rarg6] "r" ((u64)arg6),
+ [fptr] "r" (func));
+ return ret;
+}
+EXPORT_SYMBOL_GPL(LIN2WIN0);
+EXPORT_SYMBOL_GPL(LIN2WIN1);
+EXPORT_SYMBOL_GPL(LIN2WIN2);
+EXPORT_SYMBOL_GPL(LIN2WIN3);
+EXPORT_SYMBOL_GPL(LIN2WIN4);
+EXPORT_SYMBOL_GPL(LIN2WIN5);
+EXPORT_SYMBOL_GPL(LIN2WIN6);
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/head.S linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/head.S
--- linux-2.6.21-orig/arch/x86_64/kernel/head.S 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/head.S 2007-06-26 16:19:42.000000000 -0700
@@ -100,6 +100,23 @@ startup_32:
.org 0x100
.globl startup_64
startup_64:
+ /*
+ * At this point the CPU runs in long64 bit with
+ * paging disabled. First of all, need to load new DS, GDT, and CS.
+ * There is no stack until we set one up.
+ */
+
+ /* Initialize the %ds segment register */
+ mov $__KERNEL_DS,%eax
+ mov %eax,%ds
+
+ /* Load new GDT and CS. At this point, BP is in physical mode. */
+ lgdt cpu_gdt_descr_phys-__START_KERNEL_map
+
+ mov $(ljumpvector64 - __START_KERNEL_map), %rax
+ ljmp *(%rax)
+long64:
+
/* We come here either from startup_32
* or directly from a 64bit bootloader.
* Since we may have come directly from a bootloader we
@@ -357,6 +374,16 @@ gdt:
.endr
#endif
+ .align 16
+ .globl cpu_gdt_descr_phys
+cpu_gdt_descr_phys:
+ .word gdt_end-cpu_gdt_table-1
+gdt_phys:
+ .quad cpu_gdt_table-__START_KERNEL_map
+ljumpvector64:
+ .long long64-__START_KERNEL_map
+ .word __KERNEL_CS
+
/* We need valid kernel segments for data and code in long mode too
* IRET will check the segment types kkeil 2000/10/28
* Also sysret mandates a special GDT layout
--
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2.6.21 2/3] x86_64 EFI64 support Try #2
2007-07-02 17:06 [PATCH 2.6.21 0/3] x86_64 EFI64 support Try #2 Chandramouli Narayanan
2007-07-02 17:06 ` [PATCH 2.6.21 1/3] " Chandramouli Narayanan
@ 2007-07-02 17:06 ` Chandramouli Narayanan
2007-07-03 23:27 ` Andrew Morton
2007-07-02 17:06 ` [PATCH 2.6.21 3/3] " Chandramouli Narayanan
2 siblings, 1 reply; 9+ messages in thread
From: Chandramouli Narayanan @ 2007-07-02 17:06 UTC (permalink / raw)
To: linux-kernel; +Cc: ak, akpm
[-- Attachment #1: patch2 --]
[-- Type: text/plain, Size: 10422 bytes --]
EFI x86_64 support Patch 2 of 3 (try #2)
----------------------------------------
- E820 conversion integration implemented
- A way to override machine_emergency_restart is implemented so that
EFI support can provide its own implementation.
- The variable efi_enabled is still retained as it is used across
archictures with CONFIG_EFI option.
Signed-off-by: Chandramouli Narayanan <mouli@linux.intel.com>
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/aperture.c linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/aperture.c
--- linux-2.6.21-orig/arch/x86_64/kernel/aperture.c 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/aperture.c 2007-06-25 13:59:54.000000000 -0700
@@ -95,6 +95,10 @@ static int __init aperture_valid(u64 ape
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;
}
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/e820.c linux-2.6.21-uefi64-finaltest4/arch/x86_64/kernel/e820.c
--- linux-2.6.21-orig/arch/x86_64/kernel/e820.c 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi64-finaltest4/arch/x86_64/kernel/e820.c 2007-06-29 15:20:37.000000000 -0700
@@ -17,6 +17,7 @@
#include <linux/kexec.h>
#include <linux/module.h>
#include <linux/mm.h>
+#include <linux/efi.h>
#include <asm/pgtable.h>
#include <asm/page.h>
@@ -234,6 +235,7 @@ void __init e820_reserve_resources(void)
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;
@@ -383,6 +385,9 @@ void __init e820_print_map(char *who)
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;
}
@@ -601,6 +606,8 @@ void __init setup_memory_region(void)
* Otherwise fake a memory map; one section from 0k->640k,
* the next section from 1mb->appropriate_mem_k
*/
+ if (efi_enabled)
+ efi_init();
sanitize_e820_map(E820_MAP, &E820_MAP_NR);
if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0)
early_panic("Cannot find a valid memory map");
@@ -664,7 +671,7 @@ early_param("memmap", parse_memmap_opt);
void __init finish_e820_parsing(void)
{
- if (userdef) {
+ if (userdef && !efi_enabled) {
printk(KERN_INFO "user-defined physical RAM map:\n");
e820_print_map("user");
}
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/reboot.c linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/reboot.c
--- linux-2.6.21-orig/arch/x86_64/kernel/reboot.c 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/reboot.c 2007-06-26 13:03:52.000000000 -0700
@@ -7,6 +7,7 @@
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/pm.h>
+#include <linux/efi.h>
#include <asm/io.h>
#include <asm/kdebug.h>
#include <asm/delay.h>
@@ -22,6 +23,14 @@
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
+/* machine_emergency_restart_func is set to the restart implementation here.
+ * The variable provides a way for overriding the implementation.
+ * For example, EFI initialization could set up an emergency restart
+ * function hiding its implementation from here.
+ */
+void (*machine_emergency_restart_func)(void) = machine_emergency_restart;
+EXPORT_SYMBOL(machine_emergency_restart_func);
+
static long no_idt[3];
static enum {
BOOT_TRIPLE = 't',
@@ -147,7 +156,7 @@ void machine_restart(char * __unused)
if (!reboot_force) {
machine_shutdown();
}
- machine_emergency_restart();
+ machine_emergency_restart_func();
}
void machine_halt(void)
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/setup.c linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/setup.c
--- linux-2.6.21-orig/arch/x86_64/kernel/setup.c 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/setup.c 2007-06-21 17:36:47.000000000 -0700
@@ -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 = 0;
+EXPORT_SYMBOL(efi_enabled);
+#endif
struct cpuinfo_x86 boot_cpu_data __read_mostly;
EXPORT_SYMBOL(boot_cpu_data);
@@ -234,6 +239,10 @@ void __init setup_arch(char **cmdline_p)
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;
+#endif
setup_memory_region();
copy_edd();
@@ -271,6 +280,8 @@ void __init setup_arch(char **cmdline_p)
discover_ebda();
init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
+ if (efi_enabled)
+ efi_map_memmap();
dmi_scan_machine();
@@ -418,7 +429,8 @@ void __init setup_arch(char **cmdline_p)
#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
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/time.c linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/time.c
--- linux-2.6.21-orig/arch/x86_64/kernel/time.c 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/time.c 2007-06-12 16:16:12.000000000 -0700
@@ -27,6 +27,7 @@
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/kallsyms.h>
+#include <linux/efi.h>
#include <linux/acpi.h>
#ifdef CONFIG_ACPI
#include <acpi/achware.h> /* for PM timer frequency */
@@ -92,6 +93,11 @@ static void set_rtc_mmss(unsigned long n
*/
spin_lock(&rtc_lock);
+ if (efi_enabled) {
+ efi_set_rtc_mmss(nowtime);
+ spin_unlock(&rtc_lock);
+ return;
+ }
/*
* Tell the clock it's being set and stop it.
@@ -204,10 +210,15 @@ static irqreturn_t timer_interrupt(int i
static unsigned long get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
- unsigned long flags;
+ unsigned long flags, retval;
unsigned century = 0;
spin_lock_irqsave(&rtc_lock, flags);
+ if (efi_enabled) {
+ retval = efi_get_time();
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return retval;
+ }
do {
sec = CMOS_READ(RTC_SECONDS);
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/mm/init.c linux-2.6.21-uefi64-finaltest4/arch/x86_64/mm/init.c
--- linux-2.6.21-orig/arch/x86_64/mm/init.c 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi64-finaltest4/arch/x86_64/mm/init.c 2007-06-27 17:30:46.000000000 -0700
@@ -26,6 +26,7 @@
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/memory_hotplug.h>
+#include <linux/efi.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -50,6 +51,8 @@ struct dma_mapping_ops* dma_ops;
EXPORT_SYMBOL(dma_ops);
static unsigned long dma_reserve __initdata;
+/* Flag indicating EFI runtime executable code area */
+static int efi_runtime_code_area = 0;
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -89,6 +92,7 @@ void show_mem(void)
}
int after_bootmem;
+EXPORT_SYMBOL(after_bootmem);
static __init void *spp_getpage(void)
{
@@ -214,7 +218,7 @@ static __meminit void unmap_low_page(int
{
struct temp_map *ti;
- if (after_bootmem)
+ if (after_bootmem || efi_runtime_code_area)
return;
ti = &temp_mappings[i];
@@ -258,16 +262,19 @@ phys_pmd_init(pmd_t *pmd_page, unsigned
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 +303,8 @@ static void __meminit phys_pud_init(pud_
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 +351,8 @@ static void __init find_early_table_spac
/* 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 +365,8 @@ void __meminit init_memory_mapping(unsig
* 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);
@@ -369,7 +378,7 @@ void __meminit init_memory_mapping(unsig
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(&map, &pud_phys);
@@ -378,7 +387,7 @@ void __meminit init_memory_mapping(unsig
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(map);
}
--
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2.6.21 3/3] x86_64 EFI64 support Try #2
2007-07-02 17:06 [PATCH 2.6.21 0/3] x86_64 EFI64 support Try #2 Chandramouli Narayanan
2007-07-02 17:06 ` [PATCH 2.6.21 1/3] " Chandramouli Narayanan
2007-07-02 17:06 ` [PATCH 2.6.21 2/3] " Chandramouli Narayanan
@ 2007-07-02 17:06 ` Chandramouli Narayanan
2007-07-03 23:31 ` Andrew Morton
2 siblings, 1 reply; 9+ messages in thread
From: Chandramouli Narayanan @ 2007-07-02 17:06 UTC (permalink / raw)
To: linux-kernel; +Cc: ak, akpm
[-- Attachment #1: patch3 --]
[-- Type: text/plain, Size: 10816 bytes --]
EFI x86_64 support Patch 3 of 3 (try #2)
----------------------------------------
- Fixed redundant check in efifb_init().
This patch depends on the EFI x86_64 patches 1/3 and 2/3.
This patch adds Graphics Output Protocol support to the kernel.
x86_64 systems with UEFI2.0 firmware conform to UEFI 2.0 specification.
UEFI2.0 spec deprecates Universal Graphics Adapter (UGA) protocol and
only Graphics Output Protocol (GOP) is produced. Therefore, the boot loader
needs to query the UEFI firmware with appropriate Output Protocol and
pass the video information to the kernel. As a result of GOP
protocol, an EFI framebuffer driver is needed for displaying console messages.
Patch 3 of 3 adds a EFI framebuffer driver. The EFI frame buffer driver in this
patch is based on the Intel Mac framebuffer driver.
The x86_64 ELILO bootloader takes care of passing the video information
as appropriate for EFI firmware.
Signed-off-by: Chandramouli Narayanan <mouli@linux.intel.com>
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/include/linux/screen_info.h linux-2.6.21-uefi-finaltest4/include/linux/screen_info.h
--- linux-2.6.21-orig/include/linux/screen_info.h 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/include/linux/screen_info.h 2007-06-12 16:16:12.000000000 -0700
@@ -63,6 +63,7 @@ extern struct screen_info screen_info;
#define VIDEO_TYPE_EGAC 0x21 /* EGA in Color Mode */
#define VIDEO_TYPE_VGAC 0x22 /* VGA+ in Color Mode */
#define VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */
+#define VIDEO_TYPE_EFI 0x24 /* EFI graphic mode */
#define VIDEO_TYPE_PICA_S3 0x30 /* ACER PICA-61 local S3 video */
#define VIDEO_TYPE_MIPS_G364 0x31 /* MIPS Magnum 4000 G364 video */
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/drivers/video/Kconfig linux-2.6.21-uefi-finaltest4/drivers/video/Kconfig
--- linux-2.6.21-orig/drivers/video/Kconfig 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/drivers/video/Kconfig 2007-06-12 16:16:12.000000000 -0700
@@ -539,6 +539,17 @@ config FB_VESA
You will get a boot time penguin logo at no additional cost. Please
read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
+config FB_EFI
+ bool "EFI-based Framebuffer Support"
+ depends on (FB = y) && X86 && EFI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This is the EFI frame buffer device driver. If the firmware on
+ your platform is UEFI2.0, select Y to add support for
+ Graphics Output Protocol for early console messages to appear.
+
config FB_IMAC
bool "Intel-based Macintosh Framebuffer Support"
depends on (FB = y) && X86 && EFI
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/drivers/video/Makefile linux-2.6.21-uefi-finaltest4/drivers/video/Makefile
--- linux-2.6.21-orig/drivers/video/Makefile 2007-04-25 20:08:32.000000000 -0700
+++ linux-2.6.21-uefi-finaltest4/drivers/video/Makefile 2007-06-12 16:16:12.000000000 -0700
@@ -103,6 +103,7 @@ obj-$(CONFIG_FB_SM501) += sm5
# Platform or fallback drivers go here
obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_IMAC) += imacfb.o
+obj-$(CONFIG_FB_EFI) += efifb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o
obj-$(CONFIG_FB_OF) += offb.o
diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/drivers/video/efifb.c linux-2.6.21-uefi-finaltest4/drivers/video/efifb.c
--- linux-2.6.21-orig/drivers/video/efifb.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.21-uefi-finaltest4/drivers/video/efifb.c 2007-06-12 16:16:12.000000000 -0700
@@ -0,0 +1,249 @@
+/*
+ * framebuffer driver for Intel Based Mac's
+ *
+ * (c) 2006 Edgar Hucek <gimli@dark-green.com>
+ * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/dmi.h>
+#include <linux/efi.h>
+
+#include <asm/io.h>
+
+#include <video/vga.h>
+
+static struct fb_var_screeninfo efifb_defined __initdata = {
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+ .width = -1,
+ .right_margin = 32,
+ .upper_margin = 16,
+ .lower_margin = 4,
+ .vsync_len = 4,
+ .vmode = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo efifb_fix __initdata = {
+ .id = "EFI VGA",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .accel = FB_ACCEL_NONE,
+ .visual = FB_VISUAL_TRUECOLOR,
+};
+
+static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ /*
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure). Return
+ * != 0 for invalid regno.
+ */
+
+ if (regno >= info->cmap.len)
+ return 1;
+
+ if (regno < 16) {
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ ((u32 *)(info->pseudo_palette))[regno] =
+ (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ }
+ return 0;
+}
+
+static struct fb_ops efifb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = efifb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int __init efifb_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ int err;
+ unsigned int size_vmode;
+ unsigned int size_remap;
+ unsigned int size_total;
+
+ efifb_fix.smem_start = screen_info.lfb_base;
+ efifb_defined.bits_per_pixel = screen_info.lfb_depth;
+ efifb_defined.xres = screen_info.lfb_width;
+ efifb_defined.yres = screen_info.lfb_height;
+ efifb_fix.line_length = screen_info.lfb_linelength;
+
+ /* size_vmode -- that is the amount of memory needed for the
+ * used video mode, i.e. the minimum amount of
+ * memory we need. */
+ size_vmode = efifb_defined.yres * efifb_fix.line_length;
+
+ /* size_total -- all video memory we have. Used for
+ * entries, ressource allocation and bounds
+ * checking. */
+ //size_total = screen_info.lfb_size * 65536;
+ size_total = screen_info.lfb_size;
+ if (size_total < size_vmode)
+ size_total = size_vmode;
+
+ /* size_remap -- the amount of video memory we are going to
+ * use for efifb. With modern cards it is no
+ * option to simply use size_total as that
+ * wastes plenty of kernel address space. */
+ size_remap = size_vmode * 2;
+ if (size_remap < size_vmode)
+ size_remap = size_vmode;
+ if (size_remap > size_total)
+ size_remap = size_total;
+ efifb_fix.smem_len = size_remap;
+
+#ifndef __i386__
+ //screen_info.imacpm_seg = 0;
+#endif
+
+ if (!request_mem_region(efifb_fix.smem_start, size_total, "efifb")) {
+ printk(KERN_WARNING
+ "efifb: cannot reserve video memory at 0x%lx\n",
+ efifb_fix.smem_start);
+ /* We cannot make this fatal. Sometimes this comes from magic
+ spaces our resource handlers simply don't know about */
+ }
+
+ info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+ if (!info) {
+ err = -ENOMEM;
+ goto err_release_mem;
+ }
+ info->pseudo_palette = info->par;
+ info->par = NULL;
+
+ info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
+ if (!info->screen_base) {
+ printk(KERN_ERR "efifb: abort, cannot ioremap video memory "
+ "0x%x @ 0x%lx\n",
+ efifb_fix.smem_len, efifb_fix.smem_start);
+ err = -EIO;
+ goto err_unmap;
+ }
+
+ printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, "
+ "using %dk, total %dk\n",
+ efifb_fix.smem_start, info->screen_base,
+ size_remap/1024, size_total/1024);
+ printk(KERN_INFO "efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+ efifb_defined.xres, efifb_defined.yres,
+ efifb_defined.bits_per_pixel, efifb_fix.line_length,
+ screen_info.pages);
+
+ efifb_defined.xres_virtual = efifb_defined.xres;
+ efifb_defined.yres_virtual = efifb_fix.smem_len /
+ efifb_fix.line_length;
+ printk(KERN_INFO "efifb: scrolling: redraw\n");
+ efifb_defined.yres_virtual = efifb_defined.yres;
+
+ /* some dummy values for timing to make fbset happy */
+ efifb_defined.pixclock = 10000000 / efifb_defined.xres *
+ 1000 / efifb_defined.yres;
+ efifb_defined.left_margin = (efifb_defined.xres / 8) & 0xf8;
+ efifb_defined.hsync_len = (efifb_defined.xres / 8) & 0xf8;
+
+ efifb_defined.red.offset = screen_info.red_pos;
+ efifb_defined.red.length = screen_info.red_size;
+ efifb_defined.green.offset = screen_info.green_pos;
+ efifb_defined.green.length = screen_info.green_size;
+ efifb_defined.blue.offset = screen_info.blue_pos;
+ efifb_defined.blue.length = screen_info.blue_size;
+ efifb_defined.transp.offset = screen_info.rsvd_pos;
+ efifb_defined.transp.length = screen_info.rsvd_size;
+
+ printk(KERN_INFO "efifb: %s: "
+ "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+ "Truecolor",
+ screen_info.rsvd_size,
+ screen_info.red_size,
+ screen_info.green_size,
+ screen_info.blue_size,
+ screen_info.rsvd_pos,
+ screen_info.red_pos,
+ screen_info.green_pos,
+ screen_info.blue_pos);
+
+ efifb_fix.ypanstep = 0;
+ efifb_fix.ywrapstep = 0;
+
+ info->fbops = &efifb_ops;
+ info->var = efifb_defined;
+ info->fix = efifb_fix;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ err = -ENOMEM;
+ goto err_unmap;
+ }
+ if (register_framebuffer(info)<0) {
+ err = -EINVAL;
+ goto err_fb_dealoc;
+ }
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+ return 0;
+
+err_fb_dealoc:
+ fb_dealloc_cmap(&info->cmap);
+err_unmap:
+ iounmap(info->screen_base);
+ framebuffer_release(info);
+err_release_mem:
+ release_mem_region(efifb_fix.smem_start, size_total);
+ return err;
+}
+
+static struct platform_driver efifb_driver = {
+ .probe = efifb_probe,
+ .driver = {
+ .name = "efifb",
+ },
+};
+
+static struct platform_device efifb_device = {
+ .name = "efifb",
+};
+
+static int __init efifb_init(void)
+{
+ int ret;
+
+ if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
+ return -ENODEV;
+
+
+ ret = platform_driver_register(&efifb_driver);
+
+ if (!ret) {
+ ret = platform_device_register(&efifb_device);
+ if (ret)
+ platform_driver_unregister(&efifb_driver);
+ }
+ return ret;
+}
+module_init(efifb_init);
+
+MODULE_LICENSE("GPL");
--
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2.6.21 1/3] x86_64 EFI64 support Try #2
2007-07-02 17:06 ` [PATCH 2.6.21 1/3] " Chandramouli Narayanan
@ 2007-07-03 23:25 ` Andrew Morton
2007-07-04 21:40 ` Huang, Ying
0 siblings, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2007-07-03 23:25 UTC (permalink / raw)
To: Chandramouli Narayanan; +Cc: linux-kernel, ak
On Mon, 02 Jul 2007 10:06:15 -0700
Chandramouli Narayanan <mouli@linux.intel.com> wrote:
>
You just sent three patches, all with the same name. Please take care to
choose different and good Subject:s for each patch.
http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt covers this a bit.
> EFI x86_64 support Patch 1 of 3 (try #2)
> ----------------------------------------
> - Being experimental, dropped default option for CONFIG_EFI.
>
> - Implemented EFI to E820 memory map conversion. This is based on
> bootloader support. The ELILO bootloader x86_64 support has been
> updated to pass E820 map to kernel. This simplified kernel efi code.
> Also the duplicate code for setting up page table for
> EFI run time is gotten rid of with simpler patch.
>
> ------------------------------------------------------------------
> NOTE: The ELILO patch to perform EFI to E820 map conversion is being
> submitted to sourceforge project maintainer.
> ------------------------------------------------------------------
>
> - UEFI wrapper code in earlier patch is now replaced with code adapted from
> NDIS wrapper sourceforge project.
>
> - Parameters in EFI calls are cast to (u64) to rid build warnings.
>
> - Code that is supposed to be __init only in arch/x86_64/kernel/efi.c
> is prefixed as such.
>
> - Documentation/x86_64/uefi.txt adds instructions on how to set up EFI64
> system.
>
> - Documentation/i386/zero-page.txt notes differences in the boot parameters
> for x86_64. The efi init code uses these parameters passed by the bootloader.
>
> - Added missing KERN_ prefixes in EFI code. probe_kernel_address() used for
> checking firmware vendor in efi init code.
>
> - The dependency on X86_64 in the configuration of EFI_RTC is dropped
> since we have hardware realtime clock support
>
> Issues _not_ addressed (per feedback from Eric Biederman)
>
> - Virtual mode support is still retained in this patch. On looking at the
> configuration options, the EFI variable support is required at runtime.
> For instance, the firmware driver configuration support with EFI variable
> via sysfs would require this. I'm not sure if virtual mode support
> can be killed altogether. More investigation needed here.
>
> - The variable efi_enabled is used throughout across architecutres if
> CONFIG_EFI option is enabled. The i386 code also uses this variable.
> This is something that can be revisited with code consolidation across
> architectures.
>
> Signed-off-by: Chandramouli Narayanan <mouli@linux.intel.com>
All the above text tells us the differences between. v2 and v3. It all
will be of minimal interest for the final got commit and hence it will be
removed (by me, typically).
That will leave us with no cvhangelog for this patch.
Please provide a changelog with this patch. The above-linked-to document
has some guidelines.
Please feed these patches through the latest version of
scripts/checkpatch.pl and consider addressing the resulting warnings. Many
are generated.
> + * Copyright (C) 2006 Giridhar Pemmasani
> + * Copyright (C) 2007-2010 Intel Corp
> + * Contributed by Chandramouli Narayanan<mouli@linux.intel.com>
> + * Adapted NDIS wrapper macros from http://ndiswrapper.sourceforge.net
> + * for EFI x86_64 linux support
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +extern efi_status_t LIN2WIN0(void *fp);
> +extern efi_status_t LIN2WIN1(void *fp, u64 arg1);
> +extern efi_status_t LIN2WIN2(void *fp, u64 arg1, u64 arg2);
> +extern efi_status_t LIN2WIN3(void *fp, u64 arg1, u64 arg2, u64 arg3);
> +extern efi_status_t LIN2WIN4(void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4);
> +extern efi_status_t LIN2WIN5(
> + void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5);
> +extern efi_status_t LIN2WIN6(
> + void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6);
Why are these all-upper-case? That convention is conventionally used for
macros.
> --- linux-2.6.21-orig/arch/x86_64/kernel/efi.c 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/efi.c 2007-06-26 14:39:27.000000000 -0700
> @@ -0,0 +1,531 @@
> +/*
> + * Extensible Firmware Interface
> + *
> + * Based on Extensible Firmware Interface Specification version 1.0
> + *
> + * Copyright (C) 1999 VA Linux Systems
> + * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
> + * Copyright (C) 1999-2002 Hewlett-Packard Co.
> + * David Mosberger-Tang <davidm@hpl.hp.com>
> + * Stephane Eranian <eranian@hpl.hp.com>
> + * Copyright (C) 2005-2008 Intel Co.
> + * Fenghua Yu <fenghua.yu@intel.com>
> + * Bibo Mao <bibo.mao@intel.com>
> + * Chandramouli Narayanan <mouli@linux.intel.com>
> + *
> + * Code to convert EFI to E820 map has been implemented in elilo bootloader
> + * based on a EFI patch by Edgar Hucek. Based on the E820 map, the page table
> + * is setup appropriately for EFI runtime code. NDIS wrapper code from
> + * sourceforge project is adapted here for UEFI wrapper call.
> + * - mouli 06/14/2007.
> + *
> + * All EFI Runtime Services are not implemented yet as EFI only
> + * supports physical mode addressing on SoftSDV. This is to be fixed
> + * in a future version. --drummond 1999-07-20
> + *
> + * Implemented EFI runtime services and virtual mode calls. --davidm
> + *
> + * Goutham Rao: <goutham.rao@intel.com>
> + * Skip non-WB memory and ignore empty memory ranges.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/mm.h>
> +#include <linux/types.h>
> +#include <linux/time.h>
> +#include <linux/spinlock.h>
> +#include <linux/bootmem.h>
> +#include <linux/ioport.h>
> +#include <linux/module.h>
> +#include <linux/efi.h>
> +#include <linux/uaccess.h>
> +
> +#include <asm/setup.h>
> +#include <asm/bootsetup.h>
> +#include <asm/io.h>
> +#include <asm/page.h>
> +#include <asm/e820.h>
> +#include <asm/pgtable.h>
> +#include <asm/tlbflush.h>
> +#include <asm/cacheflush.h>
> +#include <asm/proto.h>
> +#include <asm-x86_64/eficallwrap.h>
> +
> +#define EFI_DEBUG 0
> +#define PFX "EFI: "
> +
> +struct efi efi;
> +EXPORT_SYMBOL(efi);
Why is this exported?
> +extern void (*machine_emergency_restart_func)(void);
Never put extern declarations in C files. Find a suitable header and
ensure that the header is included by all code which uses the symbol, as
well as the code which defines it.
> +struct efi efi_phys __initdata;
> +struct efi_memory_map memmap;
> +static efi_system_table_t efi_systab __initdata;
> +
> +static unsigned long efi_rt_eflags;
> +/* efi_rt_lock protects efi physical mode call */
> +static spinlock_t efi_rt_lock = SPIN_LOCK_UNLOCKED;
> +static pgd_t save_pgd;
>
> ...
>
> +static void __init efi_call_phys_prelog(void) __acquires(efi_rt_lock)
> +{
> + unsigned long vaddress;
> +
> + spin_lock(&efi_rt_lock);
> + local_irq_save(efi_rt_eflags);
I suspect the above two statements are in the wrong order.
> + vaddress = (unsigned long)__va(0x0UL);
> + pgd_val(save_pgd) = pgd_val(*pgd_offset_k(0x0UL));
> + set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
> +
> + global_flush_tlb();
> +}
> +
> +static void __init efi_call_phys_epilog(void) __releases(efi_rt_lock)
> +{
> + /*
> + * After the lock is released, the original page table is restored.
> + */
> + set_pgd(pgd_offset_k(0x0UL), save_pgd);
> + global_flush_tlb();
> + local_irq_restore(efi_rt_eflags);
> + spin_unlock(&efi_rt_lock);
Ditto.
> +}
> +
> +static efi_status_t __init phys_efi_set_virtual_address_map(
> + unsigned long memory_map_size,
> + unsigned long descriptor_size,
> + u32 descriptor_version, efi_memory_desc_t *virtual_map)
> +{
> + efi_status_t status;
> +
> + efi_call_phys_prelog();
> + status = LIN2WIN4(efi_phys.set_virtual_address_map,
> + (u64)memory_map_size,
> + (u64)descriptor_size,
> + (u64)descriptor_version,
> + (u64)virtual_map);
> + efi_call_phys_epilog();
> + return status;
> +}
> +
> +static efi_status_t __init phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
> +{
> +
> + efi_status_t status;
> +
> + efi_call_phys_prelog();
> + status = LIN2WIN2(efi_phys.get_time,
> + (u64)tm,
> + (u64)tc);
> + efi_call_phys_epilog();
> + return status;
> +}
> +
> +inline int efi_set_rtc_mmss(unsigned long nowtime)
Remove `inline'.
> +{
> + int real_seconds, real_minutes;
> + efi_status_t status;
> + efi_time_t eft;
> + efi_time_cap_t cap;
> +
> + spin_lock(&efi_rt_lock);
> + status = efi.get_time(&eft, &cap);
> + spin_unlock(&efi_rt_lock);
It is very unusual for any time-related low-level lock to be taken in a
non-irq-safe fashion. Is this code correct?
> + if (status != EFI_SUCCESS) {
> + printk(KERN_ERR PFX "Oops: efitime: can't read time!\n");
> + return -1;
> + }
> +
> + real_seconds = nowtime % 60;
> + real_minutes = nowtime / 60;
> + if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
> + real_minutes += 30;
> + real_minutes %= 60;
> + eft.minute = real_minutes;
> + eft.second = real_seconds;
> +
> + spin_lock(&efi_rt_lock);
> + status = efi.set_time(&eft);
> + spin_unlock(&efi_rt_lock);
> + if (status != EFI_SUCCESS) {
> + printk(KERN_ERR PFX "Oops: efitime: can't write time!\n");
> + return -1;
> + }
> + return 0;
> +}
> +/*
Missing newline.
> + * This is used during kernel init before runtime
> + * services have been remapped and also during suspend, therefore,
> + * we'll need to call both in physical and virtual modes.
> + */
> +inline unsigned long efi_get_time(void)
Remove inline
> +{
> + efi_status_t status;
> + efi_time_t eft;
> + efi_time_cap_t cap;
> +
> + if (efi.get_time) {
> + /* if we are in virtual mode use remapped function */
> + status = efi.get_time(&eft, &cap);
> + } else {
> + /* we are in physical mode */
> + status = phys_efi_get_time(&eft, &cap);
> + }
> + if (status != EFI_SUCCESS)
> + printk(KERN_ERR PFX "Oops: efitime: can't read time status: 0x%lx\n",status);
Missing space, line too long (checkpatch will point these out)
> +
> + return mktime(eft.year, eft.month, eft.day, eft.hour,
> + eft.minute, eft.second);
> +}
> +
> +/*
> + * We need to map the EFI memory map again after paging_init().
> + */
> +void __init efi_map_memmap(void)
> +{
> + int i;
> +
> + memmap.map = __va((unsigned long)memmap.phys_map);
> + memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
> +
> + /* Make EFI runtime code area executable */
> + for (i = 0; i < e820.nr_map; i++) {
> + switch (e820.map[i].type) {
> + case E820_RUNTIME_CODE:
> + init_memory_mapping(
> + e820.map[i].addr,
> + e820.map[i].addr + e820.map[i].size);
> + break;
> + default:
> + break;
> + }
> + }
> +}
> +
> +/* Override function for emergency restart on EFI enabled systems */
> +static void efi_emergency_restart(void)
> +{
> + /* If EFI enabled, reset system through EFI protocol. */
> + efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
> + return;
> +}
> +
> +void __init efi_init(void)
> +{
> + efi_config_table_t *config_tables;
> + efi_runtime_services_t *runtime;
> + efi_char16_t *c16;
> + char vendor[100] = "unknown";
> + int i = 0;
> +
> + memset(&efi, 0, sizeof(efi) );
Rendom extra space
> + memset(&efi_phys, 0, sizeof(efi_phys));
> +
> + efi_phys.systab = (efi_system_table_t *)EFI_SYSTAB;
> + memmap.phys_map = (void*)EFI_MEMMAP;
> + memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE;
> + memmap.desc_version = EFI_MEMDESC_VERSION;
> + memmap.desc_size = EFI_MEMDESC_SIZE;
> +
> + efi.systab = (efi_system_table_t *) early_ioremap(
> + (unsigned long)efi_phys.systab,
> + sizeof(efi_system_table_t));
early_ioremap() returns void*: unneeded cast.
> + memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
> + efi.systab = &efi_systab;
> + /*
> + * Verify the EFI Table
> + */
> + if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
> + printk(KERN_ERR PFX "Woah! EFI system table signature incorrect\n");
> + if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
> + printk(KERN_ERR PFX
> + "Warning: EFI system table major version mismatch: "
> + "got %d.%02d, expected %d.%02d\n",
> + efi.systab->hdr.revision >> 16,
> + efi.systab->hdr.revision & 0xffff,
> + EFI_SYSTEM_TABLE_REVISION >> 16,
> + EFI_SYSTEM_TABLE_REVISION & 0xffff);
> + /*
> + * Grab some details from the system table
> + */
> + config_tables = (efi_config_table_t *)efi.systab->tables;
> + runtime = efi.systab->runtime;
> +
> + /*
> + * Show what we know for posterity
> + */
> + c16 = (efi_char16_t *) early_ioremap(efi.systab->fw_vendor, 2);
Ditto
> + if (!probe_kernel_address(c16, i)) {
> + for (i = 0; i < sizeof(vendor) && *c16; ++i)
> + vendor[i] = *c16++;
> + vendor[i] = '\0';
> + }
> +
> + printk(KERN_INFO PFX "EFI v%u.%.02u by %s \n",
> + efi.systab->hdr.revision >> 16,
> + efi.systab->hdr.revision & 0xffff, vendor);
> +
> + /*
> + * Let's see what config tables the firmware passed to us.
> + */
> + config_tables = (efi_config_table_t *)early_ioremap( efi.systab->tables,
> + efi.systab->nr_tables * sizeof(efi_config_table_t));
> + if (config_tables == NULL)
> + printk(KERN_ERR PFX "Could not map EFI Configuration Table!\n");
> +
> + for (i = 0; i < efi.systab->nr_tables; i++) {
> + if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
> + efi.mps = config_tables[i].table;
> + printk(KERN_INFO " MPS=0x%lx ", config_tables[i].table);
> + } else
> + if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
> + efi.acpi20 = config_tables[i].table;
> + printk(KERN_INFO " ACPI 2.0=0x%lx ", config_tables[i].table);
> + } else
> + if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
> + efi.acpi = config_tables[i].table;
> + printk(KERN_INFO " ACPI=0x%lx ", config_tables[i].table);
> + } else
> + if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
> + efi.smbios = config_tables[i].table;
> + printk(KERN_INFO " SMBIOS=0x%lx ", config_tables[i].table);
> + } else
> + if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
> + efi.hcdp = config_tables[i].table;
> + printk(KERN_INFO " HCDP=0x%lx ", config_tables[i].table);
> + } else
> + if (efi_guidcmp(config_tables[i].guid, UGA_IO_PROTOCOL_GUID) == 0) {
> + efi.uga = config_tables[i].table;
> + printk(KERN_INFO " UGA=0x%lx ", config_tables[i].table);
> + }
> + }
> + printk(KERN_INFO "\n");
The KERN_* is only meaningful at the start of the output line, and this one
is being emitted at the end of the input line. Usually..
> + /*
> + * Check out the runtime services table. We need to map
> + * the runtime services table so that we can grab the physical
> + * address of several of the EFI runtime functions, needed to
> + * set the firmware into virtual mode.
> + */
> + runtime = (efi_runtime_services_t *) early_ioremap((unsigned long)
> + efi.systab->runtime,
> + sizeof(efi_runtime_services_t));
Unneeded cast (please check all patches)
> + if (runtime != NULL) {
> + /*
> + * We will only need *early* access to the following
> + * two EFI runtime services before set_virtual_address_map
> + * is invoked.
> + */
> + efi_phys.get_time = (efi_get_time_t *) runtime->get_time;
> + efi_phys.set_virtual_address_map =
> + (efi_set_virtual_address_map_t *)runtime->set_virtual_address_map;
> + } else
> + printk(KERN_ERR PFX "Could not map the runtime service table!\n");
> + /* Map the EFI memory map for use until paging_init() */
> + memmap.map = (efi_memory_desc_t *) early_ioremap(
> + (unsigned long) EFI_MEMMAP,
> + EFI_MEMMAP_SIZE);
> + if (memmap.map == NULL)
> + printk(KERN_ERR PFX "Could not map the EFI memory map!\n");
> + if (EFI_MEMDESC_SIZE != sizeof(efi_memory_desc_t)) {
> + printk(KERN_WARNING PFX "Kernel-defined memdesc"
> + "doesn't match the one from EFI!\n");
> + }
> + memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
> + /* Override the emergency restart function */
> + machine_emergency_restart_func = efi_emergency_restart;
> +}
> +
> +/*
> + * This function will switch the EFI runtime services to virtual mode.
> + * Essentially, look through the EFI memmap and map every region that
> + * has the runtime attribute bit set in its memory descriptor and update
> + * that memory descriptor with the virtual address obtained from ioremap().
> + * This enables the runtime services to be called without having to
> + * thunk back into physical mode for every invocation.
> + */
> +void __init efi_enter_virtual_mode(void)
> +{
> + efi_memory_desc_t *md;
> + efi_status_t status;
> + unsigned long end;
> + void *p;
> +
> + efi.systab = NULL;
> + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
> + md = p;
> + if (!(md->attribute & EFI_MEMORY_RUNTIME))
> + continue;
> + if (md->attribute & EFI_MEMORY_WB)
> + md->virt_addr = (unsigned long)__va(md->phys_addr);
> + else if (md->attribute & (EFI_MEMORY_UC | EFI_MEMORY_WC))
> + md->virt_addr = (unsigned long)ioremap(md->phys_addr,
> + md->num_pages << EFI_PAGE_SHIFT);
> + end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
> + if ((md->phys_addr <= (unsigned long)efi_phys.systab) &&
> + ((unsigned long)efi_phys.systab < end))
> + efi.systab = (efi_system_table_t *)
> + (md->virt_addr - md->phys_addr +
> + (unsigned long)efi_phys.systab);
> + }
> +
> + if (!efi.systab)
> + BUG();
BUG_ON()
> + status = phys_efi_set_virtual_address_map(
> + memmap.desc_size * memmap.nr_map,
> + memmap.desc_size,
> + memmap.desc_version,
> + memmap.phys_map);
> +
> + if (status != EFI_SUCCESS) {
> + printk (KERN_ALERT "You are screwed! "
> + "Unable to switch EFI into virtual mode "
> + "(status=%lx)\n", status);
> + panic("EFI call to SetVirtualAddressMap() failed!");
> + }
> + /*
> + * Now that EFI is in virtual mode, update the function
> + * pointers in the runtime service table to the new virtual addresses.
> + *
> + * Call EFI services through wrapper functions.
> + */
> +
> + efi.get_time = (efi_get_time_t *)_efi_get_time;
> + efi.set_time = (efi_set_time_t *)_efi_set_time;
> + efi.get_wakeup_time = (efi_get_wakeup_time_t *)_efi_get_wakeup_time;
> + efi.set_wakeup_time = (efi_set_wakeup_time_t *)_efi_set_wakeup_time;
> + efi.get_variable = (efi_get_variable_t *)_efi_get_variable;
> + efi.get_next_variable = (efi_get_next_variable_t *)_efi_get_next_variable;
> + efi.set_variable = (efi_set_variable_t *)_efi_set_variable;
> + efi.get_next_high_mono_count = (efi_get_next_high_mono_count_t *)
> + _efi_get_next_high_mono_count;
> + efi.reset_system = (efi_reset_system_t *)_efi_reset_system;
> + efi.set_virtual_address_map = (efi_set_virtual_address_map_t *)
> + _efi_set_virtual_address_map;
> +}
> +
> --- linux-2.6.21-orig/arch/x86_64/kernel/efi_callwrap.c 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/efi_callwrap.c 2007-06-25 14:36:32.000000000 -0700
> @@ -0,0 +1,202 @@
> +/*
> + * Copyright (C) 2006 Giridhar Pemmasani
> + * Copyright (C) 2007-2010 Intel Corp
> + * Contributed by Chandramouli Narayanan<mouli@linux.intel.com>
> + * Adapted NDIS wrapper macros from http://ndiswrapper.sourceforge.net
> + * for EFI x86_64 linux support
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/mm.h>
> +#include <linux/types.h>
> +#include <linux/time.h>
> +#include <linux/spinlock.h>
> +#include <linux/bootmem.h>
> +#include <linux/ioport.h>
> +#include <linux/module.h>
> +#include <linux/efi.h>
> +
> +#define alloc_win_stack_frame(argc) \
> + "subq $" #argc "*8, %%rsp\n\t"
> +#define free_win_stack_frame(argc) \
> + "addq $" #argc "*8, %%rsp\n\t"
> +
> +/* m is index of Windows arg required, n is total number of args to
> + * function Windows arg 1 should be at 0(%rsp), arg 2 at 8(%rsp) and
> + * so on, after stack frame is allocated, which starts at -n*8(%rsp)
> + * when stack frame is allocated. 4 > m >= n.
> +*/
> +
> +#define lin2win_win_arg(m,n) "(" #m "-1-" #n ")*8(%%rsp)"
> +
> +/* volatile args for Windows function must be in clobber / output list */
> +
> +efi_status_t LIN2WIN0(void *func)
> +{
> + u64 ret, dummy;
> + register u64 r8 __asm__("r8");
> + register u64 r9 __asm__("r9");
> + register u64 r10 __asm__("r10");
> + register u64 r11 __asm__("r11");
> + __asm__ __volatile__(
> + alloc_win_stack_frame(4)
> + "call *%[fptr]\n\t"
> + free_win_stack_frame(4)
> + : "=a" (ret), "=c" (dummy), "=d" (dummy),
> + "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
> + : [fptr] "r" (func));
> + return ret;
> +}
> +
> +efi_status_t LIN2WIN1(void *func, u64 arg1)
> +{
> + u64 ret, dummy;
> + register u64 r8 __asm__("r8");
> + register u64 r9 __asm__("r9");
> + register u64 r10 __asm__("r10");
> + register u64 r11 __asm__("r11");
> + __asm__ __volatile__(
> + alloc_win_stack_frame(4)
> + "call *%[fptr]\n\t"
> + free_win_stack_frame(4)
> + : "=a" (ret), "=c" (dummy), "=d" (dummy),
> + "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
> + : "c" (arg1),
> + [fptr] "r" (func));
> + return ret;
> +}
> +
> +efi_status_t LIN2WIN2(void *func, u64 arg1, u64 arg2)
> +{
> + u64 ret, dummy;
> + register u64 r8 __asm__("r8");
> + register u64 r9 __asm__("r9");
> + register u64 r10 __asm__("r10");
> + register u64 r11 __asm__("r11");
> + __asm__ __volatile__(
> + alloc_win_stack_frame(4)
> + "call *%[fptr]\n\t"
> + free_win_stack_frame(4)
> + : "=a" (ret), "=c" (dummy), "=d" (dummy),
> + "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
> + : "c" (arg1), "d" (arg2),
> + [fptr] "r" (func));
> + return ret;
> +}
Maybe all these should have been coded in assembler.
> +EXPORT_SYMBOL_GPL(LIN2WIN0);
> +EXPORT_SYMBOL_GPL(LIN2WIN1);
> +EXPORT_SYMBOL_GPL(LIN2WIN2);
> +EXPORT_SYMBOL_GPL(LIN2WIN3);
> +EXPORT_SYMBOL_GPL(LIN2WIN4);
> +EXPORT_SYMBOL_GPL(LIN2WIN5);
> +EXPORT_SYMBOL_GPL(LIN2WIN6);
efi was exported non-gpl, these are exported gpl. How come?
Are these exports needed? For what?
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2.6.21 2/3] x86_64 EFI64 support Try #2
2007-07-02 17:06 ` [PATCH 2.6.21 2/3] " Chandramouli Narayanan
@ 2007-07-03 23:27 ` Andrew Morton
0 siblings, 0 replies; 9+ messages in thread
From: Andrew Morton @ 2007-07-03 23:27 UTC (permalink / raw)
To: Chandramouli Narayanan; +Cc: linux-kernel, ak
On Mon, 02 Jul 2007 10:06:16 -0700
Chandramouli Narayanan <mouli@linux.intel.com> wrote:
> EFI x86_64 support Patch 2 of 3 (try #2)
> ----------------------------------------
> - E820 conversion integration implemented
> - A way to override machine_emergency_restart is implemented so that
> EFI support can provide its own implementation.
> - The variable efi_enabled is still retained as it is used across
> archictures with CONFIG_EFI option.
>
Does the above text completely describe this patch?
>
> diff -uprN -X linux-2.6.21-orig/Documentation/dontdiff linux-2.6.21-orig/arch/x86_64/kernel/aperture.c linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/aperture.c
> --- linux-2.6.21-orig/arch/x86_64/kernel/aperture.c 2007-04-25 20:08:32.000000000 -0700
> +++ linux-2.6.21-uefi-finaltest4/arch/x86_64/kernel/aperture.c 2007-06-25 13:59:54.000000000 -0700
Lots of little glitches there which checkpatch.pl will point out.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2.6.21 3/3] x86_64 EFI64 support Try #2
2007-07-02 17:06 ` [PATCH 2.6.21 3/3] " Chandramouli Narayanan
@ 2007-07-03 23:31 ` Andrew Morton
2007-07-04 21:45 ` Huang, Ying
0 siblings, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2007-07-03 23:31 UTC (permalink / raw)
To: Chandramouli Narayanan; +Cc: linux-kernel, ak, Antonino A. Daplas
On Mon, 02 Jul 2007 10:06:17 -0700
Chandramouli Narayanan <mouli@linux.intel.com> wrote:
> EFI x86_64 support Patch 3 of 3 (try #2)
> ----------------------------------------
> - Fixed redundant check in efifb_init().
>
> This patch depends on the EFI x86_64 patches 1/3 and 2/3.
>
> This patch adds Graphics Output Protocol support to the kernel.
> x86_64 systems with UEFI2.0 firmware conform to UEFI 2.0 specification.
> UEFI2.0 spec deprecates Universal Graphics Adapter (UGA) protocol and
> only Graphics Output Protocol (GOP) is produced. Therefore, the boot loader
> needs to query the UEFI firmware with appropriate Output Protocol and
> pass the video information to the kernel. As a result of GOP
> protocol, an EFI framebuffer driver is needed for displaying console messages.
> Patch 3 of 3 adds a EFI framebuffer driver. The EFI frame buffer driver in this
> patch is based on the Intel Mac framebuffer driver.
>
> The x86_64 ELILO bootloader takes care of passing the video information
> as appropriate for EFI firmware.
>
That's more like a changelog.
Please cc linux-fbdev-devel@lists.sourceforge.net and "Antonino A. Daplas"
<adaplas@pol.net> on framebuffer driver patches.
>
> +config FB_EFI
> + bool "EFI-based Framebuffer Support"
> + depends on (FB = y) && X86 && EFI
So this is selectable on i386 as well. Has it been tested there?
> + select FB_CFB_FILLRECT
> + select FB_CFB_COPYAREA
> + select FB_CFB_IMAGEBLIT
> + help
> + This is the EFI frame buffer device driver. If the firmware on
> + your platform is UEFI2.0, select Y to add support for
> + Graphics Output Protocol for early console messages to appear.
> +
> config FB_IMAC
> bool "Intel-based Macintosh Framebuffer Support"
> depends on (FB = y) && X86 && EFI
>
> ...
>
> --- linux-2.6.21-orig/drivers/video/efifb.c 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.21-uefi-finaltest4/drivers/video/efifb.c 2007-06-12 16:16:12.000000000 -0700
> @@ -0,0 +1,249 @@
> +/*
> + * framebuffer driver for Intel Based Mac's
> + *
> + * (c) 2006 Edgar Hucek <gimli@dark-green.com>
> + * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
> + *
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/fb.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/ioport.h>
> +#include <linux/mm.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/screen_info.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/dmi.h>
> +#include <linux/efi.h>
> +
> +#include <asm/io.h>
checkpatch.pl will save me work.
> +#ifndef __i386__
> + //screen_info.imacpm_seg = 0;
> +#endif
hmm.
> +
> + if (!request_mem_region(efifb_fix.smem_start, size_total, "efifb")) {
> + printk(KERN_WARNING
> + "efifb: cannot reserve video memory at 0x%lx\n",
> + efifb_fix.smem_start);
KERN_ERR?
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2.6.21 1/3] x86_64 EFI64 support Try #2
2007-07-03 23:25 ` Andrew Morton
@ 2007-07-04 21:40 ` Huang, Ying
0 siblings, 0 replies; 9+ messages in thread
From: Huang, Ying @ 2007-07-04 21:40 UTC (permalink / raw)
To: Andrew Morton; +Cc: Chandramouli Narayanan, linux-kernel, ak
Thanks for your comment. Because my colleague Mouli has left for
sabbatical, I will continue work on the X86_64 UEFI support kernel
patch.
On Tue, 2007-07-03 at 16:25 -0700, Andrew Morton wrote:
> On Mon, 02 Jul 2007 10:06:15 -0700
> Chandramouli Narayanan <mouli@linux.intel.com> wrote:
> >
>
> You just sent three patches, all with the same name. Please take care to
> choose different and good Subject:s for each patch.
> http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt covers this a bit.
>
We will do as that in the next version.
> >
> > Signed-off-by: Chandramouli Narayanan <mouli@linux.intel.com>
>
> All the above text tells us the differences between. v2 and v3. It all
> will be of minimal interest for the final got commit and hence it will be
> removed (by me, typically).
>
> That will leave us with no cvhangelog for this patch.
>
> Please provide a changelog with this patch. The above-linked-to document
> has some guidelines.
>
Will do.
> Please feed these patches through the latest version of
> scripts/checkpatch.pl and consider addressing the resulting warnings. Many
> are generated.
Ok, we will check the patch with scripts/checkpatch.pl before sending
next time.
> > +extern efi_status_t LIN2WIN0(void *fp);
> > +extern efi_status_t LIN2WIN1(void *fp, u64 arg1);
> > +extern efi_status_t LIN2WIN2(void *fp, u64 arg1, u64 arg2);
> > +extern efi_status_t LIN2WIN3(void *fp, u64 arg1, u64 arg2, u64 arg3);
> > +extern efi_status_t LIN2WIN4(void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4);
> > +extern efi_status_t LIN2WIN5(
> > + void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5);
> > +extern efi_status_t LIN2WIN6(
> > + void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6);
>
> Why are these all-upper-case? That convention is conventionally used for
> macros.
We will change them to lower case in next version.
> > +#define EFI_DEBUG 0
> > +#define PFX "EFI: "
> > +
> > +struct efi efi;
> > +EXPORT_SYMBOL(efi);
>
> Why is this exported?
>
Because the EFI Variable driver in drivers/firmware/efivars.c uses "efi"
to call EFI variable services and read EFI information. Which may be a
module.
> > +static void __init efi_call_phys_prelog(void) __acquires(efi_rt_lock)
> > +{
> > + unsigned long vaddress;
> > +
> > + spin_lock(&efi_rt_lock);
> > + local_irq_save(efi_rt_eflags);
>
> I suspect the above two statements are in the wrong order.
>
Because it is intended to disable interrupt between efi_call_phys_prelog
and efi_call_phys_epilog, the efi_rt_eflags is made a global variable.
So the spin lock should be locked firstly to protect efi_rt_eflags from
accessed from different CPU.
> > +
> > +inline int efi_set_rtc_mmss(unsigned long nowtime)
>
> Remove `inline'.
>
Will do.
> > +{
> > + int real_seconds, real_minutes;
> > + efi_status_t status;
> > + efi_time_t eft;
> > + efi_time_cap_t cap;
> > +
> > + spin_lock(&efi_rt_lock);
> > + status = efi.get_time(&eft, &cap);
> > + spin_unlock(&efi_rt_lock);
>
> It is very unusual for any time-related low-level lock to be taken in a
> non-irq-safe fashion. Is this code correct?
The efi_set_rtc_mmss has the same assumption as set_rtc_mmss. That is,
the function will be called in timer interrupt. So spin_lock_irq is not
needed. But the whole function may be needed to be enclosed by spin_lock
and spin_unlock.
> > + if (status != EFI_SUCCESS) {
> > + printk(KERN_ERR PFX "Oops: efitime: can't read time!\n");
> > + return -1;
> > + }
> > +
> > + real_seconds = nowtime % 60;
> > + real_minutes = nowtime / 60;
> > + if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
> > + real_minutes += 30;
> > + real_minutes %= 60;
> > + eft.minute = real_minutes;
> > + eft.second = real_seconds;
> > +
> > + spin_lock(&efi_rt_lock);
> > + status = efi.set_time(&eft);
> > + spin_unlock(&efi_rt_lock);
> > + if (status != EFI_SUCCESS) {
> > + printk(KERN_ERR PFX "Oops: efitime: can't write time!\n");
> > + return -1;
> > + }
> > + return 0;
> > +}
> > +/*
>
> Missing newline.
Sorry, will fix in next version.
> > + * This is used during kernel init before runtime
> > + * services have been remapped and also during suspend, therefore,
> > + * we'll need to call both in physical and virtual modes.
> > + */
> > +inline unsigned long efi_get_time(void)
>
> Remove inline
Will do.
> > +{
> > + efi_status_t status;
> > + efi_time_t eft;
> > + efi_time_cap_t cap;
> > +
> > + if (efi.get_time) {
> > + /* if we are in virtual mode use remapped function */
> > + status = efi.get_time(&eft, &cap);
> > + } else {
> > + /* we are in physical mode */
> > + status = phys_efi_get_time(&eft, &cap);
> > + }
> > + if (status != EFI_SUCCESS)
> > + printk(KERN_ERR PFX "Oops: efitime: can't read time status: 0x%lx\n",status);
>
> Missing space, line too long (checkpatch will point these out)
Will add space and checkpatch.pl for all patches.
> > +
> > + return mktime(eft.year, eft.month, eft.day, eft.hour,
> > + eft.minute, eft.second);
> > +}
> > +
> > +/*
> > + * We need to map the EFI memory map again after paging_init().
> > + */
> > +void __init efi_map_memmap(void)
> > +{
> > + int i;
> > +
> > + memmap.map = __va((unsigned long)memmap.phys_map);
> > + memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
> > +
> > + /* Make EFI runtime code area executable */
> > + for (i = 0; i < e820.nr_map; i++) {
> > + switch (e820.map[i].type) {
> > + case E820_RUNTIME_CODE:
> > + init_memory_mapping(
> > + e820.map[i].addr,
> > + e820.map[i].addr + e820.map[i].size);
> > + break;
> > + default:
> > + break;
> > + }
> > + }
> > +}
> > +
> > +/* Override function for emergency restart on EFI enabled systems */
> > +static void efi_emergency_restart(void)
> > +{
> > + /* If EFI enabled, reset system through EFI protocol. */
> > + efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
> > + return;
> > +}
> > +
> > +void __init efi_init(void)
> > +{
> > + efi_config_table_t *config_tables;
> > + efi_runtime_services_t *runtime;
> > + efi_char16_t *c16;
> > + char vendor[100] = "unknown";
> > + int i = 0;
> > +
> > + memset(&efi, 0, sizeof(efi) );
>
> Rendom extra space
Will remove it, and check with checkpatch.pl
> > + memset(&efi_phys, 0, sizeof(efi_phys));
> > +
> > + efi_phys.systab = (efi_system_table_t *)EFI_SYSTAB;
> > + memmap.phys_map = (void*)EFI_MEMMAP;
> > + memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE;
> > + memmap.desc_version = EFI_MEMDESC_VERSION;
> > + memmap.desc_size = EFI_MEMDESC_SIZE;
> > +
> > + efi.systab = (efi_system_table_t *) early_ioremap(
> > + (unsigned long)efi_phys.systab,
> > + sizeof(efi_system_table_t));
>
> early_ioremap() returns void*: unneeded cast.
Will do.
> > + if (!probe_kernel_address(c16, i)) {
> > + for (i = 0; i < sizeof(vendor) && *c16; ++i)
> > + vendor[i] = *c16++;
> > + vendor[i] = '\0';
> > + }
> > +
> > + printk(KERN_INFO PFX "EFI v%u.%.02u by %s \n",
> > + efi.systab->hdr.revision >> 16,
> > + efi.systab->hdr.revision & 0xffff, vendor);
> > +
> > + /*
> > + * Let's see what config tables the firmware passed to us.
> > + */
> > + config_tables = (efi_config_table_t *)early_ioremap( efi.systab->tables,
> > + efi.systab->nr_tables * sizeof(efi_config_table_t));
> > + if (config_tables == NULL)
> > + printk(KERN_ERR PFX "Could not map EFI Configuration Table!\n");
> > +
> > + for (i = 0; i < efi.systab->nr_tables; i++) {
> > + if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
> > + efi.mps = config_tables[i].table;
> > + printk(KERN_INFO " MPS=0x%lx ", config_tables[i].table);
> > + } else
> > + if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
> > + efi.acpi20 = config_tables[i].table;
> > + printk(KERN_INFO " ACPI 2.0=0x%lx ", config_tables[i].table);
> > + } else
> > + if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
> > + efi.acpi = config_tables[i].table;
> > + printk(KERN_INFO " ACPI=0x%lx ", config_tables[i].table);
> > + } else
> > + if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
> > + efi.smbios = config_tables[i].table;
> > + printk(KERN_INFO " SMBIOS=0x%lx ", config_tables[i].table);
> > + } else
> > + if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
> > + efi.hcdp = config_tables[i].table;
> > + printk(KERN_INFO " HCDP=0x%lx ", config_tables[i].table);
> > + } else
> > + if (efi_guidcmp(config_tables[i].guid, UGA_IO_PROTOCOL_GUID) == 0) {
> > + efi.uga = config_tables[i].table;
> > + printk(KERN_INFO " UGA=0x%lx ", config_tables[i].table);
> > + }
> > + }
> > + printk(KERN_INFO "\n");
>
> The KERN_* is only meaningful at the start of the output line, and this one
> is being emitted at the end of the input line. Usually..
Will do.
> > + /*
> > + * Check out the runtime services table. We need to map
> > + * the runtime services table so that we can grab the physical
> > + * address of several of the EFI runtime functions, needed to
> > + * set the firmware into virtual mode.
> > + */
> > + runtime = (efi_runtime_services_t *) early_ioremap((unsigned long)
> > + efi.systab->runtime,
> > + sizeof(efi_runtime_services_t));
>
> Unneeded cast (please check all patches)
Ok, we will check all patches for early_ioremap.
> > + efi.systab = NULL;
> > + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
> > + md = p;
> > + if (!(md->attribute & EFI_MEMORY_RUNTIME))
> > + continue;
> > + if (md->attribute & EFI_MEMORY_WB)
> > + md->virt_addr = (unsigned long)__va(md->phys_addr);
> > + else if (md->attribute & (EFI_MEMORY_UC | EFI_MEMORY_WC))
> > + md->virt_addr = (unsigned long)ioremap(md->phys_addr,
> > + md->num_pages << EFI_PAGE_SHIFT);
> > + end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
> > + if ((md->phys_addr <= (unsigned long)efi_phys.systab) &&
> > + ((unsigned long)efi_phys.systab < end))
> > + efi.systab = (efi_system_table_t *)
> > + (md->virt_addr - md->phys_addr +
> > + (unsigned long)efi_phys.systab);
> > + }
> > +
> > + if (!efi.systab)
> > + BUG();
>
> BUG_ON()
Will do.
> > +
> > +efi_status_t LIN2WIN1(void *func, u64 arg1)
> > +{
> > + u64 ret, dummy;
> > + register u64 r8 __asm__("r8");
> > + register u64 r9 __asm__("r9");
> > + register u64 r10 __asm__("r10");
> > + register u64 r11 __asm__("r11");
> > + __asm__ __volatile__(
> > + alloc_win_stack_frame(4)
> > + "call *%[fptr]\n\t"
> > + free_win_stack_frame(4)
> > + : "=a" (ret), "=c" (dummy), "=d" (dummy),
> > + "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
> > + : "c" (arg1),
> > + [fptr] "r" (func));
> > + return ret;
> > +}
> > +
> > +efi_status_t LIN2WIN2(void *func, u64 arg1, u64 arg2)
> > +{
> > + u64 ret, dummy;
> > + register u64 r8 __asm__("r8");
> > + register u64 r9 __asm__("r9");
> > + register u64 r10 __asm__("r10");
> > + register u64 r11 __asm__("r11");
> > + __asm__ __volatile__(
> > + alloc_win_stack_frame(4)
> > + "call *%[fptr]\n\t"
> > + free_win_stack_frame(4)
> > + : "=a" (ret), "=c" (dummy), "=d" (dummy),
> > + "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
> > + : "c" (arg1), "d" (arg2),
> > + [fptr] "r" (func));
> > + return ret;
> > +}
>
> Maybe all these should have been coded in assembler.
We will try to implement it in assembler.
> > +EXPORT_SYMBOL_GPL(LIN2WIN0);
> > +EXPORT_SYMBOL_GPL(LIN2WIN1);
> > +EXPORT_SYMBOL_GPL(LIN2WIN2);
> > +EXPORT_SYMBOL_GPL(LIN2WIN3);
> > +EXPORT_SYMBOL_GPL(LIN2WIN4);
> > +EXPORT_SYMBOL_GPL(LIN2WIN5);
> > +EXPORT_SYMBOL_GPL(LIN2WIN6);
>
> efi was exported non-gpl, these are exported gpl. How come?
Need same synchronization, :)
> Are these exports needed? For what?
>
If it is intended to call EFI runtime service outside of efi.c directly,
such as that of current EFI Variable driver, these are needed. But the
better method maybe provide the calling wrapper in efi.c. And export the
wrapper instead.
Best Regards,
Huang Ying
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2.6.21 3/3] x86_64 EFI64 support Try #2
2007-07-03 23:31 ` Andrew Morton
@ 2007-07-04 21:45 ` Huang, Ying
0 siblings, 0 replies; 9+ messages in thread
From: Huang, Ying @ 2007-07-04 21:45 UTC (permalink / raw)
To: Andrew Morton
Cc: Chandramouli Narayanan, linux-kernel, ak, Antonino A. Daplas
On Tue, 2007-07-03 at 16:31 -0700, Andrew Morton wrote:
> On Mon, 02 Jul 2007 10:06:17 -0700
> Chandramouli Narayanan <mouli@linux.intel.com> wrote:
>
> > EFI x86_64 support Patch 3 of 3 (try #2)
> > ----------------------------------------
> > - Fixed redundant check in efifb_init().
> >
> > This patch depends on the EFI x86_64 patches 1/3 and 2/3.
> >
> > This patch adds Graphics Output Protocol support to the kernel.
> > x86_64 systems with UEFI2.0 firmware conform to UEFI 2.0 specification.
> > UEFI2.0 spec deprecates Universal Graphics Adapter (UGA) protocol and
> > only Graphics Output Protocol (GOP) is produced. Therefore, the boot loader
> > needs to query the UEFI firmware with appropriate Output Protocol and
> > pass the video information to the kernel. As a result of GOP
> > protocol, an EFI framebuffer driver is needed for displaying console messages.
> > Patch 3 of 3 adds a EFI framebuffer driver. The EFI frame buffer driver in this
> > patch is based on the Intel Mac framebuffer driver.
> >
> > The x86_64 ELILO bootloader takes care of passing the video information
> > as appropriate for EFI firmware.
> >
>
> That's more like a changelog.
>
> Please cc linux-fbdev-devel@lists.sourceforge.net and "Antonino A. Daplas"
> <adaplas@pol.net> on framebuffer driver patches.
Ok, will cc them.
> >
> > +config FB_EFI
> > + bool "EFI-based Framebuffer Support"
> > + depends on (FB = y) && X86 && EFI
>
> So this is selectable on i386 as well. Has it been tested there?
I will test it.
> > +
> > +#include <linux/delay.h>
> > +#include <linux/errno.h>
> > +#include <linux/fb.h>
> > +#include <linux/kernel.h>
> > +#include <linux/init.h>
> > +#include <linux/ioport.h>
> > +#include <linux/mm.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/screen_info.h>
> > +#include <linux/slab.h>
> > +#include <linux/string.h>
> > +#include <linux/dmi.h>
> > +#include <linux/efi.h>
> > +
> > +#include <asm/io.h>
>
> checkpatch.pl will save me work.
Sorry, the next version will be checked with checkpatch.pl firstly.
> > +#ifndef __i386__
> > + //screen_info.imacpm_seg = 0;
> > +#endif
>
> hmm.
>
> > +
> > + if (!request_mem_region(efifb_fix.smem_start, size_total, "efifb")) {
> > + printk(KERN_WARNING
> > + "efifb: cannot reserve video memory at 0x%lx\n",
> > + efifb_fix.smem_start);
>
> KERN_ERR?
>
>
Best Regards,
Huang, Ying
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2007-07-04 13:46 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-07-02 17:06 [PATCH 2.6.21 0/3] x86_64 EFI64 support Try #2 Chandramouli Narayanan
2007-07-02 17:06 ` [PATCH 2.6.21 1/3] " Chandramouli Narayanan
2007-07-03 23:25 ` Andrew Morton
2007-07-04 21:40 ` Huang, Ying
2007-07-02 17:06 ` [PATCH 2.6.21 2/3] " Chandramouli Narayanan
2007-07-03 23:27 ` Andrew Morton
2007-07-02 17:06 ` [PATCH 2.6.21 3/3] " Chandramouli Narayanan
2007-07-03 23:31 ` Andrew Morton
2007-07-04 21:45 ` Huang, Ying
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).