[patch 6/7 v2] passing kexec necessary efi data via setup_data

2013-11-05 Thread dyoung
Add a new setup_data type SETUP_EFI for kexec use.
Passing the saved fw_vendor, runtime, config tables and
efi runtime mappings.

When entering virtual mode, directly mapping the efi
runtime ragions which we passed in previously. And skip
the step to call SetVirtualAddressMap.

Specially for HP z420 workstation it need another variable
saving, it's the smbios physical address, the HP bios
also update the SMBIOS address after entering virtual mode
besides of the standard fw_vendor,runtime and config table.

Tested on ovmf+qemu, lenovo thinkpad, a dell laptop and an
HP z420 workstation.

Signed-off-by: Dave Young dyo...@redhat.com
---
 arch/x86/include/asm/efi.h|   12 ++
 arch/x86/include/uapi/asm/bootparam.h |1 
 arch/x86/kernel/setup.c   |3 
 arch/x86/platform/efi/efi.c   |  151 ++
 4 files changed, 152 insertions(+), 15 deletions(-)

--- linux-2.6.orig/arch/x86/kernel/setup.c
+++ linux-2.6/arch/x86/kernel/setup.c
@@ -447,6 +447,9 @@ static void __init parse_setup_data(void
case SETUP_DTB:
add_dtb(pa_data);
break;
+   case SETUP_EFI:
+   parse_efi_setup(pa_data, data_len);
+   break;
default:
break;
}
--- linux-2.6.orig/arch/x86/platform/efi/efi.c
+++ linux-2.6/arch/x86/platform/efi/efi.c
@@ -78,6 +78,7 @@ static __initdata efi_config_table_type_
 
 efi_memory_desc_t *efi_runtime_map;
 int nr_efi_runtime_map;
+struct efi_setup_data *esdata;
 
 /*
  * Returns 1 if 'facility' is enabled, 0 otherwise.
@@ -115,6 +116,32 @@ static int __init setup_storage_paranoia
 }
 early_param(efi_no_storage_paranoia, setup_storage_paranoia);
 
+void parse_efi_setup(u64 phys_addr, u32 data_len)
+{
+   int size;
+   struct setup_data *sdata;
+   u64 esdata_phys;
+
+   if (!efi_enabled(EFI_64BIT)) {
+   pr_warn(skipping setup_data on EFI 32BIT!);
+   return;
+   }
+
+   sdata = early_memremap(phys_addr, data_len);
+   if (!sdata)
+   return;
+
+   size = data_len - sizeof(struct setup_data);
+
+   esdata_phys = phys_addr + sizeof(struct setup_data);
+
+   nr_efi_runtime_map = (size - sizeof(struct efi_setup_data)) /
+   sizeof(efi_memory_desc_t);
+   early_iounmap(sdata, data_len);
+
+   /* setup data regions have been reserved by default */
+   esdata = phys_to_virt(esdata_phys);
+}
 
 static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
@@ -504,8 +531,12 @@ static int __init efi_systab_init(void *
}
 
efi_systab.hdr = systab64-hdr;
-   efi_systab.fw_vendor = systab64-fw_vendor;
-   tmp |= systab64-fw_vendor;
+
+   if (esdata)
+   efi_systab.fw_vendor = (unsigned long)esdata-fw_vendor;
+   else
+   efi_systab.fw_vendor = systab64-fw_vendor;
+   tmp |= efi_systab.fw_vendor;
efi_systab.fw_revision = systab64-fw_revision;
efi_systab.con_in_handle = systab64-con_in_handle;
tmp |= systab64-con_in_handle;
@@ -519,13 +550,21 @@ static int __init efi_systab_init(void *
tmp |= systab64-stderr_handle;
efi_systab.stderr = systab64-stderr;
tmp |= systab64-stderr;
-   efi_systab.runtime = (void *)(unsigned long)systab64-runtime;
-   tmp |= systab64-runtime;
+   if (esdata)
+   efi_systab.runtime =
+   (void *)(unsigned long)esdata-runtime;
+   else
+   efi_systab.runtime =
+   (void *)(unsigned long)systab64-runtime;
+   tmp |= (unsigned long)efi_systab.runtime;
efi_systab.boottime = (void *)(unsigned long)systab64-boottime;
tmp |= systab64-boottime;
efi_systab.nr_tables = systab64-nr_tables;
-   efi_systab.tables = systab64-tables;
-   tmp |= systab64-tables;
+   if (esdata)
+   efi_systab.tables = (unsigned long)esdata-tables;
+   else
+   efi_systab.tables = systab64-tables;
+   tmp |= efi_systab.tables;
 
early_iounmap(systab64, sizeof(*systab64));
 #ifdef CONFIG_X86_32
@@ -631,6 +670,41 @@ static int __init efi_memmap_init(void)
return 0;
 }
 
