aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang, Ying <ying.huang@intel.com>2008-06-10 23:33:39 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-08 04:37:39 -0400
commit8c5beb50d3ec915d15c4d38aa37282309a65f14e (patch)
treeace1ef10fb672f0e28182ffc9e460147455c2ea8
parentb5bc6c0e55000dab86b73f838f5ad02908b23755 (diff)
x86 boot: pass E820 memory map entries more than 128 via linked list of setup data
Because of the size limits of struct boot_params (zero page), the maximum number of E820 memory map entries can be passed to kernel is 128. As pointed by Paul Jackson, there is some machine produced by SGI with so many nodes that the number of E820 memory map entries is more than 128. To enabling Linux kernel on these system, a new setup data type named SETUP_E820_EXT is defined to pass additional memory map entries to Linux kernel. This patch is based on x86/auto-latest branch of git-x86 tree and has been tested on x86_64 and i386 platform. Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/kernel/e820.c59
-rw-r--r--arch/x86/kernel/setup.c3
-rw-r--r--include/asm-x86/bootparam.h1
-rw-r--r--include/asm-x86/e820.h2
4 files changed, 52 insertions, 13 deletions
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index ed46b7a6bc13..544dd12c70f4 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -359,6 +359,26 @@ static struct e820entry new_bios[E820_X_MAX] __initdata;
359 return 0; 359 return 0;
360} 360}
361 361
362static int __init __copy_e820_map(struct e820entry *biosmap, int nr_map)
363{
364 while (nr_map) {
365 u64 start = biosmap->addr;
366 u64 size = biosmap->size;
367 u64 end = start + size;
368 u32 type = biosmap->type;
369
370 /* Overflow in 64 bits? Ignore the memory map. */
371 if (start > end)
372 return -1;
373
374 e820_add_region(start, size, type);
375
376 biosmap++;
377 nr_map--;
378 }
379 return 0;
380}
381
362/* 382/*
363 * Copy the BIOS e820 map into a safe place. 383 * Copy the BIOS e820 map into a safe place.
364 * 384 *
@@ -374,19 +394,7 @@ int __init copy_e820_map(struct e820entry *biosmap, int nr_map)
374 if (nr_map < 2) 394 if (nr_map < 2)
375 return -1; 395 return -1;
376 396
377 do { 397 return __copy_e820_map(biosmap, nr_map);
378 u64 start = biosmap->addr;
379 u64 size = biosmap->size;
380 u64 end = start + size;
381 u32 type = biosmap->type;
382
383 /* Overflow in 64 bits? Ignore the memory map. */
384 if (start > end)
385 return -1;
386
387 e820_add_region(start, size, type);
388 } while (biosmap++, --nr_map);
389 return 0;
390} 398}
391 399
392u64 __init e820_update_range(u64 start, u64 size, unsigned old_type, 400u64 __init e820_update_range(u64 start, u64 size, unsigned old_type,
@@ -496,6 +504,31 @@ __init void e820_setup_gap(void)
496 pci_mem_start, gapstart, gapsize); 504 pci_mem_start, gapstart, gapsize);
497} 505}
498 506
507/**
508 * Because of the size limitation of struct boot_params, only first
509 * 128 E820 memory entries are passed to kernel via
510 * boot_params.e820_map, others are passed via SETUP_E820_EXT node of
511 * linked list of struct setup_data, which is parsed here.
512 */
513void __init parse_e820_ext(struct setup_data *sdata, unsigned long pa_data)
514{
515 u32 map_len;
516 int entries;
517 struct e820entry *extmap;
518
519 entries = sdata->len / sizeof(struct e820entry);
520 map_len = sdata->len + sizeof(struct setup_data);
521 if (map_len > PAGE_SIZE)
522 sdata = early_ioremap(pa_data, map_len);
523 extmap = (struct e820entry *)(sdata->data);
524 __copy_e820_map(extmap, entries);
525 sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
526 if (map_len > PAGE_SIZE)
527 early_iounmap(sdata, map_len);
528 printk(KERN_INFO "extended physical RAM map:\n");
529 e820_print_map("extended");
530}
531
499#if defined(CONFIG_X86_64) || \ 532#if defined(CONFIG_X86_64) || \
500 (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION)) 533 (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION))
501/** 534/**
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 45a5e247d450..5b0de38cde48 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -150,6 +150,9 @@ void __init parse_setup_data(void)
150 while (pa_data) { 150 while (pa_data) {
151 data = early_ioremap(pa_data, PAGE_SIZE); 151 data = early_ioremap(pa_data, PAGE_SIZE);
152 switch (data->type) { 152 switch (data->type) {
153 case SETUP_E820_EXT:
154 parse_e820_ext(data, pa_data);
155 break;
153 default: 156 default:
154 break; 157 break;
155 } 158 }
diff --git a/include/asm-x86/bootparam.h b/include/asm-x86/bootparam.h
index 0a073904168b..876f21136660 100644
--- a/include/asm-x86/bootparam.h
+++ b/include/asm-x86/bootparam.h
@@ -11,6 +11,7 @@
11 11
12/* setup data types */ 12/* setup data types */
13#define SETUP_NONE 0 13#define SETUP_NONE 0
14#define SETUP_E820_EXT 1
14 15
15/* extensible setup data list node */ 16/* extensible setup data list node */
16struct setup_data { 17struct setup_data {
diff --git a/include/asm-x86/e820.h b/include/asm-x86/e820.h
index 55d310596907..77fc24d89163 100644
--- a/include/asm-x86/e820.h
+++ b/include/asm-x86/e820.h
@@ -69,6 +69,8 @@ extern u64 e820_update_range(u64 start, u64 size, unsigned old_type,
69 unsigned new_type); 69 unsigned new_type);
70extern void update_e820(void); 70extern void update_e820(void);
71extern void e820_setup_gap(void); 71extern void e820_setup_gap(void);
72struct setup_data;
73extern void parse_e820_ext(struct setup_data *data, unsigned long pa_data);
72 74
73#if defined(CONFIG_X86_64) || \ 75#if defined(CONFIG_X86_64) || \
74 (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION)) 76 (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION))