[PATCH -v6 1/3] x86 boot: setup data

From: Huang, Ying
Date: Mon Oct 22 2007 - 03:18:23 EST


This patch add a field of 64-bit physical pointer to NULL terminated
single linked list of struct setup_data to real-mode kernel
header. This is used as a more extensible boot parameters passing
mechanism.

Signed-off-by: Huang Ying <ying.huang@xxxxxxxxx>

---

arch/x86/boot/header.S | 8 +++++++-
arch/x86/kernel/e820_64.c | 6 +++---
arch/x86/kernel/head64.c | 26 ++++++++++++++++++++++++++
arch/x86/kernel/head_32.S | 37 ++++++++++++++++++++++++++++++++++++-
arch/x86/kernel/setup_32.c | 25 +++++++++++++++++++++++--
arch/x86/kernel/setup_64.c | 22 ++++++++++++++++++++--
arch/x86/mm/discontig_32.c | 3 ++-
include/asm-x86/bootparam.h | 15 +++++++++++++++
include/asm-x86/e820_64.h | 1 +
include/asm-x86/setup_32.h | 7 +++++++
include/asm-x86/setup_64.h | 2 ++
11 files changed, 142 insertions(+), 10 deletions(-)

Index: linux-2.6/include/asm-x86/bootparam.h
===================================================================
--- linux-2.6.orig/include/asm-x86/bootparam.h 2007-10-18 17:11:13.000000000 +0800
+++ linux-2.6/include/asm-x86/bootparam.h 2007-10-22 14:09:25.000000000 +0800
@@ -9,6 +9,17 @@
#include <asm/ist.h>
#include <video/edid.h>

+/* setup data types */
+#define SETUP_NONE 0
+
+/* extensible setup data list node */
+struct setup_data {
+ u64 next;
+ u32 type;
+ u32 len;
+ u8 data[0];
+} __attribute__((packed));
+
struct setup_header {
u8 setup_sects;
u16 root_flags;
@@ -41,6 +52,10 @@
u32 initrd_addr_max;
u32 kernel_alignment;
u8 relocatable_kernel;
+ u8 _pad2[3];
+ u32 cmdline_size;
+ u32 _pad3;
+ u64 setup_data;
} __attribute__((packed));

struct sys_desc_table {
Index: linux-2.6/arch/x86/boot/header.S
===================================================================
--- linux-2.6.orig/arch/x86/boot/header.S 2007-10-15 09:49:15.000000000 +0800
+++ linux-2.6/arch/x86/boot/header.S 2007-10-22 14:09:25.000000000 +0800
@@ -119,7 +119,7 @@
# Part 2 of the header, from the old setup.S

.ascii "HdrS" # header signature
- .word 0x0206 # header version number (>= 0x0105)
+ .word 0x0207 # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
.globl realmode_swtch
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
@@ -214,6 +214,12 @@
#added with boot protocol
#version 2.06

+pad4: .long 0
+
+setup_data: .quad 0 # 64-bit physical pointer to
+ # single linked list of
+ # struct setup_data
+
# End of setup header #####################################################

.section ".inittext", "ax"
Index: linux-2.6/arch/x86/kernel/setup_64.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/setup_64.c 2007-10-22 09:18:08.000000000 +0800
+++ linux-2.6/arch/x86/kernel/setup_64.c 2007-10-22 14:09:25.000000000 +0800
@@ -247,6 +247,22 @@
ebda_size = 64*1024;
}

+static void __init parse_setup_data(void)
+{
+ struct setup_data *data;
+
+ if (boot_params.hdr.version < 0x0207)
+ return;
+ for (data = __va(boot_params.hdr.setup_data);
+ data != __va(0);
+ data = __va(data->next)) {
+ switch (data->type) {
+ default:
+ break;
+ }
+ }
+}
+
void __init setup_arch(char **cmdline_p)
{
printk(KERN_INFO "Command line: %s\n", boot_command_line);
@@ -282,6 +298,8 @@
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;

+ parse_setup_data();
+
parse_early_param();

finish_e820_parsing();
@@ -340,9 +358,9 @@
reserve_bootmem_generic(table_start << PAGE_SHIFT,
(table_end - table_start) << PAGE_SHIFT);

- /* reserve kernel */
+ /* reserve kernel and setup data */
reserve_bootmem_generic(__pa_symbol(&_text),
- __pa_symbol(&_end) - __pa_symbol(&_text));
+ setup_data_end - __pa_symbol(&_text));

/*
* reserve physical page 0 - it's a special BIOS page on many boxes,
Index: linux-2.6/arch/x86/kernel/setup_32.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/setup_32.c 2007-10-22 09:18:08.000000000 +0800
+++ linux-2.6/arch/x86/kernel/setup_32.c 2007-10-22 14:09:25.000000000 +0800
@@ -66,6 +66,8 @@
address, and must not be in the .bss segment! */
unsigned long init_pg_tables_end __initdata = ~0UL;