+static int __init efi_reuse_config(u64 tables, int nr_tables)
+{
+   void *p, *tablep;
+   int i, sz;
+
+   if (!efi_enabled(EFI_64BIT))
+   return 0;
+
+   sz = sizeof(efi_config_table_64_t);
+
+   p = tablep = early_memremap(tables, nr_tables * sz);
+   if (!p) {
+   pr_err(Could not map Configuration table!\n);
+   

[patch 1/7 v2] Add function efi_remap_region for remapping to saved virt address

2013-11-05 Thread dyoung
Kexec kernel will use saved runtime virtual mapping, so add a
new function efi_remap_region to remapping it directly without
calculate the virt addr from efi_va.

The md is passed in from 1st kernel, the virtual addr is
saved in md-virt_addr.

Signed-off-by: Dave Young dyo...@redhat.com
---
 arch/x86/include/asm/efi.h |1 +
 arch/x86/platform/efi/efi_32.c |3 +++
 arch/x86/platform/efi/efi_64.c |   19 +++
 3 files changed, 23 insertions(+)

--- linux-2.6.orig/arch/x86/include/asm/efi.h
+++ linux-2.6/arch/x86/include/asm/efi.h
@@ -128,6 +128,7 @@ extern void efi_call_phys_epilog(void);
 extern void efi_unmap_memmap(void);
 extern void efi_memory_uc(u64 addr, unsigned long size);
 extern void __init efi_map_region(efi_memory_desc_t *md);
+extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
 extern void efi_sync_low_kernel_mappings(void);
 extern void efi_setup_page_tables(void);
 extern void __init old_map_region(efi_memory_desc_t *md);
--- linux-2.6.orig/arch/x86/platform/efi/efi_64.c
+++ linux-2.6/arch/x86/platform/efi/efi_64.c
@@ -203,6 +203,25 @@ void __init efi_map_region(efi_memory_de
md-virt_addr = efi_va;
 }
 
+/*
+ * kexec kernel will use efi_map_region_fixed to map efi
+ * runtime memory ranges. md-virt_addr is the original virtual
+ * address which had been mapped in kexec 1st kernel.
+ */
+void __init efi_map_region_fixed(efi_memory_desc_t *md)
+{
+   pgd_t *pgd = (pgd_t *)__va(real_mode_header-trampoline_pgd);
+   unsigned long pf = 0;
+
+   if (!(md-attribute  EFI_MEMORY_WB))
+   pf |= _PAGE_PCD;
+
+   if (kernel_map_pages_in_pgd(pgd, md-phys_addr, md-virt_addr,
+   md-num_pages, pf))
+   pr_warn(Error mapping PA 0x%llx - VA 0x%llx!\n,
+  md-phys_addr, md-virt_addr);
+}
+
 void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
 u32 type, u64 attribute)
 {
--- linux-2.6.orig/arch/x86/platform/efi/efi_32.c
+++ linux-2.6/arch/x86/platform/efi/efi_32.c
@@ -47,6 +47,9 @@ void __init efi_map_region(efi_memory_de
old_map_region(md);
 }
 
+void __init efi_map_region_fixed(efi_memory_desc_t *md)
+{}
+
 void efi_call_phys_prelog(void)
 {
struct desc_ptr gdt_descr;

--
To unsubscribe from this list: send the line unsubscribe linux-efi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[patch 2/3 v2] Add efi_info in x86 setup header

2013-11-05 Thread dyoung
For supporting efi runtime on kexec kernel we need to
fill the efi_info struct in setup_header. I just get
the info in kernel exported boot_params data in debugfs.

v1-v2:
update comment for offset of reserved4_1[] in x87_linux_param_header
Address comment from mjg59: do not break old kernel when use newer kexec-tools.
  add checking for xloadflags bit 4 XLF_EFI_KEXEC. Only fill
  efi_info and pass acpi_rsdp when the kexec kernel support efi boot.
coding style fix, change internal function to be static

Signed-off-by: Dave Young dyo...@redhat.com
---
 include/x86/x86-linux.h |3 ++-
 kexec/arch/i386/crashdump-x86.c |4 +++-
 kexec/arch/i386/x86-linux-setup.c   |9 +
 kexec/arch/i386/x86-linux-setup.h   |1 +
 kexec/arch/x86_64/kexec-bzImage64.c |6 ++
 5 files changed, 21 insertions(+), 2 deletions(-)

--- kexec-tools.orig/include/x86/x86-linux.h
+++ kexec-tools/include/x86/x86-linux.h
@@ -115,7 +115,8 @@ struct x86_linux_param_header {
uint32_t ext_ramdisk_image; /* 0xc0 */
uint32_t ext_ramdisk_size;  /* 0xc4 */
uint32_t ext_cmd_line_ptr;  /* 0xc8 */
-   uint8_t reserved4_1[0x1e0 - 0xcc];  /* 0xcc */
+   uint8_t reserved4_1[0x1c0 - 0xcc];  /* 0xe4 */
+   uint8_t efi_info[32];   /* 0x1c0 */
uint32_t alt_mem_k; /* 0x1e0 */
uint8_t  reserved5[4];  /* 0x1e4 */
uint8_t  e820_map_nr;   /* 0x1e8 */
--- kexec-tools.orig/kexec/arch/i386/x86-linux-setup.c
+++ kexec-tools/kexec/arch/i386/x86-linux-setup.c
@@ -466,6 +466,13 @@ void setup_subarch(struct x86_linux_para
get_bootparam(real_mode-hardware_subarch, offset, sizeof(uint32_t));
 }
 
+static void setup_efi_info(struct x86_linux_param_header *real_mode)
+{
+   off_t offset = offsetof(typeof(*real_mode), efi_info);
+
+   get_bootparam(real_mode-efi_info, offset, 32);
+}
+
 void setup_linux_system_parameters(struct kexec_info *info,
   struct x86_linux_param_header *real_mode)
 {
@@ -475,6 +482,8 @@ void setup_linux_system_parameters(struc
 
/* get subarch from running kernel */
setup_subarch(real_mode);
+   if (bzImage_support_efi_boot)
+   setup_efi_info(real_mode);

/* Default screen size */
real_mode-orig_x = 0;
--- kexec-tools.orig/kexec/arch/i386/crashdump-x86.c
+++ kexec-tools/kexec/arch/i386/crashdump-x86.c
@@ -41,6 +41,7 @@
 #include ../../crashdump.h
 #include kexec-x86.h
 #include crashdump-x86.h
+#include x86-linux-setup.h
 
 #ifdef HAVE_LIBXENCTRL
 #ifdef HAVE_XC_GET_MACHINE_MEMORY_MAP
@@ -1046,7 +1047,8 @@ int load_crashdump_segments(struct kexec
if (delete_memmap(memmap_p, elfcorehdr, memsz)  0)
return -1;
cmdline_add_memmap(mod_cmdline, memmap_p);
-   cmdline_add_efi(mod_cmdline);
+   if (!bzImage_support_efi_boot)
+   cmdline_add_efi(mod_cmdline);
cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
 
/* Inform second kernel about the presence of ACPI tables. */
--- kexec-tools.orig/kexec/arch/i386/x86-linux-setup.h
+++ kexec-tools/kexec/arch/i386/x86-linux-setup.h
@@ -28,5 +28,6 @@ void setup_linux_system_parameters(struc
 
 /* command line parameter may be appended by purgatory */
 #define PURGATORY_CMDLINE_SIZE 64
+extern int bzImage_support_efi_boot;
 
 #endif /* X86_LINUX_SETUP_H */
--- kexec-tools.orig/kexec/arch/x86_64/kexec-bzImage64.c
+++ kexec-tools/kexec/arch/x86_64/kexec-bzImage64.c
@@ -42,6 +42,7 @@
 #include arch/options.h
 
 static const int probe_debug = 0;
+int bzImage_support_efi_boot;
 
 int bzImage64_probe(const char *buf, off_t len)
 {
@@ -82,6 +83,11 @@ int bzImage64_probe(const char *buf, off
/* Must be KERNEL_64 and CAN_BE_LOADED_ABOVE_4G */
return -1;
}
+
+#define XLF_EFI_KEXEC   (1  4)
+   if ((header-xloadflags  XLF_EFI_KEXEC) == XLF_EFI_KEXEC)
+   bzImage_support_efi_boot = 1;
+
/* I've got a relocatable bzImage64 */
if (probe_debug)
fprintf(stderr, It's a relocatable bzImage64\n);

--
To unsubscribe from this list: send the line unsubscribe linux-efi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[patch 1/3 v2] Add function get_bootparam

2013-11-05 Thread dyoung
Not only setup_subarch will get data from debugfs file
boot_params/data, later code for adding efi_info will
also need do same thing. Thus add a common function here
for later use.

v1-v2: make get_bootparam() static

Signed-off-by: Dave Young dyo...@redhat.com
---
 kexec/arch/i386/x86-linux-setup.c |   14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

--- kexec-tools.orig/kexec/arch/i386/x86-linux-setup.c
+++ kexec-tools/kexec/arch/i386/x86-linux-setup.c
@@ -436,10 +436,9 @@ char *find_mnt_by_fsname(char *fsname)
return mntdir;
 }
 
-void setup_subarch(struct x86_linux_param_header *real_mode)
+static void get_bootparam(void *buf, off_t offset, size_t size)
 {
int data_file;
-   const off_t offset = offsetof(typeof(*real_mode), hardware_subarch);
char *debugfs_mnt;
char filename[PATH_MAX];
 
@@ -447,7 +446,7 @@ void setup_subarch(struct x86_linux_para
if (!debugfs_mnt)
return;
snprintf(filename, PATH_MAX, %s/%s, debugfs_mnt, boot_params/data);
-   filename[PATH_MAX-1] = 0;
+   filename[PATH_MAX - 1] = 0;
free(debugfs_mnt);
 
data_file = open(filename, O_RDONLY);
@@ -455,11 +454,18 @@ void setup_subarch(struct x86_linux_para
return;
if (lseek(data_file, offset, SEEK_SET)  0)
goto close;
-   read(data_file, real_mode-hardware_subarch, sizeof(uint32_t));
+   read(data_file, buf, size);
 close:
close(data_file);
 }
 
+void setup_subarch(struct x86_linux_param_header *real_mode)
+{
+   off_t offset = offsetof(typeof(*real_mode), hardware_subarch);
+
+   get_bootparam(real_mode-hardware_subarch, offset, sizeof(uint32_t));
+}
+
 void setup_linux_system_parameters(struct kexec_info *info,
   struct x86_linux_param_header *real_mode)
 {

--
To unsubscribe from this list: send the line unsubscribe linux-efi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[patch 4/7 v2] export more efi table variable to sysfs

2013-11-05 Thread dyoung
Export fw_vendor, runtime and config tables physical
addresses to /sys/firmware/efi/systab becaue kexec
kernel will need them.

From EFI spec these 3 variables will be updated to
virtual address after entering virtual mode. But
kernel startup code will need the physical address.

Signed-off-by: Dave Young dyo...@redhat.com
---
 arch/x86/platform/efi/efi.c |4 
 drivers/firmware/efi/efi.c  |9 +
 include/linux/efi.h |3 +++
 3 files changed, 16 insertions(+)

--- linux-2.6.orig/drivers/firmware/efi/efi.c
+++ linux-2.6/drivers/firmware/efi/efi.c
@@ -32,6 +32,9 @@ struct efi __read_mostly efi = {
.hcdp   = EFI_INVALID_TABLE_ADDR,
.uga= EFI_INVALID_TABLE_ADDR,
.uv_systab  = EFI_INVALID_TABLE_ADDR,
+   .fw_vendor  = EFI_INVALID_TABLE_ADDR,
+   .runtime= EFI_INVALID_TABLE_ADDR,
+   .config_tables  = EFI_INVALID_TABLE_ADDR,
 };
 EXPORT_SYMBOL(efi);
 
@@ -64,6 +67,12 @@ static ssize_t systab_show(struct kobjec
str += sprintf(str, BOOTINFO=0x%lx\n, efi.boot_info);
if (efi.uga != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, UGA=0x%lx\n, efi.uga);
+   if (efi.fw_vendor != EFI_INVALID_TABLE_ADDR)
+   str += sprintf(str, fw_vendor=0x%lx\n, efi.fw_vendor);
+   if (efi.runtime != EFI_INVALID_TABLE_ADDR)
+   str += sprintf(str, runtime=0x%lx\n, efi.runtime);
+   if (efi.config_tables != EFI_INVALID_TABLE_ADDR)
+   str += sprintf(str, config_tables=0x%lx\n, efi.config_tables);
 
return str - buf;
 }
--- linux-2.6.orig/include/linux/efi.h
+++ linux-2.6/include/linux/efi.h
@@ -556,6 +556,9 @@ extern struct efi {
unsigned long hcdp; /* HCDP table */
unsigned long uga;  /* UGA table */
unsigned long uv_systab;/* UV system table */
+   unsigned long fw_vendor;
+   unsigned long runtime;
+   unsigned long config_tables;
efi_get_time_t *get_time;
efi_set_time_t *set_time;
efi_get_wakeup_time_t *get_wakeup_time;
--- linux-2.6.orig/arch/x86/platform/efi/efi.c
+++ linux-2.6/arch/x86/platform/efi/efi.c
@@ -653,6 +653,10 @@ void __init efi_init(void)
 
set_bit(EFI_SYSTEM_TABLES, x86_efi_facility);
 
+   efi.fw_vendor = (unsigned long)efi.systab-fw_vendor;
+   efi.runtime = (unsigned long)efi.systab-runtime;
+   efi.config_tables = (unsigned long)efi.systab-tables;
+
/*
 * Show what we know for posterity
 */

--
To unsubscribe from this list: send the line unsubscribe linux-efi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[patch 7/7 v2] x86: add xloadflags bit for efi runtime support on kexec

2013-11-05 Thread dyoung
Old kexec-tools can not load new kernel. The reason is previously kexec-tools
do not fill efi_info in x86 setup header thus efi init fail and switch
to noefi boot. In new kexec-tools it will by default fill efi_info and
pass other efi required infomation to 2nd kernel so kexec kernel efi
initialization will success finally.

To prevent from breaking userspace, add a new xloadflags bit so kexec-tools
will check the flag and switch to old logic.

Signed-off-by: Dave Young dyo...@redhat.com
---
 arch/x86/boot/header.S|9 -
 arch/x86/include/uapi/asm/bootparam.h |1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

--- linux-2.6.orig/arch/x86/boot/header.S
+++ linux-2.6/arch/x86/boot/header.S
@@ -391,7 +391,14 @@ xloadflags:
 #else
 # define XLF23 0
 #endif
-   .word XLF0 | XLF1 | XLF23
+
+#if defined(CONFIG_X86_64)  defined(CONFIG_EFI)
+# define XLF4 XLF_EFI_KEXEC
+#else
+# define XLF4 0
+#endif
+
+   .word XLF0 | XLF1 | XLF23 | XLF4
 
 cmdline_size:   .long   COMMAND_LINE_SIZE-1 #length of the command line,
 #added with boot protocol
--- linux-2.6.orig/arch/x86/include/uapi/asm/bootparam.h
+++ linux-2.6/arch/x86/include/uapi/asm/bootparam.h
@@ -24,6 +24,7 @@
 #define XLF_CAN_BE_LOADED_ABOVE_4G (11)
 #define XLF_EFI_HANDOVER_32(12)
 #define XLF_EFI_HANDOVER_64(13)
+#define XLF_EFI_KEXEC  (14)
 
 #ifndef __ASSEMBLY__
 

--
To unsubscribe from this list: send the line unsubscribe linux-efi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[patch 0/7 v2] kexec kernel efi runtime support

2013-11-05 Thread dyoung
Hi,

Here is the V2 for supporting kexec kernel efi runtime.
Per pervious discussion I pass the 1st kernel efi runtime mapping
via setup_data to 2nd kernel. Besides of the runtime mapping
info I also pass the fw_vendor, runtime, config table, smbios
physical address in setup_data. EFI spec mentioned fw_vendor,
runtime, config table addresses will be converted to virt address
after entering virtual mode, but we will use it as physical address
in efi_init. For smbios EFI spec did not mention about the address
updating, but during my test on a HP workstation, the bios will
convert it to Virt addr, thus pass it in setup_data as well.

For fw_vendor, runtime, config table, I export them in /sys/firmware/
efi/systab, smbios is already in that file.

For efi runtime mapping I add a new directory /sys/firmware/efi/
efi-runtime-map/ like below
[dave@darkstar ~]$ tree /sys/firmware/efi/efi-runtime-map/
/sys/firmware/efi/efi-runtime-map/
├── 0
│   ├── attribute
│   ├── num_pages
│   ├── phys_addr
│   ├── type
│   └── virt_addr
├── 1
│   ├── attribute
│   ├── num_pages
│   ├── phys_addr
│   ├── type
│   └── virt_addr
[snip]
 
kexec-tools will assemble them as setup_data and pass to 2nd kernel.
I will send userspace patches as well.

Limitation is I only write support for x86_64, test on below machines:
Lenovo thinkpad t420
Dell inspiron 14 - 3421
HP Z420 workstation
Qemu + OVMF

Please help to review the patches.

The patches are based on matt's efi master tree

Changes from v1:
add one flag in xloadflags, so kexec-tools can safely load old kernel
without efi support.
coding style fixes
function name for map phys_addr to fixed virt_addr
Add ABI documentation for sysfs files
--
Thanks
Dave
--
To unsubscribe from this list: send the line unsubscribe linux-efi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[patch 3/3 v2] Passing efi related data via setup_data

2013-11-05 Thread dyoung
For supporting efi runtime, several efi physical addresses
fw_vendor, runtime, config tables, smbios and the whole runtime
mapping info need to be used in kexec kernel. Thus introduce
setup_data struct for passing these data.

collect the varialbes from /sys/firmware/efi/systab and
/sys/firmware/efi/efi-runtime-map

Tested on qemu+ovmf, dell laptop, lenovo laptop and HP workstation.

v1-v2:
HPA: use uint*_t instead of __uint*_t
Simon: indention fix; fix a memory leak
move offset change update to previous patch in setup header
only passing setup_data when the bzImage support efi boot
coding style

Signed-off-by: Dave Young dyo...@redhat.com
---
 kexec/arch/i386/x86-linux-setup.c |  132 +-
 1 file changed, 131 insertions(+), 1 deletion(-)

--- kexec-tools.orig/kexec/arch/i386/x86-linux-setup.c
+++ kexec-tools/kexec/arch/i386/x86-linux-setup.c
@@ -473,6 +473,134 @@ static void setup_efi_info(struct x86_li
get_bootparam(real_mode-efi_info, offset, 32);
 }
 
+struct efi_mem_descriptor {
+   uint32_t type;
+   uint32_t pad;
+   uint64_t phys_addr;
+   uint64_t virt_addr;
+   uint64_t num_pages;
+   uint64_t attribute;
+};
+
+struct efi_setup_data {
+   uint64_t fw_vendor;
+   uint64_t runtime;
+   uint64_t tables;
+   uint64_t smbios;
+   uint64_t reserved[8];
+   struct efi_mem_descriptor map[0];
+};
+
+struct setup_data {
+   uint64_t next;
+   uint32_t type;
+   uint32_t len;
+   uint8_t data[0];
+} __attribute__((packed));
+
+static void _get_efi_value(char *line, const char *pattern, __uint64_t *val)
+{
+   char *s, *end;
+   s = strstr(line, pattern);
+   if (s)
+   *val = strtoull(s + strlen(pattern), end, 16);
+}
+
+static void get_efi_value(struct efi_setup_data *esd)
+{
+   FILE *fp;
+   char line[1024];
+
+   fp = fopen(/sys/firmware/efi/systab, r);
+   if (!fp)
+   return;
+
+   while (fgets(line, sizeof(line), fp) != 0) {
+   _get_efi_value(line, fw_vendor=0x, esd-fw_vendor);
+   _get_efi_value(line, runtime=0x, esd-runtime);
+   _get_efi_value(line, config_tables=0x, esd-tables);
+   _get_efi_value(line, SMBIOS=0x, esd-smbios);
+   }
+
+   fclose(fp);
+}
+
+static int get_efi_runtime_map(struct efi_setup_data **esd)
+{
+   DIR *dirp;
+   struct dirent *entry;
+   char filename[1024];
+   struct efi_mem_descriptor md;
+   int nr_maps = 0;
+
+   dirp = opendir(/sys/firmware/efi/efi-runtime-map);
+   while ((entry = readdir(dirp)) != NULL) {
+   sprintf(filename,
+   /sys/firmware/efi/efi-runtime-map/%s,
+   (char *)entry-d_name);
+   if (*entry-d_name == '.')
+   continue;
+   file_scanf(filename, type, 0x%x, (unsigned int *)md.type);
+   file_scanf(filename, phys_addr, 0x%llx,
+  (unsigned long long *)md.phys_addr);
+   file_scanf(filename, virt_addr, 0x%llx,
+  (unsigned long long *)md.virt_addr);
+   file_scanf(filename, num_pages, 0x%llx,
+  (unsigned long long *)md.num_pages);
+   file_scanf(filename, attribute, 0x%llx,
+  (unsigned long long *)md.attribute);
+   *esd = realloc(*esd, sizeof(struct efi_setup_data) +
+  (nr_maps + 1) * sizeof(struct efi_mem_descriptor));
+   *((*esd)-map + nr_maps) = md;
+   nr_maps++;
+   }
+
+   closedir(dirp);
+   return nr_maps;
+}
+
+static void setup_efi_setup_data(struct kexec_info *info,
+   struct x86_linux_param_header *real_mode)
+{
+   int nr_maps;
+   int64_t setup_data_paddr;
+   struct setup_data *sd;
+   struct efi_setup_data *esd;
+   int size, sdsize;
+   int has_efi = 0;
+
+   has_efi = access(/sys/firmware/efi/systab, F_OK);
+   if (has_efi  0)
+   return;
+
+   esd = malloc(sizeof(struct efi_setup_data));
+   if (!esd)
+   return;
+   memset(esd, 0, sizeof(struct efi_setup_data));
+   get_efi_value(esd);
+   nr_maps = get_efi_runtime_map(esd);
+   size = nr_maps * sizeof(struct efi_mem_descriptor) +
+   sizeof(struct efi_setup_data);
+   sd = malloc(sizeof(struct setup_data) + size);
+   if (!sd) {
+   free(esd);
+   return;
+   }
+
+   memset(sd, 0, sizeof(struct setup_data) + size);
+   sd-next = 0;
+   sd-type = 4;
+   sd-len = size;
+   memcpy(sd-data, esd, size);
+   free(esd);
+   sdsize = sd-len + sizeof(struct setup_data);
+   setup_data_paddr = add_buffer(info, sd, sdsize, sdsize, getpagesize(),
+   0x10, ULONG_MAX, INT_MAX);
+
+   real_mode-setup_data = 

[patch 3/7 v2] Cleanup efi_enter_virtual_mode function

2013-11-05 Thread dyoung
Add two small functions:
efi_merge_regions and efi_map_regions, efi_enter_virtual_mode
calls them instead of embedding two long for loop.

v1-v2:
refresh; coding style fixes.

Signed-off-by: Dave Young dyo...@redhat.com
---
 arch/x86/platform/efi/efi.c |  107 +---
 1 file changed, 63 insertions(+), 44 deletions(-)

--- linux-2.6.orig/arch/x86/platform/efi/efi.c
+++ linux-2.6/arch/x86/platform/efi/efi.c
@@ -773,44 +773,12 @@ void __init old_map_region(efi_memory_de
   (unsigned long long)md-phys_addr);
 }
 
-/*
- * This function will switch the EFI runtime services to virtual mode.
- * Essentially, we look through the EFI memmap and map every region that
- * has the runtime attribute bit set in its memory descriptor into the
- * -trampoline_pgd page table using a top-down VA allocation scheme.
- *
- * The old method which used to update that memory descriptor with the
- * virtual address obtained from ioremap() is still supported when the
- * kernel is booted with efi=old_map on its command line. Same old
- * method enabled the runtime services to be called without having to
- * thunk back into physical mode for every invocation.
- *
- * The new method does a pagetable switch in a preemption-safe manner
- * so that we're in a different address space when calling a runtime
- * function. For function arguments passing we do copy the PGDs of the
- * kernel page table into -trampoline_pgd prior to each call.
- */
-void __init efi_enter_virtual_mode(void)
+/* Merge contiguous regions of the same type and attribute */
+static void efi_merge_regions(void)
 {
+   void *p;
efi_memory_desc_t *md, *prev_md = NULL;
-   void *p, *new_memmap = NULL;
-   unsigned long size;
-   efi_status_t status;
-   u64 end, systab;
-   int count = 0;
-
-   efi.systab = NULL;
-
-   /*
-* We don't do virtual mode, since we don't do runtime services, on
-* non-native EFI
-*/
-   if (!efi_is_native()) {
-   efi_unmap_memmap();
-   return;
-   }
 
-   /* Merge contiguous regions of the same type and attribute */
for (p = memmap.map; p  memmap.map_end; p += memmap.desc_size) {
u64 prev_size;
md = p;
@@ -837,6 +805,18 @@ void __init efi_enter_virtual_mode(void)
prev_md = md;
 
}
+}
+
+/*
+ * Map efi memory ranges for runtime serivce
+ * Return the new memmap with updated virtual addrresses.
+ */
+static void efi_map_regions(void **new_memmap, int *count)
+{
+   efi_memory_desc_t *md;
+   void *p;
+   unsigned long size;
+   u64 end, systab;
 
for (p = memmap.map; p  memmap.map_end; p += memmap.desc_size) {
md = p;
@@ -860,17 +840,59 @@ void __init efi_enter_virtual_mode(void)
efi.systab = (efi_system_table_t *) (unsigned long) 
systab;
}
 
-   new_memmap = krealloc(new_memmap,
- (count + 1) * memmap.desc_size,
- GFP_KERNEL);
-   if (!new_memmap)
+   *new_memmap = krealloc(*new_memmap,
+   (*count + 1) * memmap.desc_size,
+   GFP_KERNEL);
+   if (!*new_memmap)
goto err_out;
 
-   memcpy(new_memmap + (count * memmap.desc_size), md,
+   memcpy(*new_memmap + (*count * memmap.desc_size), md,
   memmap.desc_size);
-   count++;
+   (*count)++;
}
 
+err_out:
+   pr_err(Error reallocating memory, EFI runtime non-functional!\n);
+}
+
+/*
+ * This function will switch the EFI runtime services to virtual mode.
+ * Essentially, we look through the EFI memmap and map every region that
+ * has the runtime attribute bit set in its memory descriptor into the
+ * -trampoline_pgd page table using a top-down VA allocation scheme.
+ *
+ * The old method which used to update that memory descriptor with the
+ * virtual address obtained from ioremap() is still supported when the
+ * kernel is booted with efi=old_map on its command line. Same old
+ * method enabled the runtime services to be called without having to
+ * thunk back into physical mode for every invocation.
+ *
+ * The new method does a pagetable switch in a preemption-safe manner
+ * so that we're in a different address space when calling a runtime
+ * function. For function arguments passing we do copy the PGDs of the
+ * kernel page table into -trampoline_pgd prior to each call.
+ */
+void __init efi_enter_virtual_mode(void)
+{
+   efi_status_t status;
+   void *p, *new_memmap = NULL;
+   int count = 0;
+
+   efi.systab = NULL;
+
+   /*
+* We don't do virtual mode, since we don't do runtime services, on
+* non-native EFI
+*/
+   if (!efi_is_native()) {
+  

Re: [patch 0/7 v2] kexec kernel efi runtime support

2013-11-05 Thread Borislav Petkov
On Tue, Nov 05, 2013 at 04:20:07PM +0800, dyo...@redhat.com wrote:
 Please help to review the patches.

Sure, but will have to wait 'til next week when I get back.

Thanks.

-- 
Regards/Gruss,
Boris.
--
To unsubscribe from this list: send the line unsubscribe linux-efi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html