diff options
Diffstat (limited to 'arch/x86/kernel/head64.c')
-rw-r--r-- | arch/x86/kernel/head64.c | 45 |
1 files changed, 27 insertions, 18 deletions
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 38f32e798a99..b684552347df 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c | |||
@@ -49,33 +49,42 @@ static void __init copy_bootdata(char *real_mode_data) | |||
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||
52 | #define EBDA_ADDR_POINTER 0x40E | 52 | #define BIOS_EBDA_SEGMENT 0x40E |
53 | #define BIOS_LOWMEM_KILOBYTES 0x413 | ||
53 | 54 | ||
55 | /* | ||
56 | * The BIOS places the EBDA/XBDA at the top of conventional | ||
57 | * memory, and usually decreases the reported amount of | ||
58 | * conventional memory (int 0x12) too. | ||
59 | */ | ||
54 | static __init void reserve_ebda(void) | 60 | static __init void reserve_ebda(void) |
55 | { | 61 | { |
56 | unsigned ebda_addr, ebda_size; | 62 | unsigned int lowmem, ebda_addr; |
57 | 63 | ||
58 | /* | 64 | /* end of low (conventional) memory */ |
59 | * there is a real-mode segmented pointer pointing to the | 65 | lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES); |
60 | * 4K EBDA area at 0x40E | 66 | lowmem <<= 10; |
61 | */ | 67 | |
62 | ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER); | 68 | /* start of EBDA area */ |
69 | ebda_addr = *(unsigned short *)__va(BIOS_EBDA_SEGMENT); | ||
63 | ebda_addr <<= 4; | 70 | ebda_addr <<= 4; |
64 | 71 | ||
65 | if (!ebda_addr) | 72 | /* Fixup: bios puts an EBDA in the top 64K segment */ |
66 | return; | 73 | /* of conventional memory, but does not adjust lowmem. */ |
74 | if ((lowmem - ebda_addr) <= 0x10000) | ||
75 | lowmem = ebda_addr; | ||
67 | 76 | ||
68 | ebda_size = *(unsigned short *)__va(ebda_addr); | 77 | /* Fixup: bios does not report an EBDA at all. */ |
78 | /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */ | ||
79 | if ((ebda_addr == 0) && (lowmem >= 0x9f000)) | ||
80 | lowmem = 0x9f000; | ||
69 | 81 | ||
70 | /* Round EBDA up to pages */ | 82 | /* Paranoia: should never happen, but... */ |
71 | if (ebda_size == 0) | 83 | if (lowmem >= 0x100000) |
72 | ebda_size = 1; | 84 | lowmem = 0xa0000; |
73 | ebda_size <<= 10; | ||
74 | ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE); | ||
75 | if (ebda_size > 64*1024) | ||
76 | ebda_size = 64*1024; | ||
77 | 85 | ||
78 | reserve_early(ebda_addr, ebda_addr + ebda_size, "EBDA"); | 86 | /* reserve all memory between lowmem and the 1MB mark */ |
87 | reserve_early(lowmem, 0x100000, "BIOS reserved"); | ||
79 | } | 88 | } |
80 | 89 | ||
81 | void __init x86_64_start_kernel(char * real_mode_data) | 90 | void __init x86_64_start_kernel(char * real_mode_data) |