+unsigned long setup_data_len __initdata;
+
int disable_pse __devinitdata = 0;

/*
@@ -327,7 +329,7 @@
* partially used pages are not usable - thus
* we are rounding upwards:
*/
- min_low_pfn = PFN_UP(init_pg_tables_end);
+ min_low_pfn = PFN_UP(init_pg_tables_end+setup_data_len);

find_max_pfn();

@@ -532,6 +534,22 @@
return machine_specific_memory_setup();
}

+static void __init parse_setup_data(void)
+{
+ struct setup_data *data;
+
+ if (boot_params.hdr.version < 0x0207)
+ return;
+ for (data = __va(boot_params.hdr.setup_data);
+ data != __va(0);
+ data = __va(data->next)) {
+ switch (data->type) {
+ default:
+ break;
+ }
+ }
+}
+
/*
* Determine if we were loaded by an EFI loader. If so, then we have also been
* passed the efi memmap, systab, etc., so we should use these data structures
@@ -579,6 +597,9 @@
rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
#endif
+
+ parse_setup_data();
+
ARCH_SETUP
if (efi_enabled)
efi_init();
@@ -594,7 +615,7 @@
init_mm.start_code = (unsigned long) _text;
init_mm.end_code = (unsigned long) _etext;
init_mm.end_data = (unsigned long) _edata;
- init_mm.brk = init_pg_tables_end + PAGE_OFFSET;
+ init_mm.brk = init_pg_tables_end + setup_data_len + PAGE_OFFSET;

code_resource.start = virt_to_phys(_text);
code_resource.end = virt_to_phys(_etext)-1;
Index: linux-2.6/arch/x86/kernel/e820_64.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/e820_64.c 2007-10-22 09:18:08.000000000 +0800
+++ linux-2.6/arch/x86/kernel/e820_64.c 2007-10-22 14:09:25.000000000 +0800
@@ -79,9 +79,9 @@
}
}
#endif
- /* kernel code */
- if (last >= __pa_symbol(&_text) && addr < __pa_symbol(&_end)) {
- *addrp = PAGE_ALIGN(__pa_symbol(&_end));
+ /* kernel code and setup data */
+ if (last >= __pa_symbol(&_text) && addr < setup_data_end) {
+ *addrp = PAGE_ALIGN(setup_data_end);
return 1;
}

Index: linux-2.6/arch/x86/kernel/head64.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/head64.c 2007-10-22 09:18:08.000000000 +0800
+++ linux-2.6/arch/x86/kernel/head64.c 2007-10-22 14:09:25.000000000 +0800
@@ -19,6 +19,9 @@
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <asm/sections.h>
+#include <asm/io.h>
+
+unsigned long __initdata setup_data_end;

static void __init zap_identity_mappings(void)
{
@@ -38,12 +41,35 @@
static void __init copy_bootdata(char *real_mode_data)
{
char * command_line;
+ void *sdata_dst;
+ struct setup_data *sdata;
+ u64 *ppa_next;
+ unsigned long sdata_len;

memcpy(&boot_params, real_mode_data, sizeof boot_params);
if (boot_params.hdr.cmd_line_ptr) {
command_line = __va(boot_params.hdr.cmd_line_ptr);
memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
}
+
+#define SETUP_DATA_ALIGN(addr) \
+ (((unsigned long)(addr)+(SETUP_DATA_ALIGN_SIZE-1))& \
+ ~(SETUP_DATA_ALIGN_SIZE-1))
+
+ sdata_dst = __va(SETUP_DATA_ALIGN(__pa_symbol(&_end)));
+ ppa_next = &boot_params.hdr.setup_data;
+ while (*ppa_next) {
+ sdata = early_ioremap(*ppa_next, sizeof(*sdata));
+ sdata_len = sizeof(*sdata) + sdata->len;
+ early_iounmap(sdata, sizeof(*sdata));
+ sdata = early_ioremap(*ppa_next, sdata_len);
+ memcpy(sdata_dst, sdata, sdata_len);
+ early_iounmap(sdata, sdata_len);
+ *ppa_next = __pa(sdata_dst);
+ ppa_next = &((struct setup_data *)sdata_dst)->next;
+ sdata_dst = (void *)SETUP_DATA_ALIGN(sdata_dst+sdata_len);
+ }
+ setup_data_end = __pa(sdata_dst);
}

void __init x86_64_start_kernel(char * real_mode_data)
Index: linux-2.6/include/asm-x86/e820_64.h
===================================================================
--- linux-2.6.orig/include/asm-x86/e820_64.h 2007-10-15 09:49:20.000000000 +0800
+++ linux-2.6/include/asm-x86/e820_64.h 2007-10-22 14:09:25.000000000 +0800
@@ -56,6 +56,7 @@

extern unsigned ebda_addr, ebda_size;
extern unsigned long nodemap_addr, nodemap_size;
+extern unsigned long setup_data_end;
#endif/*!__ASSEMBLY__*/

#endif/*__E820_HEADER*/
Index: linux-2.6/arch/x86/kernel/head_32.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/head_32.S 2007-10-18 17:11:11.000000000 +0800
+++ linux-2.6/arch/x86/kernel/head_32.S 2007-10-22 14:09:25.000000000 +0800
@@ -127,6 +127,21 @@
rep
movsl
1:
+ movl boot_params - __PAGE_OFFSET + SETUP_DATA_POINTER,%ebp
+ xorl %ecx,%ecx
+2:
+ andl %ebp,%ebp
+ jz 1f
+ movl $(SETUP_DATA_HEADER_LEN+SETUP_DATA_ALIGN_SIZE-1),%eax
+ addl (SETUP_DATA_LEN)(%ebp),%eax
+ andl $~(SETUP_DATA_ALIGN_SIZE-1),%eax
+ addl %eax, %ecx
+ movl SETUP_DATA_NEXT(%ebp),%ebp
+ jmp 2b
+1:
+ addl $(PAGE_SIZE_asm-1),%ecx
+ andl $~(PAGE_SIZE_asm-1),%ecx
+ movl %ecx,(setup_data_len - __PAGE_OFFSET)

/*
* Initialize page tables. This creates a PDE and a set of page
@@ -153,13 +168,33 @@
stosl
addl $0x1000,%eax
loop 11b
- /* End condition: we must map up to and including INIT_MAP_BEYOND_END */
+ /* End condition: we must map up to and including INIT_MAP_BEYOND_END + setup_data_len */
/* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */
leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp
+ addl (setup_data_len - __PAGE_OFFSET),%ebp
cmpl %ebp,%eax
jb 10b
movl %edi,(init_pg_tables_end - __PAGE_OFFSET)

+ /* Copy setup data */
+ leal (boot_params - __PAGE_OFFSET + SETUP_DATA_POINTER),%ebx
+2:
+ movl (%ebx),%ebp
+ andl %ebp,%ebp
+ jz 1f
+ movl $SETUP_DATA_HEADER_LEN,%ecx
+ addl SETUP_DATA_LEN(%ebp),%ecx
+ addl $(SETUP_DATA_ALIGN_SIZE-1),%edi
+ andl $~(SETUP_DATA_ALIGN_SIZE-1),%edi
+ movl %edi,(%ebx)
+ movl %ebp,%esi
+ rep
+ movsb
+ movl (%ebx),%ebx
+ leal SETUP_DATA_NEXT(%ebx),%ebx
+ jmp 2b
+1:
+
xorl %ebx,%ebx /* This is the boot CPU (BSP) */
jmp 3f
/*
Index: linux-2.6/arch/x86/mm/discontig_32.c
===================================================================
--- linux-2.6.orig/arch/x86/mm/discontig_32.c 2007-10-22 09:18:09.000000000 +0800
+++ linux-2.6/arch/x86/mm/discontig_32.c 2007-10-22 14:09:25.000000000 +0800
@@ -282,7 +282,8 @@
kva_pages = calculate_numa_remap_pages();

/* partially used pages are not usable - thus round upwards */
- system_start_pfn = min_low_pfn = PFN_UP(init_pg_tables_end);
+ system_start_pfn = min_low_pfn = PFN_UP(init_pg_tables_end +
+ setup_data_len);

kva_start_pfn = find_max_low_pfn() - kva_pages;

Index: linux-2.6/include/asm-x86/setup_32.h
===================================================================
--- linux-2.6.orig/include/asm-x86/setup_32.h 2007-10-18 17:11:13.000000000 +0800
+++ linux-2.6/include/asm-x86/setup_32.h 2007-10-22 14:09:25.000000000 +0800
@@ -25,6 +25,13 @@
#define OLD_CL_OFFSET 0x90022
#define NEW_CL_POINTER 0x228 /* Relative to real mode data */

+#define SETUP_DATA_POINTER 0x240 /* Relative to real mode data */
+
+#define SETUP_DATA_NEXT 0x0
+#define SETUP_DATA_LEN 0xc
+#define SETUP_DATA_HEADER_LEN 0x10
+#define SETUP_DATA_ALIGN_SIZE 0x8
+
#ifndef __ASSEMBLY__

#include <asm/bootparam.h>
Index: linux-2.6/include/asm-x86/setup_64.h
===================================================================
--- linux-2.6.orig/include/asm-x86/setup_64.h 2007-10-18 17:11:13.000000000 +0800
+++ linux-2.6/include/asm-x86/setup_64.h 2007-10-22 14:09:25.000000000 +0800
@@ -4,7 +4,9 @@
#define COMMAND_LINE_SIZE 2048

#ifdef __KERNEL__
+#include <linux/const.h>

+#define SETUP_DATA_ALIGN_SIZE __AC(0x8,UL)
#ifndef __ASSEMBLY__
#include <asm/bootparam.h>

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/