Commit 92aa63a5a1bf2e7b0c79e6716d24b76dbbdcf951
Committed by
Linus Torvalds
1 parent
d58831e416
Exists in
master
and in
39 other branches
[PATCH] kdump: Retrieve saved max pfn
This patch retrieves the max_pfn being used by previous kernel and stores it in a safe location (saved_max_pfn) before it is overwritten due to user defined memory map. This pfn is used to make sure that user does not try to read the physical memory beyond saved_max_pfn. Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 3 changed files with 24 additions and 0 deletions Inline Diff
arch/i386/kernel/setup.c
1 | /* | 1 | /* |
2 | * linux/arch/i386/kernel/setup.c | 2 | * linux/arch/i386/kernel/setup.c |
3 | * | 3 | * |
4 | * Copyright (C) 1995 Linus Torvalds | 4 | * Copyright (C) 1995 Linus Torvalds |
5 | * | 5 | * |
6 | * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 | 6 | * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 |
7 | * | 7 | * |
8 | * Memory region support | 8 | * Memory region support |
9 | * David Parsons <orc@pell.chi.il.us>, July-August 1999 | 9 | * David Parsons <orc@pell.chi.il.us>, July-August 1999 |
10 | * | 10 | * |
11 | * Added E820 sanitization routine (removes overlapping memory regions); | 11 | * Added E820 sanitization routine (removes overlapping memory regions); |
12 | * Brian Moyle <bmoyle@mvista.com>, February 2001 | 12 | * Brian Moyle <bmoyle@mvista.com>, February 2001 |
13 | * | 13 | * |
14 | * Moved CPU detection code to cpu/${cpu}.c | 14 | * Moved CPU detection code to cpu/${cpu}.c |
15 | * Patrick Mochel <mochel@osdl.org>, March 2002 | 15 | * Patrick Mochel <mochel@osdl.org>, March 2002 |
16 | * | 16 | * |
17 | * Provisions for empty E820 memory regions (reported by certain BIOSes). | 17 | * Provisions for empty E820 memory regions (reported by certain BIOSes). |
18 | * Alex Achenbach <xela@slit.de>, December 2002. | 18 | * Alex Achenbach <xela@slit.de>, December 2002. |
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * This file handles the architecture-dependent parts of initialization | 23 | * This file handles the architecture-dependent parts of initialization |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/config.h> | 26 | #include <linux/config.h> |
27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
29 | #include <linux/mmzone.h> | 29 | #include <linux/mmzone.h> |
30 | #include <linux/tty.h> | 30 | #include <linux/tty.h> |
31 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
32 | #include <linux/acpi.h> | 32 | #include <linux/acpi.h> |
33 | #include <linux/apm_bios.h> | 33 | #include <linux/apm_bios.h> |
34 | #include <linux/initrd.h> | 34 | #include <linux/initrd.h> |
35 | #include <linux/bootmem.h> | 35 | #include <linux/bootmem.h> |
36 | #include <linux/seq_file.h> | 36 | #include <linux/seq_file.h> |
37 | #include <linux/console.h> | 37 | #include <linux/console.h> |
38 | #include <linux/mca.h> | 38 | #include <linux/mca.h> |
39 | #include <linux/root_dev.h> | 39 | #include <linux/root_dev.h> |
40 | #include <linux/highmem.h> | 40 | #include <linux/highmem.h> |
41 | #include <linux/module.h> | 41 | #include <linux/module.h> |
42 | #include <linux/efi.h> | 42 | #include <linux/efi.h> |
43 | #include <linux/init.h> | 43 | #include <linux/init.h> |
44 | #include <linux/edd.h> | 44 | #include <linux/edd.h> |
45 | #include <linux/nodemask.h> | 45 | #include <linux/nodemask.h> |
46 | #include <linux/kexec.h> | 46 | #include <linux/kexec.h> |
47 | 47 | ||
48 | #include <video/edid.h> | 48 | #include <video/edid.h> |
49 | 49 | ||
50 | #include <asm/apic.h> | 50 | #include <asm/apic.h> |
51 | #include <asm/e820.h> | 51 | #include <asm/e820.h> |
52 | #include <asm/mpspec.h> | 52 | #include <asm/mpspec.h> |
53 | #include <asm/setup.h> | 53 | #include <asm/setup.h> |
54 | #include <asm/arch_hooks.h> | 54 | #include <asm/arch_hooks.h> |
55 | #include <asm/sections.h> | 55 | #include <asm/sections.h> |
56 | #include <asm/io_apic.h> | 56 | #include <asm/io_apic.h> |
57 | #include <asm/ist.h> | 57 | #include <asm/ist.h> |
58 | #include <asm/io.h> | 58 | #include <asm/io.h> |
59 | #include "setup_arch_pre.h" | 59 | #include "setup_arch_pre.h" |
60 | #include <bios_ebda.h> | 60 | #include <bios_ebda.h> |
61 | 61 | ||
62 | /* Forward Declaration. */ | ||
63 | void __init find_max_pfn(void); | ||
64 | |||
62 | /* This value is set up by the early boot code to point to the value | 65 | /* This value is set up by the early boot code to point to the value |
63 | immediately after the boot time page tables. It contains a *physical* | 66 | immediately after the boot time page tables. It contains a *physical* |
64 | address, and must not be in the .bss segment! */ | 67 | address, and must not be in the .bss segment! */ |
65 | unsigned long init_pg_tables_end __initdata = ~0UL; | 68 | unsigned long init_pg_tables_end __initdata = ~0UL; |
66 | 69 | ||
67 | int disable_pse __devinitdata = 0; | 70 | int disable_pse __devinitdata = 0; |
68 | 71 | ||
69 | /* | 72 | /* |
70 | * Machine setup.. | 73 | * Machine setup.. |
71 | */ | 74 | */ |
72 | 75 | ||
73 | #ifdef CONFIG_EFI | 76 | #ifdef CONFIG_EFI |
74 | int efi_enabled = 0; | 77 | int efi_enabled = 0; |
75 | EXPORT_SYMBOL(efi_enabled); | 78 | EXPORT_SYMBOL(efi_enabled); |
76 | #endif | 79 | #endif |
77 | 80 | ||
78 | /* cpu data as detected by the assembly code in head.S */ | 81 | /* cpu data as detected by the assembly code in head.S */ |
79 | struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; | 82 | struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; |
80 | /* common cpu data for all cpus */ | 83 | /* common cpu data for all cpus */ |
81 | struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; | 84 | struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; |
82 | EXPORT_SYMBOL(boot_cpu_data); | 85 | EXPORT_SYMBOL(boot_cpu_data); |
83 | 86 | ||
84 | unsigned long mmu_cr4_features; | 87 | unsigned long mmu_cr4_features; |
85 | 88 | ||
86 | #ifdef CONFIG_ACPI_INTERPRETER | 89 | #ifdef CONFIG_ACPI_INTERPRETER |
87 | int acpi_disabled = 0; | 90 | int acpi_disabled = 0; |
88 | #else | 91 | #else |
89 | int acpi_disabled = 1; | 92 | int acpi_disabled = 1; |
90 | #endif | 93 | #endif |
91 | EXPORT_SYMBOL(acpi_disabled); | 94 | EXPORT_SYMBOL(acpi_disabled); |
92 | 95 | ||
93 | #ifdef CONFIG_ACPI_BOOT | 96 | #ifdef CONFIG_ACPI_BOOT |
94 | int __initdata acpi_force = 0; | 97 | int __initdata acpi_force = 0; |
95 | extern acpi_interrupt_flags acpi_sci_flags; | 98 | extern acpi_interrupt_flags acpi_sci_flags; |
96 | #endif | 99 | #endif |
97 | 100 | ||
98 | /* for MCA, but anyone else can use it if they want */ | 101 | /* for MCA, but anyone else can use it if they want */ |
99 | unsigned int machine_id; | 102 | unsigned int machine_id; |
100 | #ifdef CONFIG_MCA | 103 | #ifdef CONFIG_MCA |
101 | EXPORT_SYMBOL(machine_id); | 104 | EXPORT_SYMBOL(machine_id); |
102 | #endif | 105 | #endif |
103 | unsigned int machine_submodel_id; | 106 | unsigned int machine_submodel_id; |
104 | unsigned int BIOS_revision; | 107 | unsigned int BIOS_revision; |
105 | unsigned int mca_pentium_flag; | 108 | unsigned int mca_pentium_flag; |
106 | 109 | ||
107 | /* For PCI or other memory-mapped resources */ | 110 | /* For PCI or other memory-mapped resources */ |
108 | unsigned long pci_mem_start = 0x10000000; | 111 | unsigned long pci_mem_start = 0x10000000; |
109 | #ifdef CONFIG_PCI | 112 | #ifdef CONFIG_PCI |
110 | EXPORT_SYMBOL(pci_mem_start); | 113 | EXPORT_SYMBOL(pci_mem_start); |
111 | #endif | 114 | #endif |
112 | 115 | ||
113 | /* Boot loader ID as an integer, for the benefit of proc_dointvec */ | 116 | /* Boot loader ID as an integer, for the benefit of proc_dointvec */ |
114 | int bootloader_type; | 117 | int bootloader_type; |
115 | 118 | ||
116 | /* user-defined highmem size */ | 119 | /* user-defined highmem size */ |
117 | static unsigned int highmem_pages = -1; | 120 | static unsigned int highmem_pages = -1; |
118 | 121 | ||
119 | /* | 122 | /* |
120 | * Setup options | 123 | * Setup options |
121 | */ | 124 | */ |
122 | struct drive_info_struct { char dummy[32]; } drive_info; | 125 | struct drive_info_struct { char dummy[32]; } drive_info; |
123 | #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || \ | 126 | #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || \ |
124 | defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) | 127 | defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) |
125 | EXPORT_SYMBOL(drive_info); | 128 | EXPORT_SYMBOL(drive_info); |
126 | #endif | 129 | #endif |
127 | struct screen_info screen_info; | 130 | struct screen_info screen_info; |
128 | #ifdef CONFIG_VT | 131 | #ifdef CONFIG_VT |
129 | EXPORT_SYMBOL(screen_info); | 132 | EXPORT_SYMBOL(screen_info); |
130 | #endif | 133 | #endif |
131 | struct apm_info apm_info; | 134 | struct apm_info apm_info; |
132 | EXPORT_SYMBOL(apm_info); | 135 | EXPORT_SYMBOL(apm_info); |
133 | struct sys_desc_table_struct { | 136 | struct sys_desc_table_struct { |
134 | unsigned short length; | 137 | unsigned short length; |
135 | unsigned char table[0]; | 138 | unsigned char table[0]; |
136 | }; | 139 | }; |
137 | struct edid_info edid_info; | 140 | struct edid_info edid_info; |
138 | struct ist_info ist_info; | 141 | struct ist_info ist_info; |
139 | #if defined(CONFIG_X86_SPEEDSTEP_SMI) || \ | 142 | #if defined(CONFIG_X86_SPEEDSTEP_SMI) || \ |
140 | defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) | 143 | defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) |
141 | EXPORT_SYMBOL(ist_info); | 144 | EXPORT_SYMBOL(ist_info); |
142 | #endif | 145 | #endif |
143 | struct e820map e820; | 146 | struct e820map e820; |
144 | 147 | ||
145 | extern void early_cpu_init(void); | 148 | extern void early_cpu_init(void); |
146 | extern void dmi_scan_machine(void); | 149 | extern void dmi_scan_machine(void); |
147 | extern void generic_apic_probe(char *); | 150 | extern void generic_apic_probe(char *); |
148 | extern int root_mountflags; | 151 | extern int root_mountflags; |
149 | 152 | ||
150 | unsigned long saved_videomode; | 153 | unsigned long saved_videomode; |
151 | 154 | ||
152 | #define RAMDISK_IMAGE_START_MASK 0x07FF | 155 | #define RAMDISK_IMAGE_START_MASK 0x07FF |
153 | #define RAMDISK_PROMPT_FLAG 0x8000 | 156 | #define RAMDISK_PROMPT_FLAG 0x8000 |
154 | #define RAMDISK_LOAD_FLAG 0x4000 | 157 | #define RAMDISK_LOAD_FLAG 0x4000 |
155 | 158 | ||
156 | static char command_line[COMMAND_LINE_SIZE]; | 159 | static char command_line[COMMAND_LINE_SIZE]; |
157 | 160 | ||
158 | unsigned char __initdata boot_params[PARAM_SIZE]; | 161 | unsigned char __initdata boot_params[PARAM_SIZE]; |
159 | 162 | ||
160 | static struct resource data_resource = { | 163 | static struct resource data_resource = { |
161 | .name = "Kernel data", | 164 | .name = "Kernel data", |
162 | .start = 0, | 165 | .start = 0, |
163 | .end = 0, | 166 | .end = 0, |
164 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM | 167 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM |
165 | }; | 168 | }; |
166 | 169 | ||
167 | static struct resource code_resource = { | 170 | static struct resource code_resource = { |
168 | .name = "Kernel code", | 171 | .name = "Kernel code", |
169 | .start = 0, | 172 | .start = 0, |
170 | .end = 0, | 173 | .end = 0, |
171 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM | 174 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM |
172 | }; | 175 | }; |
173 | 176 | ||
174 | static struct resource system_rom_resource = { | 177 | static struct resource system_rom_resource = { |
175 | .name = "System ROM", | 178 | .name = "System ROM", |
176 | .start = 0xf0000, | 179 | .start = 0xf0000, |
177 | .end = 0xfffff, | 180 | .end = 0xfffff, |
178 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | 181 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
179 | }; | 182 | }; |
180 | 183 | ||
181 | static struct resource extension_rom_resource = { | 184 | static struct resource extension_rom_resource = { |
182 | .name = "Extension ROM", | 185 | .name = "Extension ROM", |
183 | .start = 0xe0000, | 186 | .start = 0xe0000, |
184 | .end = 0xeffff, | 187 | .end = 0xeffff, |
185 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | 188 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
186 | }; | 189 | }; |
187 | 190 | ||
188 | static struct resource adapter_rom_resources[] = { { | 191 | static struct resource adapter_rom_resources[] = { { |
189 | .name = "Adapter ROM", | 192 | .name = "Adapter ROM", |
190 | .start = 0xc8000, | 193 | .start = 0xc8000, |
191 | .end = 0, | 194 | .end = 0, |
192 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | 195 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
193 | }, { | 196 | }, { |
194 | .name = "Adapter ROM", | 197 | .name = "Adapter ROM", |
195 | .start = 0, | 198 | .start = 0, |
196 | .end = 0, | 199 | .end = 0, |
197 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | 200 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
198 | }, { | 201 | }, { |
199 | .name = "Adapter ROM", | 202 | .name = "Adapter ROM", |
200 | .start = 0, | 203 | .start = 0, |
201 | .end = 0, | 204 | .end = 0, |
202 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | 205 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
203 | }, { | 206 | }, { |
204 | .name = "Adapter ROM", | 207 | .name = "Adapter ROM", |
205 | .start = 0, | 208 | .start = 0, |
206 | .end = 0, | 209 | .end = 0, |
207 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | 210 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
208 | }, { | 211 | }, { |
209 | .name = "Adapter ROM", | 212 | .name = "Adapter ROM", |
210 | .start = 0, | 213 | .start = 0, |
211 | .end = 0, | 214 | .end = 0, |
212 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | 215 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
213 | }, { | 216 | }, { |
214 | .name = "Adapter ROM", | 217 | .name = "Adapter ROM", |
215 | .start = 0, | 218 | .start = 0, |
216 | .end = 0, | 219 | .end = 0, |
217 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | 220 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
218 | } }; | 221 | } }; |
219 | 222 | ||
220 | #define ADAPTER_ROM_RESOURCES \ | 223 | #define ADAPTER_ROM_RESOURCES \ |
221 | (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0]) | 224 | (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0]) |
222 | 225 | ||
223 | static struct resource video_rom_resource = { | 226 | static struct resource video_rom_resource = { |
224 | .name = "Video ROM", | 227 | .name = "Video ROM", |
225 | .start = 0xc0000, | 228 | .start = 0xc0000, |
226 | .end = 0xc7fff, | 229 | .end = 0xc7fff, |
227 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | 230 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
228 | }; | 231 | }; |
229 | 232 | ||
230 | static struct resource video_ram_resource = { | 233 | static struct resource video_ram_resource = { |
231 | .name = "Video RAM area", | 234 | .name = "Video RAM area", |
232 | .start = 0xa0000, | 235 | .start = 0xa0000, |
233 | .end = 0xbffff, | 236 | .end = 0xbffff, |
234 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM | 237 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM |
235 | }; | 238 | }; |
236 | 239 | ||
237 | static struct resource standard_io_resources[] = { { | 240 | static struct resource standard_io_resources[] = { { |
238 | .name = "dma1", | 241 | .name = "dma1", |
239 | .start = 0x0000, | 242 | .start = 0x0000, |
240 | .end = 0x001f, | 243 | .end = 0x001f, |
241 | .flags = IORESOURCE_BUSY | IORESOURCE_IO | 244 | .flags = IORESOURCE_BUSY | IORESOURCE_IO |
242 | }, { | 245 | }, { |
243 | .name = "pic1", | 246 | .name = "pic1", |
244 | .start = 0x0020, | 247 | .start = 0x0020, |
245 | .end = 0x0021, | 248 | .end = 0x0021, |
246 | .flags = IORESOURCE_BUSY | IORESOURCE_IO | 249 | .flags = IORESOURCE_BUSY | IORESOURCE_IO |
247 | }, { | 250 | }, { |
248 | .name = "timer0", | 251 | .name = "timer0", |
249 | .start = 0x0040, | 252 | .start = 0x0040, |
250 | .end = 0x0043, | 253 | .end = 0x0043, |
251 | .flags = IORESOURCE_BUSY | IORESOURCE_IO | 254 | .flags = IORESOURCE_BUSY | IORESOURCE_IO |
252 | }, { | 255 | }, { |
253 | .name = "timer1", | 256 | .name = "timer1", |
254 | .start = 0x0050, | 257 | .start = 0x0050, |
255 | .end = 0x0053, | 258 | .end = 0x0053, |
256 | .flags = IORESOURCE_BUSY | IORESOURCE_IO | 259 | .flags = IORESOURCE_BUSY | IORESOURCE_IO |
257 | }, { | 260 | }, { |
258 | .name = "keyboard", | 261 | .name = "keyboard", |
259 | .start = 0x0060, | 262 | .start = 0x0060, |
260 | .end = 0x006f, | 263 | .end = 0x006f, |
261 | .flags = IORESOURCE_BUSY | IORESOURCE_IO | 264 | .flags = IORESOURCE_BUSY | IORESOURCE_IO |
262 | }, { | 265 | }, { |
263 | .name = "dma page reg", | 266 | .name = "dma page reg", |
264 | .start = 0x0080, | 267 | .start = 0x0080, |
265 | .end = 0x008f, | 268 | .end = 0x008f, |
266 | .flags = IORESOURCE_BUSY | IORESOURCE_IO | 269 | .flags = IORESOURCE_BUSY | IORESOURCE_IO |
267 | }, { | 270 | }, { |
268 | .name = "pic2", | 271 | .name = "pic2", |
269 | .start = 0x00a0, | 272 | .start = 0x00a0, |
270 | .end = 0x00a1, | 273 | .end = 0x00a1, |
271 | .flags = IORESOURCE_BUSY | IORESOURCE_IO | 274 | .flags = IORESOURCE_BUSY | IORESOURCE_IO |
272 | }, { | 275 | }, { |
273 | .name = "dma2", | 276 | .name = "dma2", |
274 | .start = 0x00c0, | 277 | .start = 0x00c0, |
275 | .end = 0x00df, | 278 | .end = 0x00df, |
276 | .flags = IORESOURCE_BUSY | IORESOURCE_IO | 279 | .flags = IORESOURCE_BUSY | IORESOURCE_IO |
277 | }, { | 280 | }, { |
278 | .name = "fpu", | 281 | .name = "fpu", |
279 | .start = 0x00f0, | 282 | .start = 0x00f0, |
280 | .end = 0x00ff, | 283 | .end = 0x00ff, |
281 | .flags = IORESOURCE_BUSY | IORESOURCE_IO | 284 | .flags = IORESOURCE_BUSY | IORESOURCE_IO |
282 | } }; | 285 | } }; |
283 | 286 | ||
284 | #define STANDARD_IO_RESOURCES \ | 287 | #define STANDARD_IO_RESOURCES \ |
285 | (sizeof standard_io_resources / sizeof standard_io_resources[0]) | 288 | (sizeof standard_io_resources / sizeof standard_io_resources[0]) |
286 | 289 | ||
287 | #define romsignature(x) (*(unsigned short *)(x) == 0xaa55) | 290 | #define romsignature(x) (*(unsigned short *)(x) == 0xaa55) |
288 | 291 | ||
289 | static int __init romchecksum(unsigned char *rom, unsigned long length) | 292 | static int __init romchecksum(unsigned char *rom, unsigned long length) |
290 | { | 293 | { |
291 | unsigned char *p, sum = 0; | 294 | unsigned char *p, sum = 0; |
292 | 295 | ||
293 | for (p = rom; p < rom + length; p++) | 296 | for (p = rom; p < rom + length; p++) |
294 | sum += *p; | 297 | sum += *p; |
295 | return sum == 0; | 298 | return sum == 0; |
296 | } | 299 | } |
297 | 300 | ||
298 | static void __init probe_roms(void) | 301 | static void __init probe_roms(void) |
299 | { | 302 | { |
300 | unsigned long start, length, upper; | 303 | unsigned long start, length, upper; |
301 | unsigned char *rom; | 304 | unsigned char *rom; |
302 | int i; | 305 | int i; |
303 | 306 | ||
304 | /* video rom */ | 307 | /* video rom */ |
305 | upper = adapter_rom_resources[0].start; | 308 | upper = adapter_rom_resources[0].start; |
306 | for (start = video_rom_resource.start; start < upper; start += 2048) { | 309 | for (start = video_rom_resource.start; start < upper; start += 2048) { |
307 | rom = isa_bus_to_virt(start); | 310 | rom = isa_bus_to_virt(start); |
308 | if (!romsignature(rom)) | 311 | if (!romsignature(rom)) |
309 | continue; | 312 | continue; |
310 | 313 | ||
311 | video_rom_resource.start = start; | 314 | video_rom_resource.start = start; |
312 | 315 | ||
313 | /* 0 < length <= 0x7f * 512, historically */ | 316 | /* 0 < length <= 0x7f * 512, historically */ |
314 | length = rom[2] * 512; | 317 | length = rom[2] * 512; |
315 | 318 | ||
316 | /* if checksum okay, trust length byte */ | 319 | /* if checksum okay, trust length byte */ |
317 | if (length && romchecksum(rom, length)) | 320 | if (length && romchecksum(rom, length)) |
318 | video_rom_resource.end = start + length - 1; | 321 | video_rom_resource.end = start + length - 1; |
319 | 322 | ||
320 | request_resource(&iomem_resource, &video_rom_resource); | 323 | request_resource(&iomem_resource, &video_rom_resource); |
321 | break; | 324 | break; |
322 | } | 325 | } |
323 | 326 | ||
324 | start = (video_rom_resource.end + 1 + 2047) & ~2047UL; | 327 | start = (video_rom_resource.end + 1 + 2047) & ~2047UL; |
325 | if (start < upper) | 328 | if (start < upper) |
326 | start = upper; | 329 | start = upper; |
327 | 330 | ||
328 | /* system rom */ | 331 | /* system rom */ |
329 | request_resource(&iomem_resource, &system_rom_resource); | 332 | request_resource(&iomem_resource, &system_rom_resource); |
330 | upper = system_rom_resource.start; | 333 | upper = system_rom_resource.start; |
331 | 334 | ||
332 | /* check for extension rom (ignore length byte!) */ | 335 | /* check for extension rom (ignore length byte!) */ |
333 | rom = isa_bus_to_virt(extension_rom_resource.start); | 336 | rom = isa_bus_to_virt(extension_rom_resource.start); |
334 | if (romsignature(rom)) { | 337 | if (romsignature(rom)) { |
335 | length = extension_rom_resource.end - extension_rom_resource.start + 1; | 338 | length = extension_rom_resource.end - extension_rom_resource.start + 1; |
336 | if (romchecksum(rom, length)) { | 339 | if (romchecksum(rom, length)) { |
337 | request_resource(&iomem_resource, &extension_rom_resource); | 340 | request_resource(&iomem_resource, &extension_rom_resource); |
338 | upper = extension_rom_resource.start; | 341 | upper = extension_rom_resource.start; |
339 | } | 342 | } |
340 | } | 343 | } |
341 | 344 | ||
342 | /* check for adapter roms on 2k boundaries */ | 345 | /* check for adapter roms on 2k boundaries */ |
343 | for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) { | 346 | for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) { |
344 | rom = isa_bus_to_virt(start); | 347 | rom = isa_bus_to_virt(start); |
345 | if (!romsignature(rom)) | 348 | if (!romsignature(rom)) |
346 | continue; | 349 | continue; |
347 | 350 | ||
348 | /* 0 < length <= 0x7f * 512, historically */ | 351 | /* 0 < length <= 0x7f * 512, historically */ |
349 | length = rom[2] * 512; | 352 | length = rom[2] * 512; |
350 | 353 | ||
351 | /* but accept any length that fits if checksum okay */ | 354 | /* but accept any length that fits if checksum okay */ |
352 | if (!length || start + length > upper || !romchecksum(rom, length)) | 355 | if (!length || start + length > upper || !romchecksum(rom, length)) |
353 | continue; | 356 | continue; |
354 | 357 | ||
355 | adapter_rom_resources[i].start = start; | 358 | adapter_rom_resources[i].start = start; |
356 | adapter_rom_resources[i].end = start + length - 1; | 359 | adapter_rom_resources[i].end = start + length - 1; |
357 | request_resource(&iomem_resource, &adapter_rom_resources[i]); | 360 | request_resource(&iomem_resource, &adapter_rom_resources[i]); |
358 | 361 | ||
359 | start = adapter_rom_resources[i++].end & ~2047UL; | 362 | start = adapter_rom_resources[i++].end & ~2047UL; |
360 | } | 363 | } |
361 | } | 364 | } |
362 | 365 | ||
363 | static void __init limit_regions(unsigned long long size) | 366 | static void __init limit_regions(unsigned long long size) |
364 | { | 367 | { |
365 | unsigned long long current_addr = 0; | 368 | unsigned long long current_addr = 0; |
366 | int i; | 369 | int i; |
367 | 370 | ||
368 | if (efi_enabled) { | 371 | if (efi_enabled) { |
369 | for (i = 0; i < memmap.nr_map; i++) { | 372 | for (i = 0; i < memmap.nr_map; i++) { |
370 | current_addr = memmap.map[i].phys_addr + | 373 | current_addr = memmap.map[i].phys_addr + |
371 | (memmap.map[i].num_pages << 12); | 374 | (memmap.map[i].num_pages << 12); |
372 | if (memmap.map[i].type == EFI_CONVENTIONAL_MEMORY) { | 375 | if (memmap.map[i].type == EFI_CONVENTIONAL_MEMORY) { |
373 | if (current_addr >= size) { | 376 | if (current_addr >= size) { |
374 | memmap.map[i].num_pages -= | 377 | memmap.map[i].num_pages -= |
375 | (((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT); | 378 | (((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT); |
376 | memmap.nr_map = i + 1; | 379 | memmap.nr_map = i + 1; |
377 | return; | 380 | return; |
378 | } | 381 | } |
379 | } | 382 | } |
380 | } | 383 | } |
381 | } | 384 | } |
382 | for (i = 0; i < e820.nr_map; i++) { | 385 | for (i = 0; i < e820.nr_map; i++) { |
383 | if (e820.map[i].type == E820_RAM) { | 386 | if (e820.map[i].type == E820_RAM) { |
384 | current_addr = e820.map[i].addr + e820.map[i].size; | 387 | current_addr = e820.map[i].addr + e820.map[i].size; |
385 | if (current_addr >= size) { | 388 | if (current_addr >= size) { |
386 | e820.map[i].size -= current_addr-size; | 389 | e820.map[i].size -= current_addr-size; |
387 | e820.nr_map = i + 1; | 390 | e820.nr_map = i + 1; |
388 | return; | 391 | return; |
389 | } | 392 | } |
390 | } | 393 | } |
391 | } | 394 | } |
392 | } | 395 | } |
393 | 396 | ||
394 | static void __init add_memory_region(unsigned long long start, | 397 | static void __init add_memory_region(unsigned long long start, |
395 | unsigned long long size, int type) | 398 | unsigned long long size, int type) |
396 | { | 399 | { |
397 | int x; | 400 | int x; |
398 | 401 | ||
399 | if (!efi_enabled) { | 402 | if (!efi_enabled) { |
400 | x = e820.nr_map; | 403 | x = e820.nr_map; |
401 | 404 | ||
402 | if (x == E820MAX) { | 405 | if (x == E820MAX) { |
403 | printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); | 406 | printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); |
404 | return; | 407 | return; |
405 | } | 408 | } |
406 | 409 | ||
407 | e820.map[x].addr = start; | 410 | e820.map[x].addr = start; |
408 | e820.map[x].size = size; | 411 | e820.map[x].size = size; |
409 | e820.map[x].type = type; | 412 | e820.map[x].type = type; |
410 | e820.nr_map++; | 413 | e820.nr_map++; |
411 | } | 414 | } |
412 | } /* add_memory_region */ | 415 | } /* add_memory_region */ |
413 | 416 | ||
414 | #define E820_DEBUG 1 | 417 | #define E820_DEBUG 1 |
415 | 418 | ||
416 | static void __init print_memory_map(char *who) | 419 | static void __init print_memory_map(char *who) |
417 | { | 420 | { |
418 | int i; | 421 | int i; |
419 | 422 | ||
420 | for (i = 0; i < e820.nr_map; i++) { | 423 | for (i = 0; i < e820.nr_map; i++) { |
421 | printk(" %s: %016Lx - %016Lx ", who, | 424 | printk(" %s: %016Lx - %016Lx ", who, |
422 | e820.map[i].addr, | 425 | e820.map[i].addr, |
423 | e820.map[i].addr + e820.map[i].size); | 426 | e820.map[i].addr + e820.map[i].size); |
424 | switch (e820.map[i].type) { | 427 | switch (e820.map[i].type) { |
425 | case E820_RAM: printk("(usable)\n"); | 428 | case E820_RAM: printk("(usable)\n"); |
426 | break; | 429 | break; |
427 | case E820_RESERVED: | 430 | case E820_RESERVED: |
428 | printk("(reserved)\n"); | 431 | printk("(reserved)\n"); |
429 | break; | 432 | break; |
430 | case E820_ACPI: | 433 | case E820_ACPI: |
431 | printk("(ACPI data)\n"); | 434 | printk("(ACPI data)\n"); |
432 | break; | 435 | break; |
433 | case E820_NVS: | 436 | case E820_NVS: |
434 | printk("(ACPI NVS)\n"); | 437 | printk("(ACPI NVS)\n"); |
435 | break; | 438 | break; |
436 | default: printk("type %lu\n", e820.map[i].type); | 439 | default: printk("type %lu\n", e820.map[i].type); |
437 | break; | 440 | break; |
438 | } | 441 | } |
439 | } | 442 | } |
440 | } | 443 | } |
441 | 444 | ||
442 | /* | 445 | /* |
443 | * Sanitize the BIOS e820 map. | 446 | * Sanitize the BIOS e820 map. |
444 | * | 447 | * |
445 | * Some e820 responses include overlapping entries. The following | 448 | * Some e820 responses include overlapping entries. The following |
446 | * replaces the original e820 map with a new one, removing overlaps. | 449 | * replaces the original e820 map with a new one, removing overlaps. |
447 | * | 450 | * |
448 | */ | 451 | */ |
449 | struct change_member { | 452 | struct change_member { |
450 | struct e820entry *pbios; /* pointer to original bios entry */ | 453 | struct e820entry *pbios; /* pointer to original bios entry */ |
451 | unsigned long long addr; /* address for this change point */ | 454 | unsigned long long addr; /* address for this change point */ |
452 | }; | 455 | }; |
453 | static struct change_member change_point_list[2*E820MAX] __initdata; | 456 | static struct change_member change_point_list[2*E820MAX] __initdata; |
454 | static struct change_member *change_point[2*E820MAX] __initdata; | 457 | static struct change_member *change_point[2*E820MAX] __initdata; |
455 | static struct e820entry *overlap_list[E820MAX] __initdata; | 458 | static struct e820entry *overlap_list[E820MAX] __initdata; |
456 | static struct e820entry new_bios[E820MAX] __initdata; | 459 | static struct e820entry new_bios[E820MAX] __initdata; |
457 | 460 | ||
458 | static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) | 461 | static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) |
459 | { | 462 | { |
460 | struct change_member *change_tmp; | 463 | struct change_member *change_tmp; |
461 | unsigned long current_type, last_type; | 464 | unsigned long current_type, last_type; |
462 | unsigned long long last_addr; | 465 | unsigned long long last_addr; |
463 | int chgidx, still_changing; | 466 | int chgidx, still_changing; |
464 | int overlap_entries; | 467 | int overlap_entries; |
465 | int new_bios_entry; | 468 | int new_bios_entry; |
466 | int old_nr, new_nr, chg_nr; | 469 | int old_nr, new_nr, chg_nr; |
467 | int i; | 470 | int i; |
468 | 471 | ||
469 | /* | 472 | /* |
470 | Visually we're performing the following (1,2,3,4 = memory types)... | 473 | Visually we're performing the following (1,2,3,4 = memory types)... |
471 | 474 | ||
472 | Sample memory map (w/overlaps): | 475 | Sample memory map (w/overlaps): |
473 | ____22__________________ | 476 | ____22__________________ |
474 | ______________________4_ | 477 | ______________________4_ |
475 | ____1111________________ | 478 | ____1111________________ |
476 | _44_____________________ | 479 | _44_____________________ |
477 | 11111111________________ | 480 | 11111111________________ |
478 | ____________________33__ | 481 | ____________________33__ |
479 | ___________44___________ | 482 | ___________44___________ |
480 | __________33333_________ | 483 | __________33333_________ |
481 | ______________22________ | 484 | ______________22________ |
482 | ___________________2222_ | 485 | ___________________2222_ |
483 | _________111111111______ | 486 | _________111111111______ |
484 | _____________________11_ | 487 | _____________________11_ |
485 | _________________4______ | 488 | _________________4______ |
486 | 489 | ||
487 | Sanitized equivalent (no overlap): | 490 | Sanitized equivalent (no overlap): |
488 | 1_______________________ | 491 | 1_______________________ |
489 | _44_____________________ | 492 | _44_____________________ |
490 | ___1____________________ | 493 | ___1____________________ |
491 | ____22__________________ | 494 | ____22__________________ |
492 | ______11________________ | 495 | ______11________________ |
493 | _________1______________ | 496 | _________1______________ |
494 | __________3_____________ | 497 | __________3_____________ |
495 | ___________44___________ | 498 | ___________44___________ |
496 | _____________33_________ | 499 | _____________33_________ |
497 | _______________2________ | 500 | _______________2________ |
498 | ________________1_______ | 501 | ________________1_______ |
499 | _________________4______ | 502 | _________________4______ |
500 | ___________________2____ | 503 | ___________________2____ |
501 | ____________________33__ | 504 | ____________________33__ |
502 | ______________________4_ | 505 | ______________________4_ |
503 | */ | 506 | */ |
504 | 507 | ||
505 | /* if there's only one memory region, don't bother */ | 508 | /* if there's only one memory region, don't bother */ |
506 | if (*pnr_map < 2) | 509 | if (*pnr_map < 2) |
507 | return -1; | 510 | return -1; |
508 | 511 | ||
509 | old_nr = *pnr_map; | 512 | old_nr = *pnr_map; |
510 | 513 | ||
511 | /* bail out if we find any unreasonable addresses in bios map */ | 514 | /* bail out if we find any unreasonable addresses in bios map */ |
512 | for (i=0; i<old_nr; i++) | 515 | for (i=0; i<old_nr; i++) |
513 | if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) | 516 | if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) |
514 | return -1; | 517 | return -1; |
515 | 518 | ||
516 | /* create pointers for initial change-point information (for sorting) */ | 519 | /* create pointers for initial change-point information (for sorting) */ |
517 | for (i=0; i < 2*old_nr; i++) | 520 | for (i=0; i < 2*old_nr; i++) |
518 | change_point[i] = &change_point_list[i]; | 521 | change_point[i] = &change_point_list[i]; |
519 | 522 | ||
520 | /* record all known change-points (starting and ending addresses), | 523 | /* record all known change-points (starting and ending addresses), |
521 | omitting those that are for empty memory regions */ | 524 | omitting those that are for empty memory regions */ |
522 | chgidx = 0; | 525 | chgidx = 0; |
523 | for (i=0; i < old_nr; i++) { | 526 | for (i=0; i < old_nr; i++) { |
524 | if (biosmap[i].size != 0) { | 527 | if (biosmap[i].size != 0) { |
525 | change_point[chgidx]->addr = biosmap[i].addr; | 528 | change_point[chgidx]->addr = biosmap[i].addr; |
526 | change_point[chgidx++]->pbios = &biosmap[i]; | 529 | change_point[chgidx++]->pbios = &biosmap[i]; |
527 | change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; | 530 | change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; |
528 | change_point[chgidx++]->pbios = &biosmap[i]; | 531 | change_point[chgidx++]->pbios = &biosmap[i]; |
529 | } | 532 | } |
530 | } | 533 | } |
531 | chg_nr = chgidx; /* true number of change-points */ | 534 | chg_nr = chgidx; /* true number of change-points */ |
532 | 535 | ||
533 | /* sort change-point list by memory addresses (low -> high) */ | 536 | /* sort change-point list by memory addresses (low -> high) */ |
534 | still_changing = 1; | 537 | still_changing = 1; |
535 | while (still_changing) { | 538 | while (still_changing) { |
536 | still_changing = 0; | 539 | still_changing = 0; |
537 | for (i=1; i < chg_nr; i++) { | 540 | for (i=1; i < chg_nr; i++) { |
538 | /* if <current_addr> > <last_addr>, swap */ | 541 | /* if <current_addr> > <last_addr>, swap */ |
539 | /* or, if current=<start_addr> & last=<end_addr>, swap */ | 542 | /* or, if current=<start_addr> & last=<end_addr>, swap */ |
540 | if ((change_point[i]->addr < change_point[i-1]->addr) || | 543 | if ((change_point[i]->addr < change_point[i-1]->addr) || |
541 | ((change_point[i]->addr == change_point[i-1]->addr) && | 544 | ((change_point[i]->addr == change_point[i-1]->addr) && |
542 | (change_point[i]->addr == change_point[i]->pbios->addr) && | 545 | (change_point[i]->addr == change_point[i]->pbios->addr) && |
543 | (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) | 546 | (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) |
544 | ) | 547 | ) |
545 | { | 548 | { |
546 | change_tmp = change_point[i]; | 549 | change_tmp = change_point[i]; |
547 | change_point[i] = change_point[i-1]; | 550 | change_point[i] = change_point[i-1]; |
548 | change_point[i-1] = change_tmp; | 551 | change_point[i-1] = change_tmp; |
549 | still_changing=1; | 552 | still_changing=1; |
550 | } | 553 | } |
551 | } | 554 | } |
552 | } | 555 | } |
553 | 556 | ||
554 | /* create a new bios memory map, removing overlaps */ | 557 | /* create a new bios memory map, removing overlaps */ |
555 | overlap_entries=0; /* number of entries in the overlap table */ | 558 | overlap_entries=0; /* number of entries in the overlap table */ |
556 | new_bios_entry=0; /* index for creating new bios map entries */ | 559 | new_bios_entry=0; /* index for creating new bios map entries */ |
557 | last_type = 0; /* start with undefined memory type */ | 560 | last_type = 0; /* start with undefined memory type */ |
558 | last_addr = 0; /* start with 0 as last starting address */ | 561 | last_addr = 0; /* start with 0 as last starting address */ |
559 | /* loop through change-points, determining affect on the new bios map */ | 562 | /* loop through change-points, determining affect on the new bios map */ |
560 | for (chgidx=0; chgidx < chg_nr; chgidx++) | 563 | for (chgidx=0; chgidx < chg_nr; chgidx++) |
561 | { | 564 | { |
562 | /* keep track of all overlapping bios entries */ | 565 | /* keep track of all overlapping bios entries */ |
563 | if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) | 566 | if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) |
564 | { | 567 | { |
565 | /* add map entry to overlap list (> 1 entry implies an overlap) */ | 568 | /* add map entry to overlap list (> 1 entry implies an overlap) */ |
566 | overlap_list[overlap_entries++]=change_point[chgidx]->pbios; | 569 | overlap_list[overlap_entries++]=change_point[chgidx]->pbios; |
567 | } | 570 | } |
568 | else | 571 | else |
569 | { | 572 | { |
570 | /* remove entry from list (order independent, so swap with last) */ | 573 | /* remove entry from list (order independent, so swap with last) */ |
571 | for (i=0; i<overlap_entries; i++) | 574 | for (i=0; i<overlap_entries; i++) |
572 | { | 575 | { |
573 | if (overlap_list[i] == change_point[chgidx]->pbios) | 576 | if (overlap_list[i] == change_point[chgidx]->pbios) |
574 | overlap_list[i] = overlap_list[overlap_entries-1]; | 577 | overlap_list[i] = overlap_list[overlap_entries-1]; |
575 | } | 578 | } |
576 | overlap_entries--; | 579 | overlap_entries--; |
577 | } | 580 | } |
578 | /* if there are overlapping entries, decide which "type" to use */ | 581 | /* if there are overlapping entries, decide which "type" to use */ |
579 | /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ | 582 | /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ |
580 | current_type = 0; | 583 | current_type = 0; |
581 | for (i=0; i<overlap_entries; i++) | 584 | for (i=0; i<overlap_entries; i++) |
582 | if (overlap_list[i]->type > current_type) | 585 | if (overlap_list[i]->type > current_type) |
583 | current_type = overlap_list[i]->type; | 586 | current_type = overlap_list[i]->type; |
584 | /* continue building up new bios map based on this information */ | 587 | /* continue building up new bios map based on this information */ |
585 | if (current_type != last_type) { | 588 | if (current_type != last_type) { |
586 | if (last_type != 0) { | 589 | if (last_type != 0) { |
587 | new_bios[new_bios_entry].size = | 590 | new_bios[new_bios_entry].size = |
588 | change_point[chgidx]->addr - last_addr; | 591 | change_point[chgidx]->addr - last_addr; |
589 | /* move forward only if the new size was non-zero */ | 592 | /* move forward only if the new size was non-zero */ |
590 | if (new_bios[new_bios_entry].size != 0) | 593 | if (new_bios[new_bios_entry].size != 0) |
591 | if (++new_bios_entry >= E820MAX) | 594 | if (++new_bios_entry >= E820MAX) |
592 | break; /* no more space left for new bios entries */ | 595 | break; /* no more space left for new bios entries */ |
593 | } | 596 | } |
594 | if (current_type != 0) { | 597 | if (current_type != 0) { |
595 | new_bios[new_bios_entry].addr = change_point[chgidx]->addr; | 598 | new_bios[new_bios_entry].addr = change_point[chgidx]->addr; |
596 | new_bios[new_bios_entry].type = current_type; | 599 | new_bios[new_bios_entry].type = current_type; |
597 | last_addr=change_point[chgidx]->addr; | 600 | last_addr=change_point[chgidx]->addr; |
598 | } | 601 | } |
599 | last_type = current_type; | 602 | last_type = current_type; |
600 | } | 603 | } |
601 | } | 604 | } |
602 | new_nr = new_bios_entry; /* retain count for new bios entries */ | 605 | new_nr = new_bios_entry; /* retain count for new bios entries */ |
603 | 606 | ||
604 | /* copy new bios mapping into original location */ | 607 | /* copy new bios mapping into original location */ |
605 | memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); | 608 | memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); |
606 | *pnr_map = new_nr; | 609 | *pnr_map = new_nr; |
607 | 610 | ||
608 | return 0; | 611 | return 0; |
609 | } | 612 | } |
610 | 613 | ||
611 | /* | 614 | /* |
612 | * Copy the BIOS e820 map into a safe place. | 615 | * Copy the BIOS e820 map into a safe place. |
613 | * | 616 | * |
614 | * Sanity-check it while we're at it.. | 617 | * Sanity-check it while we're at it.. |
615 | * | 618 | * |
616 | * If we're lucky and live on a modern system, the setup code | 619 | * If we're lucky and live on a modern system, the setup code |
617 | * will have given us a memory map that we can use to properly | 620 | * will have given us a memory map that we can use to properly |
618 | * set up memory. If we aren't, we'll fake a memory map. | 621 | * set up memory. If we aren't, we'll fake a memory map. |
619 | * | 622 | * |
620 | * We check to see that the memory map contains at least 2 elements | 623 | * We check to see that the memory map contains at least 2 elements |
621 | * before we'll use it, because the detection code in setup.S may | 624 | * before we'll use it, because the detection code in setup.S may |
622 | * not be perfect and most every PC known to man has two memory | 625 | * not be perfect and most every PC known to man has two memory |
623 | * regions: one from 0 to 640k, and one from 1mb up. (The IBM | 626 | * regions: one from 0 to 640k, and one from 1mb up. (The IBM |
624 | * thinkpad 560x, for example, does not cooperate with the memory | 627 | * thinkpad 560x, for example, does not cooperate with the memory |
625 | * detection code.) | 628 | * detection code.) |
626 | */ | 629 | */ |
627 | static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) | 630 | static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) |
628 | { | 631 | { |
629 | /* Only one memory region (or negative)? Ignore it */ | 632 | /* Only one memory region (or negative)? Ignore it */ |
630 | if (nr_map < 2) | 633 | if (nr_map < 2) |
631 | return -1; | 634 | return -1; |
632 | 635 | ||
633 | do { | 636 | do { |
634 | unsigned long long start = biosmap->addr; | 637 | unsigned long long start = biosmap->addr; |
635 | unsigned long long size = biosmap->size; | 638 | unsigned long long size = biosmap->size; |
636 | unsigned long long end = start + size; | 639 | unsigned long long end = start + size; |
637 | unsigned long type = biosmap->type; | 640 | unsigned long type = biosmap->type; |
638 | 641 | ||
639 | /* Overflow in 64 bits? Ignore the memory map. */ | 642 | /* Overflow in 64 bits? Ignore the memory map. */ |
640 | if (start > end) | 643 | if (start > end) |
641 | return -1; | 644 | return -1; |
642 | 645 | ||
643 | /* | 646 | /* |
644 | * Some BIOSes claim RAM in the 640k - 1M region. | 647 | * Some BIOSes claim RAM in the 640k - 1M region. |
645 | * Not right. Fix it up. | 648 | * Not right. Fix it up. |
646 | */ | 649 | */ |
647 | if (type == E820_RAM) { | 650 | if (type == E820_RAM) { |
648 | if (start < 0x100000ULL && end > 0xA0000ULL) { | 651 | if (start < 0x100000ULL && end > 0xA0000ULL) { |
649 | if (start < 0xA0000ULL) | 652 | if (start < 0xA0000ULL) |
650 | add_memory_region(start, 0xA0000ULL-start, type); | 653 | add_memory_region(start, 0xA0000ULL-start, type); |
651 | if (end <= 0x100000ULL) | 654 | if (end <= 0x100000ULL) |
652 | continue; | 655 | continue; |
653 | start = 0x100000ULL; | 656 | start = 0x100000ULL; |
654 | size = end - start; | 657 | size = end - start; |
655 | } | 658 | } |
656 | } | 659 | } |
657 | add_memory_region(start, size, type); | 660 | add_memory_region(start, size, type); |
658 | } while (biosmap++,--nr_map); | 661 | } while (biosmap++,--nr_map); |
659 | return 0; | 662 | return 0; |
660 | } | 663 | } |
661 | 664 | ||
662 | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) | 665 | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) |
663 | struct edd edd; | 666 | struct edd edd; |
664 | #ifdef CONFIG_EDD_MODULE | 667 | #ifdef CONFIG_EDD_MODULE |
665 | EXPORT_SYMBOL(edd); | 668 | EXPORT_SYMBOL(edd); |
666 | #endif | 669 | #endif |
667 | /** | 670 | /** |
668 | * copy_edd() - Copy the BIOS EDD information | 671 | * copy_edd() - Copy the BIOS EDD information |
669 | * from boot_params into a safe place. | 672 | * from boot_params into a safe place. |
670 | * | 673 | * |
671 | */ | 674 | */ |
672 | static inline void copy_edd(void) | 675 | static inline void copy_edd(void) |
673 | { | 676 | { |
674 | memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature)); | 677 | memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature)); |
675 | memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info)); | 678 | memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info)); |
676 | edd.mbr_signature_nr = EDD_MBR_SIG_NR; | 679 | edd.mbr_signature_nr = EDD_MBR_SIG_NR; |
677 | edd.edd_info_nr = EDD_NR; | 680 | edd.edd_info_nr = EDD_NR; |
678 | } | 681 | } |
679 | #else | 682 | #else |
680 | static inline void copy_edd(void) | 683 | static inline void copy_edd(void) |
681 | { | 684 | { |
682 | } | 685 | } |
683 | #endif | 686 | #endif |
684 | 687 | ||
685 | /* | 688 | /* |
686 | * Do NOT EVER look at the BIOS memory size location. | 689 | * Do NOT EVER look at the BIOS memory size location. |
687 | * It does not work on many machines. | 690 | * It does not work on many machines. |
688 | */ | 691 | */ |
689 | #define LOWMEMSIZE() (0x9f000) | 692 | #define LOWMEMSIZE() (0x9f000) |
690 | 693 | ||
691 | static void __init parse_cmdline_early (char ** cmdline_p) | 694 | static void __init parse_cmdline_early (char ** cmdline_p) |
692 | { | 695 | { |
693 | char c = ' ', *to = command_line, *from = saved_command_line; | 696 | char c = ' ', *to = command_line, *from = saved_command_line; |
694 | int len = 0; | 697 | int len = 0; |
695 | int userdef = 0; | 698 | int userdef = 0; |
696 | 699 | ||
697 | /* Save unparsed command line copy for /proc/cmdline */ | 700 | /* Save unparsed command line copy for /proc/cmdline */ |
698 | saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; | 701 | saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; |
699 | 702 | ||
700 | for (;;) { | 703 | for (;;) { |
701 | if (c != ' ') | 704 | if (c != ' ') |
702 | goto next_char; | 705 | goto next_char; |
703 | /* | 706 | /* |
704 | * "mem=nopentium" disables the 4MB page tables. | 707 | * "mem=nopentium" disables the 4MB page tables. |
705 | * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM | 708 | * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM |
706 | * to <mem>, overriding the bios size. | 709 | * to <mem>, overriding the bios size. |
707 | * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from | 710 | * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from |
708 | * <start> to <start>+<mem>, overriding the bios size. | 711 | * <start> to <start>+<mem>, overriding the bios size. |
709 | * | 712 | * |
710 | * HPA tells me bootloaders need to parse mem=, so no new | 713 | * HPA tells me bootloaders need to parse mem=, so no new |
711 | * option should be mem= [also see Documentation/i386/boot.txt] | 714 | * option should be mem= [also see Documentation/i386/boot.txt] |
712 | */ | 715 | */ |
713 | if (!memcmp(from, "mem=", 4)) { | 716 | if (!memcmp(from, "mem=", 4)) { |
714 | if (to != command_line) | 717 | if (to != command_line) |
715 | to--; | 718 | to--; |
716 | if (!memcmp(from+4, "nopentium", 9)) { | 719 | if (!memcmp(from+4, "nopentium", 9)) { |
717 | from += 9+4; | 720 | from += 9+4; |
718 | clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); | 721 | clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); |
719 | disable_pse = 1; | 722 | disable_pse = 1; |
720 | } else { | 723 | } else { |
721 | /* If the user specifies memory size, we | 724 | /* If the user specifies memory size, we |
722 | * limit the BIOS-provided memory map to | 725 | * limit the BIOS-provided memory map to |
723 | * that size. exactmap can be used to specify | 726 | * that size. exactmap can be used to specify |
724 | * the exact map. mem=number can be used to | 727 | * the exact map. mem=number can be used to |
725 | * trim the existing memory map. | 728 | * trim the existing memory map. |
726 | */ | 729 | */ |
727 | unsigned long long mem_size; | 730 | unsigned long long mem_size; |
728 | 731 | ||
729 | mem_size = memparse(from+4, &from); | 732 | mem_size = memparse(from+4, &from); |
730 | limit_regions(mem_size); | 733 | limit_regions(mem_size); |
731 | userdef=1; | 734 | userdef=1; |
732 | } | 735 | } |
733 | } | 736 | } |
734 | 737 | ||
735 | else if (!memcmp(from, "memmap=", 7)) { | 738 | else if (!memcmp(from, "memmap=", 7)) { |
736 | if (to != command_line) | 739 | if (to != command_line) |
737 | to--; | 740 | to--; |
738 | if (!memcmp(from+7, "exactmap", 8)) { | 741 | if (!memcmp(from+7, "exactmap", 8)) { |
742 | #ifdef CONFIG_CRASH_DUMP | ||
743 | /* If we are doing a crash dump, we | ||
744 | * still need to know the real mem | ||
745 | * size before original memory map is | ||
746 | * reset. | ||
747 | */ | ||
748 | find_max_pfn(); | ||
749 | saved_max_pfn = max_pfn; | ||
750 | #endif | ||
739 | from += 8+7; | 751 | from += 8+7; |
740 | e820.nr_map = 0; | 752 | e820.nr_map = 0; |
741 | userdef = 1; | 753 | userdef = 1; |
742 | } else { | 754 | } else { |
743 | /* If the user specifies memory size, we | 755 | /* If the user specifies memory size, we |
744 | * limit the BIOS-provided memory map to | 756 | * limit the BIOS-provided memory map to |
745 | * that size. exactmap can be used to specify | 757 | * that size. exactmap can be used to specify |
746 | * the exact map. mem=number can be used to | 758 | * the exact map. mem=number can be used to |
747 | * trim the existing memory map. | 759 | * trim the existing memory map. |
748 | */ | 760 | */ |
749 | unsigned long long start_at, mem_size; | 761 | unsigned long long start_at, mem_size; |
750 | 762 | ||
751 | mem_size = memparse(from+7, &from); | 763 | mem_size = memparse(from+7, &from); |
752 | if (*from == '@') { | 764 | if (*from == '@') { |
753 | start_at = memparse(from+1, &from); | 765 | start_at = memparse(from+1, &from); |
754 | add_memory_region(start_at, mem_size, E820_RAM); | 766 | add_memory_region(start_at, mem_size, E820_RAM); |
755 | } else if (*from == '#') { | 767 | } else if (*from == '#') { |
756 | start_at = memparse(from+1, &from); | 768 | start_at = memparse(from+1, &from); |
757 | add_memory_region(start_at, mem_size, E820_ACPI); | 769 | add_memory_region(start_at, mem_size, E820_ACPI); |
758 | } else if (*from == '$') { | 770 | } else if (*from == '$') { |
759 | start_at = memparse(from+1, &from); | 771 | start_at = memparse(from+1, &from); |
760 | add_memory_region(start_at, mem_size, E820_RESERVED); | 772 | add_memory_region(start_at, mem_size, E820_RESERVED); |
761 | } else { | 773 | } else { |
762 | limit_regions(mem_size); | 774 | limit_regions(mem_size); |
763 | userdef=1; | 775 | userdef=1; |
764 | } | 776 | } |
765 | } | 777 | } |
766 | } | 778 | } |
767 | 779 | ||
768 | else if (!memcmp(from, "noexec=", 7)) | 780 | else if (!memcmp(from, "noexec=", 7)) |
769 | noexec_setup(from + 7); | 781 | noexec_setup(from + 7); |
770 | 782 | ||
771 | 783 | ||
772 | #ifdef CONFIG_X86_SMP | 784 | #ifdef CONFIG_X86_SMP |
773 | /* | 785 | /* |
774 | * If the BIOS enumerates physical processors before logical, | 786 | * If the BIOS enumerates physical processors before logical, |
775 | * maxcpus=N at enumeration-time can be used to disable HT. | 787 | * maxcpus=N at enumeration-time can be used to disable HT. |
776 | */ | 788 | */ |
777 | else if (!memcmp(from, "maxcpus=", 8)) { | 789 | else if (!memcmp(from, "maxcpus=", 8)) { |
778 | extern unsigned int maxcpus; | 790 | extern unsigned int maxcpus; |
779 | 791 | ||
780 | maxcpus = simple_strtoul(from + 8, NULL, 0); | 792 | maxcpus = simple_strtoul(from + 8, NULL, 0); |
781 | } | 793 | } |
782 | #endif | 794 | #endif |
783 | 795 | ||
784 | #ifdef CONFIG_ACPI_BOOT | 796 | #ifdef CONFIG_ACPI_BOOT |
785 | /* "acpi=off" disables both ACPI table parsing and interpreter */ | 797 | /* "acpi=off" disables both ACPI table parsing and interpreter */ |
786 | else if (!memcmp(from, "acpi=off", 8)) { | 798 | else if (!memcmp(from, "acpi=off", 8)) { |
787 | disable_acpi(); | 799 | disable_acpi(); |
788 | } | 800 | } |
789 | 801 | ||
790 | /* acpi=force to over-ride black-list */ | 802 | /* acpi=force to over-ride black-list */ |
791 | else if (!memcmp(from, "acpi=force", 10)) { | 803 | else if (!memcmp(from, "acpi=force", 10)) { |
792 | acpi_force = 1; | 804 | acpi_force = 1; |
793 | acpi_ht = 1; | 805 | acpi_ht = 1; |
794 | acpi_disabled = 0; | 806 | acpi_disabled = 0; |
795 | } | 807 | } |
796 | 808 | ||
797 | /* acpi=strict disables out-of-spec workarounds */ | 809 | /* acpi=strict disables out-of-spec workarounds */ |
798 | else if (!memcmp(from, "acpi=strict", 11)) { | 810 | else if (!memcmp(from, "acpi=strict", 11)) { |
799 | acpi_strict = 1; | 811 | acpi_strict = 1; |
800 | } | 812 | } |
801 | 813 | ||
802 | /* Limit ACPI just to boot-time to enable HT */ | 814 | /* Limit ACPI just to boot-time to enable HT */ |
803 | else if (!memcmp(from, "acpi=ht", 7)) { | 815 | else if (!memcmp(from, "acpi=ht", 7)) { |
804 | if (!acpi_force) | 816 | if (!acpi_force) |
805 | disable_acpi(); | 817 | disable_acpi(); |
806 | acpi_ht = 1; | 818 | acpi_ht = 1; |
807 | } | 819 | } |
808 | 820 | ||
809 | /* "pci=noacpi" disable ACPI IRQ routing and PCI scan */ | 821 | /* "pci=noacpi" disable ACPI IRQ routing and PCI scan */ |
810 | else if (!memcmp(from, "pci=noacpi", 10)) { | 822 | else if (!memcmp(from, "pci=noacpi", 10)) { |
811 | acpi_disable_pci(); | 823 | acpi_disable_pci(); |
812 | } | 824 | } |
813 | /* "acpi=noirq" disables ACPI interrupt routing */ | 825 | /* "acpi=noirq" disables ACPI interrupt routing */ |
814 | else if (!memcmp(from, "acpi=noirq", 10)) { | 826 | else if (!memcmp(from, "acpi=noirq", 10)) { |
815 | acpi_noirq_set(); | 827 | acpi_noirq_set(); |
816 | } | 828 | } |
817 | 829 | ||
818 | else if (!memcmp(from, "acpi_sci=edge", 13)) | 830 | else if (!memcmp(from, "acpi_sci=edge", 13)) |
819 | acpi_sci_flags.trigger = 1; | 831 | acpi_sci_flags.trigger = 1; |
820 | 832 | ||
821 | else if (!memcmp(from, "acpi_sci=level", 14)) | 833 | else if (!memcmp(from, "acpi_sci=level", 14)) |
822 | acpi_sci_flags.trigger = 3; | 834 | acpi_sci_flags.trigger = 3; |
823 | 835 | ||
824 | else if (!memcmp(from, "acpi_sci=high", 13)) | 836 | else if (!memcmp(from, "acpi_sci=high", 13)) |
825 | acpi_sci_flags.polarity = 1; | 837 | acpi_sci_flags.polarity = 1; |
826 | 838 | ||
827 | else if (!memcmp(from, "acpi_sci=low", 12)) | 839 | else if (!memcmp(from, "acpi_sci=low", 12)) |
828 | acpi_sci_flags.polarity = 3; | 840 | acpi_sci_flags.polarity = 3; |
829 | 841 | ||
830 | #ifdef CONFIG_X86_IO_APIC | 842 | #ifdef CONFIG_X86_IO_APIC |
831 | else if (!memcmp(from, "acpi_skip_timer_override", 24)) | 843 | else if (!memcmp(from, "acpi_skip_timer_override", 24)) |
832 | acpi_skip_timer_override = 1; | 844 | acpi_skip_timer_override = 1; |
833 | #endif | 845 | #endif |
834 | 846 | ||
835 | #ifdef CONFIG_X86_LOCAL_APIC | 847 | #ifdef CONFIG_X86_LOCAL_APIC |
836 | /* disable IO-APIC */ | 848 | /* disable IO-APIC */ |
837 | else if (!memcmp(from, "noapic", 6)) | 849 | else if (!memcmp(from, "noapic", 6)) |
838 | disable_ioapic_setup(); | 850 | disable_ioapic_setup(); |
839 | #endif /* CONFIG_X86_LOCAL_APIC */ | 851 | #endif /* CONFIG_X86_LOCAL_APIC */ |
840 | #endif /* CONFIG_ACPI_BOOT */ | 852 | #endif /* CONFIG_ACPI_BOOT */ |
841 | 853 | ||
842 | #ifdef CONFIG_X86_LOCAL_APIC | 854 | #ifdef CONFIG_X86_LOCAL_APIC |
843 | /* enable local APIC */ | 855 | /* enable local APIC */ |
844 | else if (!memcmp(from, "lapic", 5)) | 856 | else if (!memcmp(from, "lapic", 5)) |
845 | lapic_enable(); | 857 | lapic_enable(); |
846 | 858 | ||
847 | /* disable local APIC */ | 859 | /* disable local APIC */ |
848 | else if (!memcmp(from, "nolapic", 6)) | 860 | else if (!memcmp(from, "nolapic", 6)) |
849 | lapic_disable(); | 861 | lapic_disable(); |
850 | #endif /* CONFIG_X86_LOCAL_APIC */ | 862 | #endif /* CONFIG_X86_LOCAL_APIC */ |
851 | 863 | ||
852 | #ifdef CONFIG_KEXEC | 864 | #ifdef CONFIG_KEXEC |
853 | /* crashkernel=size@addr specifies the location to reserve for | 865 | /* crashkernel=size@addr specifies the location to reserve for |
854 | * a crash kernel. By reserving this memory we guarantee | 866 | * a crash kernel. By reserving this memory we guarantee |
855 | * that linux never set's it up as a DMA target. | 867 | * that linux never set's it up as a DMA target. |
856 | * Useful for holding code to do something appropriate | 868 | * Useful for holding code to do something appropriate |
857 | * after a kernel panic. | 869 | * after a kernel panic. |
858 | */ | 870 | */ |
859 | else if (!memcmp(from, "crashkernel=", 12)) { | 871 | else if (!memcmp(from, "crashkernel=", 12)) { |
860 | unsigned long size, base; | 872 | unsigned long size, base; |
861 | size = memparse(from+12, &from); | 873 | size = memparse(from+12, &from); |
862 | if (*from == '@') { | 874 | if (*from == '@') { |
863 | base = memparse(from+1, &from); | 875 | base = memparse(from+1, &from); |
864 | /* FIXME: Do I want a sanity check | 876 | /* FIXME: Do I want a sanity check |
865 | * to validate the memory range? | 877 | * to validate the memory range? |
866 | */ | 878 | */ |
867 | crashk_res.start = base; | 879 | crashk_res.start = base; |
868 | crashk_res.end = base + size - 1; | 880 | crashk_res.end = base + size - 1; |
869 | } | 881 | } |
870 | } | 882 | } |
871 | #endif | 883 | #endif |
872 | 884 | ||
873 | /* | 885 | /* |
874 | * highmem=size forces highmem to be exactly 'size' bytes. | 886 | * highmem=size forces highmem to be exactly 'size' bytes. |
875 | * This works even on boxes that have no highmem otherwise. | 887 | * This works even on boxes that have no highmem otherwise. |
876 | * This also works to reduce highmem size on bigger boxes. | 888 | * This also works to reduce highmem size on bigger boxes. |
877 | */ | 889 | */ |
878 | else if (!memcmp(from, "highmem=", 8)) | 890 | else if (!memcmp(from, "highmem=", 8)) |
879 | highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; | 891 | highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; |
880 | 892 | ||
881 | /* | 893 | /* |
882 | * vmalloc=size forces the vmalloc area to be exactly 'size' | 894 | * vmalloc=size forces the vmalloc area to be exactly 'size' |
883 | * bytes. This can be used to increase (or decrease) the | 895 | * bytes. This can be used to increase (or decrease) the |
884 | * vmalloc area - the default is 128m. | 896 | * vmalloc area - the default is 128m. |
885 | */ | 897 | */ |
886 | else if (!memcmp(from, "vmalloc=", 8)) | 898 | else if (!memcmp(from, "vmalloc=", 8)) |
887 | __VMALLOC_RESERVE = memparse(from+8, &from); | 899 | __VMALLOC_RESERVE = memparse(from+8, &from); |
888 | 900 | ||
889 | next_char: | 901 | next_char: |
890 | c = *(from++); | 902 | c = *(from++); |
891 | if (!c) | 903 | if (!c) |
892 | break; | 904 | break; |
893 | if (COMMAND_LINE_SIZE <= ++len) | 905 | if (COMMAND_LINE_SIZE <= ++len) |
894 | break; | 906 | break; |
895 | *(to++) = c; | 907 | *(to++) = c; |
896 | } | 908 | } |
897 | *to = '\0'; | 909 | *to = '\0'; |
898 | *cmdline_p = command_line; | 910 | *cmdline_p = command_line; |
899 | if (userdef) { | 911 | if (userdef) { |
900 | printk(KERN_INFO "user-defined physical RAM map:\n"); | 912 | printk(KERN_INFO "user-defined physical RAM map:\n"); |
901 | print_memory_map("user"); | 913 | print_memory_map("user"); |
902 | } | 914 | } |
903 | } | 915 | } |
904 | 916 | ||
905 | /* | 917 | /* |
906 | * Callback for efi_memory_walk. | 918 | * Callback for efi_memory_walk. |
907 | */ | 919 | */ |
908 | static int __init | 920 | static int __init |
909 | efi_find_max_pfn(unsigned long start, unsigned long end, void *arg) | 921 | efi_find_max_pfn(unsigned long start, unsigned long end, void *arg) |
910 | { | 922 | { |
911 | unsigned long *max_pfn = arg, pfn; | 923 | unsigned long *max_pfn = arg, pfn; |
912 | 924 | ||
913 | if (start < end) { | 925 | if (start < end) { |
914 | pfn = PFN_UP(end -1); | 926 | pfn = PFN_UP(end -1); |
915 | if (pfn > *max_pfn) | 927 | if (pfn > *max_pfn) |
916 | *max_pfn = pfn; | 928 | *max_pfn = pfn; |
917 | } | 929 | } |
918 | return 0; | 930 | return 0; |
919 | } | 931 | } |
920 | 932 | ||
921 | 933 | ||
922 | /* | 934 | /* |
923 | * Find the highest page frame number we have available | 935 | * Find the highest page frame number we have available |
924 | */ | 936 | */ |
925 | void __init find_max_pfn(void) | 937 | void __init find_max_pfn(void) |
926 | { | 938 | { |
927 | int i; | 939 | int i; |
928 | 940 | ||
929 | max_pfn = 0; | 941 | max_pfn = 0; |
930 | if (efi_enabled) { | 942 | if (efi_enabled) { |
931 | efi_memmap_walk(efi_find_max_pfn, &max_pfn); | 943 | efi_memmap_walk(efi_find_max_pfn, &max_pfn); |
932 | return; | 944 | return; |
933 | } | 945 | } |
934 | 946 | ||
935 | for (i = 0; i < e820.nr_map; i++) { | 947 | for (i = 0; i < e820.nr_map; i++) { |
936 | unsigned long start, end; | 948 | unsigned long start, end; |
937 | /* RAM? */ | 949 | /* RAM? */ |
938 | if (e820.map[i].type != E820_RAM) | 950 | if (e820.map[i].type != E820_RAM) |
939 | continue; | 951 | continue; |
940 | start = PFN_UP(e820.map[i].addr); | 952 | start = PFN_UP(e820.map[i].addr); |
941 | end = PFN_DOWN(e820.map[i].addr + e820.map[i].size); | 953 | end = PFN_DOWN(e820.map[i].addr + e820.map[i].size); |
942 | if (start >= end) | 954 | if (start >= end) |
943 | continue; | 955 | continue; |
944 | if (end > max_pfn) | 956 | if (end > max_pfn) |
945 | max_pfn = end; | 957 | max_pfn = end; |
946 | } | 958 | } |
947 | } | 959 | } |
948 | 960 | ||
949 | /* | 961 | /* |
950 | * Determine low and high memory ranges: | 962 | * Determine low and high memory ranges: |
951 | */ | 963 | */ |
952 | unsigned long __init find_max_low_pfn(void) | 964 | unsigned long __init find_max_low_pfn(void) |
953 | { | 965 | { |
954 | unsigned long max_low_pfn; | 966 | unsigned long max_low_pfn; |
955 | 967 | ||
956 | max_low_pfn = max_pfn; | 968 | max_low_pfn = max_pfn; |
957 | if (max_low_pfn > MAXMEM_PFN) { | 969 | if (max_low_pfn > MAXMEM_PFN) { |
958 | if (highmem_pages == -1) | 970 | if (highmem_pages == -1) |
959 | highmem_pages = max_pfn - MAXMEM_PFN; | 971 | highmem_pages = max_pfn - MAXMEM_PFN; |
960 | if (highmem_pages + MAXMEM_PFN < max_pfn) | 972 | if (highmem_pages + MAXMEM_PFN < max_pfn) |
961 | max_pfn = MAXMEM_PFN + highmem_pages; | 973 | max_pfn = MAXMEM_PFN + highmem_pages; |
962 | if (highmem_pages + MAXMEM_PFN > max_pfn) { | 974 | if (highmem_pages + MAXMEM_PFN > max_pfn) { |
963 | printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages)); | 975 | printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages)); |
964 | highmem_pages = 0; | 976 | highmem_pages = 0; |
965 | } | 977 | } |
966 | max_low_pfn = MAXMEM_PFN; | 978 | max_low_pfn = MAXMEM_PFN; |
967 | #ifndef CONFIG_HIGHMEM | 979 | #ifndef CONFIG_HIGHMEM |
968 | /* Maximum memory usable is what is directly addressable */ | 980 | /* Maximum memory usable is what is directly addressable */ |
969 | printk(KERN_WARNING "Warning only %ldMB will be used.\n", | 981 | printk(KERN_WARNING "Warning only %ldMB will be used.\n", |
970 | MAXMEM>>20); | 982 | MAXMEM>>20); |
971 | if (max_pfn > MAX_NONPAE_PFN) | 983 | if (max_pfn > MAX_NONPAE_PFN) |
972 | printk(KERN_WARNING "Use a PAE enabled kernel.\n"); | 984 | printk(KERN_WARNING "Use a PAE enabled kernel.\n"); |
973 | else | 985 | else |
974 | printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); | 986 | printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); |
975 | max_pfn = MAXMEM_PFN; | 987 | max_pfn = MAXMEM_PFN; |
976 | #else /* !CONFIG_HIGHMEM */ | 988 | #else /* !CONFIG_HIGHMEM */ |
977 | #ifndef CONFIG_X86_PAE | 989 | #ifndef CONFIG_X86_PAE |
978 | if (max_pfn > MAX_NONPAE_PFN) { | 990 | if (max_pfn > MAX_NONPAE_PFN) { |
979 | max_pfn = MAX_NONPAE_PFN; | 991 | max_pfn = MAX_NONPAE_PFN; |
980 | printk(KERN_WARNING "Warning only 4GB will be used.\n"); | 992 | printk(KERN_WARNING "Warning only 4GB will be used.\n"); |
981 | printk(KERN_WARNING "Use a PAE enabled kernel.\n"); | 993 | printk(KERN_WARNING "Use a PAE enabled kernel.\n"); |
982 | } | 994 | } |
983 | #endif /* !CONFIG_X86_PAE */ | 995 | #endif /* !CONFIG_X86_PAE */ |
984 | #endif /* !CONFIG_HIGHMEM */ | 996 | #endif /* !CONFIG_HIGHMEM */ |
985 | } else { | 997 | } else { |
986 | if (highmem_pages == -1) | 998 | if (highmem_pages == -1) |
987 | highmem_pages = 0; | 999 | highmem_pages = 0; |
988 | #ifdef CONFIG_HIGHMEM | 1000 | #ifdef CONFIG_HIGHMEM |
989 | if (highmem_pages >= max_pfn) { | 1001 | if (highmem_pages >= max_pfn) { |
990 | printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn)); | 1002 | printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn)); |
991 | highmem_pages = 0; | 1003 | highmem_pages = 0; |
992 | } | 1004 | } |
993 | if (highmem_pages) { | 1005 | if (highmem_pages) { |
994 | if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){ | 1006 | if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){ |
995 | printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages)); | 1007 | printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages)); |
996 | highmem_pages = 0; | 1008 | highmem_pages = 0; |
997 | } | 1009 | } |
998 | max_low_pfn -= highmem_pages; | 1010 | max_low_pfn -= highmem_pages; |
999 | } | 1011 | } |
1000 | #else | 1012 | #else |
1001 | if (highmem_pages) | 1013 | if (highmem_pages) |
1002 | printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n"); | 1014 | printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n"); |
1003 | #endif | 1015 | #endif |
1004 | } | 1016 | } |
1005 | return max_low_pfn; | 1017 | return max_low_pfn; |
1006 | } | 1018 | } |
1007 | 1019 | ||
1008 | /* | 1020 | /* |
1009 | * Free all available memory for boot time allocation. Used | 1021 | * Free all available memory for boot time allocation. Used |
1010 | * as a callback function by efi_memory_walk() | 1022 | * as a callback function by efi_memory_walk() |
1011 | */ | 1023 | */ |
1012 | 1024 | ||
1013 | static int __init | 1025 | static int __init |
1014 | free_available_memory(unsigned long start, unsigned long end, void *arg) | 1026 | free_available_memory(unsigned long start, unsigned long end, void *arg) |
1015 | { | 1027 | { |
1016 | /* check max_low_pfn */ | 1028 | /* check max_low_pfn */ |
1017 | if (start >= ((max_low_pfn + 1) << PAGE_SHIFT)) | 1029 | if (start >= ((max_low_pfn + 1) << PAGE_SHIFT)) |
1018 | return 0; | 1030 | return 0; |
1019 | if (end >= ((max_low_pfn + 1) << PAGE_SHIFT)) | 1031 | if (end >= ((max_low_pfn + 1) << PAGE_SHIFT)) |
1020 | end = (max_low_pfn + 1) << PAGE_SHIFT; | 1032 | end = (max_low_pfn + 1) << PAGE_SHIFT; |
1021 | if (start < end) | 1033 | if (start < end) |
1022 | free_bootmem(start, end - start); | 1034 | free_bootmem(start, end - start); |
1023 | 1035 | ||
1024 | return 0; | 1036 | return 0; |
1025 | } | 1037 | } |
1026 | /* | 1038 | /* |
1027 | * Register fully available low RAM pages with the bootmem allocator. | 1039 | * Register fully available low RAM pages with the bootmem allocator. |
1028 | */ | 1040 | */ |
1029 | static void __init register_bootmem_low_pages(unsigned long max_low_pfn) | 1041 | static void __init register_bootmem_low_pages(unsigned long max_low_pfn) |
1030 | { | 1042 | { |
1031 | int i; | 1043 | int i; |
1032 | 1044 | ||
1033 | if (efi_enabled) { | 1045 | if (efi_enabled) { |
1034 | efi_memmap_walk(free_available_memory, NULL); | 1046 | efi_memmap_walk(free_available_memory, NULL); |
1035 | return; | 1047 | return; |
1036 | } | 1048 | } |
1037 | for (i = 0; i < e820.nr_map; i++) { | 1049 | for (i = 0; i < e820.nr_map; i++) { |
1038 | unsigned long curr_pfn, last_pfn, size; | 1050 | unsigned long curr_pfn, last_pfn, size; |
1039 | /* | 1051 | /* |
1040 | * Reserve usable low memory | 1052 | * Reserve usable low memory |
1041 | */ | 1053 | */ |
1042 | if (e820.map[i].type != E820_RAM) | 1054 | if (e820.map[i].type != E820_RAM) |
1043 | continue; | 1055 | continue; |
1044 | /* | 1056 | /* |
1045 | * We are rounding up the start address of usable memory: | 1057 | * We are rounding up the start address of usable memory: |
1046 | */ | 1058 | */ |
1047 | curr_pfn = PFN_UP(e820.map[i].addr); | 1059 | curr_pfn = PFN_UP(e820.map[i].addr); |
1048 | if (curr_pfn >= max_low_pfn) | 1060 | if (curr_pfn >= max_low_pfn) |
1049 | continue; | 1061 | continue; |
1050 | /* | 1062 | /* |
1051 | * ... and at the end of the usable range downwards: | 1063 | * ... and at the end of the usable range downwards: |
1052 | */ | 1064 | */ |
1053 | last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); | 1065 | last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); |
1054 | 1066 | ||
1055 | if (last_pfn > max_low_pfn) | 1067 | if (last_pfn > max_low_pfn) |
1056 | last_pfn = max_low_pfn; | 1068 | last_pfn = max_low_pfn; |
1057 | 1069 | ||
1058 | /* | 1070 | /* |
1059 | * .. finally, did all the rounding and playing | 1071 | * .. finally, did all the rounding and playing |
1060 | * around just make the area go away? | 1072 | * around just make the area go away? |
1061 | */ | 1073 | */ |
1062 | if (last_pfn <= curr_pfn) | 1074 | if (last_pfn <= curr_pfn) |
1063 | continue; | 1075 | continue; |
1064 | 1076 | ||
1065 | size = last_pfn - curr_pfn; | 1077 | size = last_pfn - curr_pfn; |
1066 | free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); | 1078 | free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); |
1067 | } | 1079 | } |
1068 | } | 1080 | } |
1069 | 1081 | ||
1070 | /* | 1082 | /* |
1071 | * workaround for Dell systems that neglect to reserve EBDA | 1083 | * workaround for Dell systems that neglect to reserve EBDA |
1072 | */ | 1084 | */ |
1073 | static void __init reserve_ebda_region(void) | 1085 | static void __init reserve_ebda_region(void) |
1074 | { | 1086 | { |
1075 | unsigned int addr; | 1087 | unsigned int addr; |
1076 | addr = get_bios_ebda(); | 1088 | addr = get_bios_ebda(); |
1077 | if (addr) | 1089 | if (addr) |
1078 | reserve_bootmem(addr, PAGE_SIZE); | 1090 | reserve_bootmem(addr, PAGE_SIZE); |
1079 | } | 1091 | } |
1080 | 1092 | ||
1081 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 1093 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
1082 | void __init setup_bootmem_allocator(void); | 1094 | void __init setup_bootmem_allocator(void); |
1083 | static unsigned long __init setup_memory(void) | 1095 | static unsigned long __init setup_memory(void) |
1084 | { | 1096 | { |
1085 | /* | 1097 | /* |
1086 | * partially used pages are not usable - thus | 1098 | * partially used pages are not usable - thus |
1087 | * we are rounding upwards: | 1099 | * we are rounding upwards: |
1088 | */ | 1100 | */ |
1089 | min_low_pfn = PFN_UP(init_pg_tables_end); | 1101 | min_low_pfn = PFN_UP(init_pg_tables_end); |
1090 | 1102 | ||
1091 | find_max_pfn(); | 1103 | find_max_pfn(); |
1092 | 1104 | ||
1093 | max_low_pfn = find_max_low_pfn(); | 1105 | max_low_pfn = find_max_low_pfn(); |
1094 | 1106 | ||
1095 | #ifdef CONFIG_HIGHMEM | 1107 | #ifdef CONFIG_HIGHMEM |
1096 | highstart_pfn = highend_pfn = max_pfn; | 1108 | highstart_pfn = highend_pfn = max_pfn; |
1097 | if (max_pfn > max_low_pfn) { | 1109 | if (max_pfn > max_low_pfn) { |
1098 | highstart_pfn = max_low_pfn; | 1110 | highstart_pfn = max_low_pfn; |
1099 | } | 1111 | } |
1100 | printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", | 1112 | printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", |
1101 | pages_to_mb(highend_pfn - highstart_pfn)); | 1113 | pages_to_mb(highend_pfn - highstart_pfn)); |
1102 | #endif | 1114 | #endif |
1103 | printk(KERN_NOTICE "%ldMB LOWMEM available.\n", | 1115 | printk(KERN_NOTICE "%ldMB LOWMEM available.\n", |
1104 | pages_to_mb(max_low_pfn)); | 1116 | pages_to_mb(max_low_pfn)); |
1105 | 1117 | ||
1106 | setup_bootmem_allocator(); | 1118 | setup_bootmem_allocator(); |
1107 | 1119 | ||
1108 | return max_low_pfn; | 1120 | return max_low_pfn; |
1109 | } | 1121 | } |
1110 | 1122 | ||
1111 | void __init zone_sizes_init(void) | 1123 | void __init zone_sizes_init(void) |
1112 | { | 1124 | { |
1113 | unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; | 1125 | unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; |
1114 | unsigned int max_dma, low; | 1126 | unsigned int max_dma, low; |
1115 | 1127 | ||
1116 | max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; | 1128 | max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; |
1117 | low = max_low_pfn; | 1129 | low = max_low_pfn; |
1118 | 1130 | ||
1119 | if (low < max_dma) | 1131 | if (low < max_dma) |
1120 | zones_size[ZONE_DMA] = low; | 1132 | zones_size[ZONE_DMA] = low; |
1121 | else { | 1133 | else { |
1122 | zones_size[ZONE_DMA] = max_dma; | 1134 | zones_size[ZONE_DMA] = max_dma; |
1123 | zones_size[ZONE_NORMAL] = low - max_dma; | 1135 | zones_size[ZONE_NORMAL] = low - max_dma; |
1124 | #ifdef CONFIG_HIGHMEM | 1136 | #ifdef CONFIG_HIGHMEM |
1125 | zones_size[ZONE_HIGHMEM] = highend_pfn - low; | 1137 | zones_size[ZONE_HIGHMEM] = highend_pfn - low; |
1126 | #endif | 1138 | #endif |
1127 | } | 1139 | } |
1128 | free_area_init(zones_size); | 1140 | free_area_init(zones_size); |
1129 | } | 1141 | } |
1130 | #else | 1142 | #else |
1131 | extern unsigned long __init setup_memory(void); | 1143 | extern unsigned long __init setup_memory(void); |
1132 | extern void zone_sizes_init(void); | 1144 | extern void zone_sizes_init(void); |
1133 | #endif /* !CONFIG_NEED_MULTIPLE_NODES */ | 1145 | #endif /* !CONFIG_NEED_MULTIPLE_NODES */ |
1134 | 1146 | ||
1135 | void __init setup_bootmem_allocator(void) | 1147 | void __init setup_bootmem_allocator(void) |
1136 | { | 1148 | { |
1137 | unsigned long bootmap_size; | 1149 | unsigned long bootmap_size; |
1138 | /* | 1150 | /* |
1139 | * Initialize the boot-time allocator (with low memory only): | 1151 | * Initialize the boot-time allocator (with low memory only): |
1140 | */ | 1152 | */ |
1141 | bootmap_size = init_bootmem(min_low_pfn, max_low_pfn); | 1153 | bootmap_size = init_bootmem(min_low_pfn, max_low_pfn); |
1142 | 1154 | ||
1143 | register_bootmem_low_pages(max_low_pfn); | 1155 | register_bootmem_low_pages(max_low_pfn); |
1144 | 1156 | ||
1145 | /* | 1157 | /* |
1146 | * Reserve the bootmem bitmap itself as well. We do this in two | 1158 | * Reserve the bootmem bitmap itself as well. We do this in two |
1147 | * steps (first step was init_bootmem()) because this catches | 1159 | * steps (first step was init_bootmem()) because this catches |
1148 | * the (very unlikely) case of us accidentally initializing the | 1160 | * the (very unlikely) case of us accidentally initializing the |
1149 | * bootmem allocator with an invalid RAM area. | 1161 | * bootmem allocator with an invalid RAM area. |
1150 | */ | 1162 | */ |
1151 | reserve_bootmem(__PHYSICAL_START, (PFN_PHYS(min_low_pfn) + | 1163 | reserve_bootmem(__PHYSICAL_START, (PFN_PHYS(min_low_pfn) + |
1152 | bootmap_size + PAGE_SIZE-1) - (__PHYSICAL_START)); | 1164 | bootmap_size + PAGE_SIZE-1) - (__PHYSICAL_START)); |
1153 | 1165 | ||
1154 | /* | 1166 | /* |
1155 | * reserve physical page 0 - it's a special BIOS page on many boxes, | 1167 | * reserve physical page 0 - it's a special BIOS page on many boxes, |
1156 | * enabling clean reboots, SMP operation, laptop functions. | 1168 | * enabling clean reboots, SMP operation, laptop functions. |
1157 | */ | 1169 | */ |
1158 | reserve_bootmem(0, PAGE_SIZE); | 1170 | reserve_bootmem(0, PAGE_SIZE); |
1159 | 1171 | ||
1160 | /* reserve EBDA region, it's a 4K region */ | 1172 | /* reserve EBDA region, it's a 4K region */ |
1161 | reserve_ebda_region(); | 1173 | reserve_ebda_region(); |
1162 | 1174 | ||
1163 | /* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent | 1175 | /* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent |
1164 | PCI prefetch into it (errata #56). Usually the page is reserved anyways, | 1176 | PCI prefetch into it (errata #56). Usually the page is reserved anyways, |
1165 | unless you have no PS/2 mouse plugged in. */ | 1177 | unless you have no PS/2 mouse plugged in. */ |
1166 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && | 1178 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && |
1167 | boot_cpu_data.x86 == 6) | 1179 | boot_cpu_data.x86 == 6) |
1168 | reserve_bootmem(0xa0000 - 4096, 4096); | 1180 | reserve_bootmem(0xa0000 - 4096, 4096); |
1169 | 1181 | ||
1170 | #ifdef CONFIG_SMP | 1182 | #ifdef CONFIG_SMP |
1171 | /* | 1183 | /* |
1172 | * But first pinch a few for the stack/trampoline stuff | 1184 | * But first pinch a few for the stack/trampoline stuff |
1173 | * FIXME: Don't need the extra page at 4K, but need to fix | 1185 | * FIXME: Don't need the extra page at 4K, but need to fix |
1174 | * trampoline before removing it. (see the GDT stuff) | 1186 | * trampoline before removing it. (see the GDT stuff) |
1175 | */ | 1187 | */ |
1176 | reserve_bootmem(PAGE_SIZE, PAGE_SIZE); | 1188 | reserve_bootmem(PAGE_SIZE, PAGE_SIZE); |
1177 | #endif | 1189 | #endif |
1178 | #ifdef CONFIG_ACPI_SLEEP | 1190 | #ifdef CONFIG_ACPI_SLEEP |
1179 | /* | 1191 | /* |
1180 | * Reserve low memory region for sleep support. | 1192 | * Reserve low memory region for sleep support. |
1181 | */ | 1193 | */ |
1182 | acpi_reserve_bootmem(); | 1194 | acpi_reserve_bootmem(); |
1183 | #endif | 1195 | #endif |
1184 | #ifdef CONFIG_X86_FIND_SMP_CONFIG | 1196 | #ifdef CONFIG_X86_FIND_SMP_CONFIG |
1185 | /* | 1197 | /* |
1186 | * Find and reserve possible boot-time SMP configuration: | 1198 | * Find and reserve possible boot-time SMP configuration: |
1187 | */ | 1199 | */ |
1188 | find_smp_config(); | 1200 | find_smp_config(); |
1189 | #endif | 1201 | #endif |
1190 | 1202 | ||
1191 | #ifdef CONFIG_BLK_DEV_INITRD | 1203 | #ifdef CONFIG_BLK_DEV_INITRD |
1192 | if (LOADER_TYPE && INITRD_START) { | 1204 | if (LOADER_TYPE && INITRD_START) { |
1193 | if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { | 1205 | if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { |
1194 | reserve_bootmem(INITRD_START, INITRD_SIZE); | 1206 | reserve_bootmem(INITRD_START, INITRD_SIZE); |
1195 | initrd_start = | 1207 | initrd_start = |
1196 | INITRD_START ? INITRD_START + PAGE_OFFSET : 0; | 1208 | INITRD_START ? INITRD_START + PAGE_OFFSET : 0; |
1197 | initrd_end = initrd_start+INITRD_SIZE; | 1209 | initrd_end = initrd_start+INITRD_SIZE; |
1198 | } | 1210 | } |
1199 | else { | 1211 | else { |
1200 | printk(KERN_ERR "initrd extends beyond end of memory " | 1212 | printk(KERN_ERR "initrd extends beyond end of memory " |
1201 | "(0x%08lx > 0x%08lx)\ndisabling initrd\n", | 1213 | "(0x%08lx > 0x%08lx)\ndisabling initrd\n", |
1202 | INITRD_START + INITRD_SIZE, | 1214 | INITRD_START + INITRD_SIZE, |
1203 | max_low_pfn << PAGE_SHIFT); | 1215 | max_low_pfn << PAGE_SHIFT); |
1204 | initrd_start = 0; | 1216 | initrd_start = 0; |
1205 | } | 1217 | } |
1206 | } | 1218 | } |
1207 | #endif | 1219 | #endif |
1208 | #ifdef CONFIG_KEXEC | 1220 | #ifdef CONFIG_KEXEC |
1209 | if (crashk_res.start != crashk_res.end) | 1221 | if (crashk_res.start != crashk_res.end) |
1210 | reserve_bootmem(crashk_res.start, | 1222 | reserve_bootmem(crashk_res.start, |
1211 | crashk_res.end - crashk_res.start + 1); | 1223 | crashk_res.end - crashk_res.start + 1); |
1212 | #endif | 1224 | #endif |
1213 | } | 1225 | } |
1214 | 1226 | ||
1215 | /* | 1227 | /* |
1216 | * The node 0 pgdat is initialized before all of these because | 1228 | * The node 0 pgdat is initialized before all of these because |
1217 | * it's needed for bootmem. node>0 pgdats have their virtual | 1229 | * it's needed for bootmem. node>0 pgdats have their virtual |
1218 | * space allocated before the pagetables are in place to access | 1230 | * space allocated before the pagetables are in place to access |
1219 | * them, so they can't be cleared then. | 1231 | * them, so they can't be cleared then. |
1220 | * | 1232 | * |
1221 | * This should all compile down to nothing when NUMA is off. | 1233 | * This should all compile down to nothing when NUMA is off. |
1222 | */ | 1234 | */ |
1223 | void __init remapped_pgdat_init(void) | 1235 | void __init remapped_pgdat_init(void) |
1224 | { | 1236 | { |
1225 | int nid; | 1237 | int nid; |
1226 | 1238 | ||
1227 | for_each_online_node(nid) { | 1239 | for_each_online_node(nid) { |
1228 | if (nid != 0) | 1240 | if (nid != 0) |
1229 | memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); | 1241 | memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); |
1230 | } | 1242 | } |
1231 | } | 1243 | } |
1232 | 1244 | ||
1233 | /* | 1245 | /* |
1234 | * Request address space for all standard RAM and ROM resources | 1246 | * Request address space for all standard RAM and ROM resources |
1235 | * and also for regions reported as reserved by the e820. | 1247 | * and also for regions reported as reserved by the e820. |
1236 | */ | 1248 | */ |
1237 | static void __init | 1249 | static void __init |
1238 | legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource) | 1250 | legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource) |
1239 | { | 1251 | { |
1240 | int i; | 1252 | int i; |
1241 | 1253 | ||
1242 | probe_roms(); | 1254 | probe_roms(); |
1243 | for (i = 0; i < e820.nr_map; i++) { | 1255 | for (i = 0; i < e820.nr_map; i++) { |
1244 | struct resource *res; | 1256 | struct resource *res; |
1245 | if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) | 1257 | if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) |
1246 | continue; | 1258 | continue; |
1247 | res = alloc_bootmem_low(sizeof(struct resource)); | 1259 | res = alloc_bootmem_low(sizeof(struct resource)); |
1248 | switch (e820.map[i].type) { | 1260 | switch (e820.map[i].type) { |
1249 | case E820_RAM: res->name = "System RAM"; break; | 1261 | case E820_RAM: res->name = "System RAM"; break; |
1250 | case E820_ACPI: res->name = "ACPI Tables"; break; | 1262 | case E820_ACPI: res->name = "ACPI Tables"; break; |
1251 | case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; | 1263 | case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; |
1252 | default: res->name = "reserved"; | 1264 | default: res->name = "reserved"; |
1253 | } | 1265 | } |
1254 | res->start = e820.map[i].addr; | 1266 | res->start = e820.map[i].addr; |
1255 | res->end = res->start + e820.map[i].size - 1; | 1267 | res->end = res->start + e820.map[i].size - 1; |
1256 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | 1268 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; |
1257 | request_resource(&iomem_resource, res); | 1269 | request_resource(&iomem_resource, res); |
1258 | if (e820.map[i].type == E820_RAM) { | 1270 | if (e820.map[i].type == E820_RAM) { |
1259 | /* | 1271 | /* |
1260 | * We don't know which RAM region contains kernel data, | 1272 | * We don't know which RAM region contains kernel data, |
1261 | * so we try it repeatedly and let the resource manager | 1273 | * so we try it repeatedly and let the resource manager |
1262 | * test it. | 1274 | * test it. |
1263 | */ | 1275 | */ |
1264 | request_resource(res, code_resource); | 1276 | request_resource(res, code_resource); |
1265 | request_resource(res, data_resource); | 1277 | request_resource(res, data_resource); |
1266 | #ifdef CONFIG_KEXEC | 1278 | #ifdef CONFIG_KEXEC |
1267 | request_resource(res, &crashk_res); | 1279 | request_resource(res, &crashk_res); |
1268 | #endif | 1280 | #endif |
1269 | } | 1281 | } |
1270 | } | 1282 | } |
1271 | } | 1283 | } |
1272 | 1284 | ||
1273 | /* | 1285 | /* |
1274 | * Request address space for all standard resources | 1286 | * Request address space for all standard resources |
1275 | */ | 1287 | */ |
1276 | static void __init register_memory(void) | 1288 | static void __init register_memory(void) |
1277 | { | 1289 | { |
1278 | unsigned long gapstart, gapsize; | 1290 | unsigned long gapstart, gapsize; |
1279 | unsigned long long last; | 1291 | unsigned long long last; |
1280 | int i; | 1292 | int i; |
1281 | 1293 | ||
1282 | if (efi_enabled) | 1294 | if (efi_enabled) |
1283 | efi_initialize_iomem_resources(&code_resource, &data_resource); | 1295 | efi_initialize_iomem_resources(&code_resource, &data_resource); |
1284 | else | 1296 | else |
1285 | legacy_init_iomem_resources(&code_resource, &data_resource); | 1297 | legacy_init_iomem_resources(&code_resource, &data_resource); |
1286 | 1298 | ||
1287 | /* EFI systems may still have VGA */ | 1299 | /* EFI systems may still have VGA */ |
1288 | request_resource(&iomem_resource, &video_ram_resource); | 1300 | request_resource(&iomem_resource, &video_ram_resource); |
1289 | 1301 | ||
1290 | /* request I/O space for devices used on all i[345]86 PCs */ | 1302 | /* request I/O space for devices used on all i[345]86 PCs */ |
1291 | for (i = 0; i < STANDARD_IO_RESOURCES; i++) | 1303 | for (i = 0; i < STANDARD_IO_RESOURCES; i++) |
1292 | request_resource(&ioport_resource, &standard_io_resources[i]); | 1304 | request_resource(&ioport_resource, &standard_io_resources[i]); |
1293 | 1305 | ||
1294 | /* | 1306 | /* |
1295 | * Search for the bigest gap in the low 32 bits of the e820 | 1307 | * Search for the bigest gap in the low 32 bits of the e820 |
1296 | * memory space. | 1308 | * memory space. |
1297 | */ | 1309 | */ |
1298 | last = 0x100000000ull; | 1310 | last = 0x100000000ull; |
1299 | gapstart = 0x10000000; | 1311 | gapstart = 0x10000000; |
1300 | gapsize = 0x400000; | 1312 | gapsize = 0x400000; |
1301 | i = e820.nr_map; | 1313 | i = e820.nr_map; |
1302 | while (--i >= 0) { | 1314 | while (--i >= 0) { |
1303 | unsigned long long start = e820.map[i].addr; | 1315 | unsigned long long start = e820.map[i].addr; |
1304 | unsigned long long end = start + e820.map[i].size; | 1316 | unsigned long long end = start + e820.map[i].size; |
1305 | 1317 | ||
1306 | /* | 1318 | /* |
1307 | * Since "last" is at most 4GB, we know we'll | 1319 | * Since "last" is at most 4GB, we know we'll |
1308 | * fit in 32 bits if this condition is true | 1320 | * fit in 32 bits if this condition is true |
1309 | */ | 1321 | */ |
1310 | if (last > end) { | 1322 | if (last > end) { |
1311 | unsigned long gap = last - end; | 1323 | unsigned long gap = last - end; |
1312 | 1324 | ||
1313 | if (gap > gapsize) { | 1325 | if (gap > gapsize) { |
1314 | gapsize = gap; | 1326 | gapsize = gap; |
1315 | gapstart = end; | 1327 | gapstart = end; |
1316 | } | 1328 | } |
1317 | } | 1329 | } |
1318 | if (start < last) | 1330 | if (start < last) |
1319 | last = start; | 1331 | last = start; |
1320 | } | 1332 | } |
1321 | 1333 | ||
1322 | /* | 1334 | /* |
1323 | * Start allocating dynamic PCI memory a bit into the gap, | 1335 | * Start allocating dynamic PCI memory a bit into the gap, |
1324 | * aligned up to the nearest megabyte. | 1336 | * aligned up to the nearest megabyte. |
1325 | * | 1337 | * |
1326 | * Question: should we try to pad it up a bit (do something | 1338 | * Question: should we try to pad it up a bit (do something |
1327 | * like " + (gapsize >> 3)" in there too?). We now have the | 1339 | * like " + (gapsize >> 3)" in there too?). We now have the |
1328 | * technology. | 1340 | * technology. |
1329 | */ | 1341 | */ |
1330 | pci_mem_start = (gapstart + 0xfffff) & ~0xfffff; | 1342 | pci_mem_start = (gapstart + 0xfffff) & ~0xfffff; |
1331 | 1343 | ||
1332 | printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n", | 1344 | printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n", |
1333 | pci_mem_start, gapstart, gapsize); | 1345 | pci_mem_start, gapstart, gapsize); |
1334 | } | 1346 | } |
1335 | 1347 | ||
1336 | /* Use inline assembly to define this because the nops are defined | 1348 | /* Use inline assembly to define this because the nops are defined |
1337 | as inline assembly strings in the include files and we cannot | 1349 | as inline assembly strings in the include files and we cannot |
1338 | get them easily into strings. */ | 1350 | get them easily into strings. */ |
1339 | asm("\t.data\nintelnops: " | 1351 | asm("\t.data\nintelnops: " |
1340 | GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6 | 1352 | GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6 |
1341 | GENERIC_NOP7 GENERIC_NOP8); | 1353 | GENERIC_NOP7 GENERIC_NOP8); |
1342 | asm("\t.data\nk8nops: " | 1354 | asm("\t.data\nk8nops: " |
1343 | K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6 | 1355 | K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6 |
1344 | K8_NOP7 K8_NOP8); | 1356 | K8_NOP7 K8_NOP8); |
1345 | asm("\t.data\nk7nops: " | 1357 | asm("\t.data\nk7nops: " |
1346 | K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6 | 1358 | K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6 |
1347 | K7_NOP7 K7_NOP8); | 1359 | K7_NOP7 K7_NOP8); |
1348 | 1360 | ||
1349 | extern unsigned char intelnops[], k8nops[], k7nops[]; | 1361 | extern unsigned char intelnops[], k8nops[], k7nops[]; |
1350 | static unsigned char *intel_nops[ASM_NOP_MAX+1] = { | 1362 | static unsigned char *intel_nops[ASM_NOP_MAX+1] = { |
1351 | NULL, | 1363 | NULL, |
1352 | intelnops, | 1364 | intelnops, |
1353 | intelnops + 1, | 1365 | intelnops + 1, |
1354 | intelnops + 1 + 2, | 1366 | intelnops + 1 + 2, |
1355 | intelnops + 1 + 2 + 3, | 1367 | intelnops + 1 + 2 + 3, |
1356 | intelnops + 1 + 2 + 3 + 4, | 1368 | intelnops + 1 + 2 + 3 + 4, |
1357 | intelnops + 1 + 2 + 3 + 4 + 5, | 1369 | intelnops + 1 + 2 + 3 + 4 + 5, |
1358 | intelnops + 1 + 2 + 3 + 4 + 5 + 6, | 1370 | intelnops + 1 + 2 + 3 + 4 + 5 + 6, |
1359 | intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7, | 1371 | intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7, |
1360 | }; | 1372 | }; |
1361 | static unsigned char *k8_nops[ASM_NOP_MAX+1] = { | 1373 | static unsigned char *k8_nops[ASM_NOP_MAX+1] = { |
1362 | NULL, | 1374 | NULL, |
1363 | k8nops, | 1375 | k8nops, |
1364 | k8nops + 1, | 1376 | k8nops + 1, |
1365 | k8nops + 1 + 2, | 1377 | k8nops + 1 + 2, |
1366 | k8nops + 1 + 2 + 3, | 1378 | k8nops + 1 + 2 + 3, |
1367 | k8nops + 1 + 2 + 3 + 4, | 1379 | k8nops + 1 + 2 + 3 + 4, |
1368 | k8nops + 1 + 2 + 3 + 4 + 5, | 1380 | k8nops + 1 + 2 + 3 + 4 + 5, |
1369 | k8nops + 1 + 2 + 3 + 4 + 5 + 6, | 1381 | k8nops + 1 + 2 + 3 + 4 + 5 + 6, |
1370 | k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, | 1382 | k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, |
1371 | }; | 1383 | }; |
1372 | static unsigned char *k7_nops[ASM_NOP_MAX+1] = { | 1384 | static unsigned char *k7_nops[ASM_NOP_MAX+1] = { |
1373 | NULL, | 1385 | NULL, |
1374 | k7nops, | 1386 | k7nops, |
1375 | k7nops + 1, | 1387 | k7nops + 1, |
1376 | k7nops + 1 + 2, | 1388 | k7nops + 1 + 2, |
1377 | k7nops + 1 + 2 + 3, | 1389 | k7nops + 1 + 2 + 3, |
1378 | k7nops + 1 + 2 + 3 + 4, | 1390 | k7nops + 1 + 2 + 3 + 4, |
1379 | k7nops + 1 + 2 + 3 + 4 + 5, | 1391 | k7nops + 1 + 2 + 3 + 4 + 5, |
1380 | k7nops + 1 + 2 + 3 + 4 + 5 + 6, | 1392 | k7nops + 1 + 2 + 3 + 4 + 5 + 6, |
1381 | k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, | 1393 | k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, |
1382 | }; | 1394 | }; |
1383 | static struct nop { | 1395 | static struct nop { |
1384 | int cpuid; | 1396 | int cpuid; |
1385 | unsigned char **noptable; | 1397 | unsigned char **noptable; |
1386 | } noptypes[] = { | 1398 | } noptypes[] = { |
1387 | { X86_FEATURE_K8, k8_nops }, | 1399 | { X86_FEATURE_K8, k8_nops }, |
1388 | { X86_FEATURE_K7, k7_nops }, | 1400 | { X86_FEATURE_K7, k7_nops }, |
1389 | { -1, NULL } | 1401 | { -1, NULL } |
1390 | }; | 1402 | }; |
1391 | 1403 | ||
1392 | /* Replace instructions with better alternatives for this CPU type. | 1404 | /* Replace instructions with better alternatives for this CPU type. |
1393 | 1405 | ||
1394 | This runs before SMP is initialized to avoid SMP problems with | 1406 | This runs before SMP is initialized to avoid SMP problems with |
1395 | self modifying code. This implies that assymetric systems where | 1407 | self modifying code. This implies that assymetric systems where |
1396 | APs have less capabilities than the boot processor are not handled. | 1408 | APs have less capabilities than the boot processor are not handled. |
1397 | In this case boot with "noreplacement". */ | 1409 | In this case boot with "noreplacement". */ |
1398 | void apply_alternatives(void *start, void *end) | 1410 | void apply_alternatives(void *start, void *end) |
1399 | { | 1411 | { |
1400 | struct alt_instr *a; | 1412 | struct alt_instr *a; |
1401 | int diff, i, k; | 1413 | int diff, i, k; |
1402 | unsigned char **noptable = intel_nops; | 1414 | unsigned char **noptable = intel_nops; |
1403 | for (i = 0; noptypes[i].cpuid >= 0; i++) { | 1415 | for (i = 0; noptypes[i].cpuid >= 0; i++) { |
1404 | if (boot_cpu_has(noptypes[i].cpuid)) { | 1416 | if (boot_cpu_has(noptypes[i].cpuid)) { |
1405 | noptable = noptypes[i].noptable; | 1417 | noptable = noptypes[i].noptable; |
1406 | break; | 1418 | break; |
1407 | } | 1419 | } |
1408 | } | 1420 | } |
1409 | for (a = start; (void *)a < end; a++) { | 1421 | for (a = start; (void *)a < end; a++) { |
1410 | if (!boot_cpu_has(a->cpuid)) | 1422 | if (!boot_cpu_has(a->cpuid)) |
1411 | continue; | 1423 | continue; |
1412 | BUG_ON(a->replacementlen > a->instrlen); | 1424 | BUG_ON(a->replacementlen > a->instrlen); |
1413 | memcpy(a->instr, a->replacement, a->replacementlen); | 1425 | memcpy(a->instr, a->replacement, a->replacementlen); |
1414 | diff = a->instrlen - a->replacementlen; | 1426 | diff = a->instrlen - a->replacementlen; |
1415 | /* Pad the rest with nops */ | 1427 | /* Pad the rest with nops */ |
1416 | for (i = a->replacementlen; diff > 0; diff -= k, i += k) { | 1428 | for (i = a->replacementlen; diff > 0; diff -= k, i += k) { |
1417 | k = diff; | 1429 | k = diff; |
1418 | if (k > ASM_NOP_MAX) | 1430 | if (k > ASM_NOP_MAX) |
1419 | k = ASM_NOP_MAX; | 1431 | k = ASM_NOP_MAX; |
1420 | memcpy(a->instr + i, noptable[k], k); | 1432 | memcpy(a->instr + i, noptable[k], k); |
1421 | } | 1433 | } |
1422 | } | 1434 | } |
1423 | } | 1435 | } |
1424 | 1436 | ||
1425 | static int no_replacement __initdata = 0; | 1437 | static int no_replacement __initdata = 0; |
1426 | 1438 | ||
1427 | void __init alternative_instructions(void) | 1439 | void __init alternative_instructions(void) |
1428 | { | 1440 | { |
1429 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; | 1441 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; |
1430 | if (no_replacement) | 1442 | if (no_replacement) |
1431 | return; | 1443 | return; |
1432 | apply_alternatives(__alt_instructions, __alt_instructions_end); | 1444 | apply_alternatives(__alt_instructions, __alt_instructions_end); |
1433 | } | 1445 | } |
1434 | 1446 | ||
1435 | static int __init noreplacement_setup(char *s) | 1447 | static int __init noreplacement_setup(char *s) |
1436 | { | 1448 | { |
1437 | no_replacement = 1; | 1449 | no_replacement = 1; |
1438 | return 0; | 1450 | return 0; |
1439 | } | 1451 | } |
1440 | 1452 | ||
1441 | __setup("noreplacement", noreplacement_setup); | 1453 | __setup("noreplacement", noreplacement_setup); |
1442 | 1454 | ||
1443 | static char * __init machine_specific_memory_setup(void); | 1455 | static char * __init machine_specific_memory_setup(void); |
1444 | 1456 | ||
1445 | #ifdef CONFIG_MCA | 1457 | #ifdef CONFIG_MCA |
1446 | static void set_mca_bus(int x) | 1458 | static void set_mca_bus(int x) |
1447 | { | 1459 | { |
1448 | MCA_bus = x; | 1460 | MCA_bus = x; |
1449 | } | 1461 | } |
1450 | #else | 1462 | #else |
1451 | static void set_mca_bus(int x) { } | 1463 | static void set_mca_bus(int x) { } |
1452 | #endif | 1464 | #endif |
1453 | 1465 | ||
1454 | /* | 1466 | /* |
1455 | * Determine if we were loaded by an EFI loader. If so, then we have also been | 1467 | * Determine if we were loaded by an EFI loader. If so, then we have also been |
1456 | * passed the efi memmap, systab, etc., so we should use these data structures | 1468 | * passed the efi memmap, systab, etc., so we should use these data structures |
1457 | * for initialization. Note, the efi init code path is determined by the | 1469 | * for initialization. Note, the efi init code path is determined by the |
1458 | * global efi_enabled. This allows the same kernel image to be used on existing | 1470 | * global efi_enabled. This allows the same kernel image to be used on existing |
1459 | * systems (with a traditional BIOS) as well as on EFI systems. | 1471 | * systems (with a traditional BIOS) as well as on EFI systems. |
1460 | */ | 1472 | */ |
1461 | void __init setup_arch(char **cmdline_p) | 1473 | void __init setup_arch(char **cmdline_p) |
1462 | { | 1474 | { |
1463 | unsigned long max_low_pfn; | 1475 | unsigned long max_low_pfn; |
1464 | 1476 | ||
1465 | memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); | 1477 | memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); |
1466 | pre_setup_arch_hook(); | 1478 | pre_setup_arch_hook(); |
1467 | early_cpu_init(); | 1479 | early_cpu_init(); |
1468 | 1480 | ||
1469 | /* | 1481 | /* |
1470 | * FIXME: This isn't an official loader_type right | 1482 | * FIXME: This isn't an official loader_type right |
1471 | * now but does currently work with elilo. | 1483 | * now but does currently work with elilo. |
1472 | * If we were configured as an EFI kernel, check to make | 1484 | * If we were configured as an EFI kernel, check to make |
1473 | * sure that we were loaded correctly from elilo and that | 1485 | * sure that we were loaded correctly from elilo and that |
1474 | * the system table is valid. If not, then initialize normally. | 1486 | * the system table is valid. If not, then initialize normally. |
1475 | */ | 1487 | */ |
1476 | #ifdef CONFIG_EFI | 1488 | #ifdef CONFIG_EFI |
1477 | if ((LOADER_TYPE == 0x50) && EFI_SYSTAB) | 1489 | if ((LOADER_TYPE == 0x50) && EFI_SYSTAB) |
1478 | efi_enabled = 1; | 1490 | efi_enabled = 1; |
1479 | #endif | 1491 | #endif |
1480 | 1492 | ||
1481 | ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); | 1493 | ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); |
1482 | drive_info = DRIVE_INFO; | 1494 | drive_info = DRIVE_INFO; |
1483 | screen_info = SCREEN_INFO; | 1495 | screen_info = SCREEN_INFO; |
1484 | edid_info = EDID_INFO; | 1496 | edid_info = EDID_INFO; |
1485 | apm_info.bios = APM_BIOS_INFO; | 1497 | apm_info.bios = APM_BIOS_INFO; |
1486 | ist_info = IST_INFO; | 1498 | ist_info = IST_INFO; |
1487 | saved_videomode = VIDEO_MODE; | 1499 | saved_videomode = VIDEO_MODE; |
1488 | if( SYS_DESC_TABLE.length != 0 ) { | 1500 | if( SYS_DESC_TABLE.length != 0 ) { |
1489 | set_mca_bus(SYS_DESC_TABLE.table[3] & 0x2); | 1501 | set_mca_bus(SYS_DESC_TABLE.table[3] & 0x2); |
1490 | machine_id = SYS_DESC_TABLE.table[0]; | 1502 | machine_id = SYS_DESC_TABLE.table[0]; |
1491 | machine_submodel_id = SYS_DESC_TABLE.table[1]; | 1503 | machine_submodel_id = SYS_DESC_TABLE.table[1]; |
1492 | BIOS_revision = SYS_DESC_TABLE.table[2]; | 1504 | BIOS_revision = SYS_DESC_TABLE.table[2]; |
1493 | } | 1505 | } |
1494 | bootloader_type = LOADER_TYPE; | 1506 | bootloader_type = LOADER_TYPE; |
1495 | 1507 | ||
1496 | #ifdef CONFIG_BLK_DEV_RAM | 1508 | #ifdef CONFIG_BLK_DEV_RAM |
1497 | rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; | 1509 | rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; |
1498 | rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); | 1510 | rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); |
1499 | rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); | 1511 | rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); |
1500 | #endif | 1512 | #endif |
1501 | ARCH_SETUP | 1513 | ARCH_SETUP |
1502 | if (efi_enabled) | 1514 | if (efi_enabled) |
1503 | efi_init(); | 1515 | efi_init(); |
1504 | else { | 1516 | else { |
1505 | printk(KERN_INFO "BIOS-provided physical RAM map:\n"); | 1517 | printk(KERN_INFO "BIOS-provided physical RAM map:\n"); |
1506 | print_memory_map(machine_specific_memory_setup()); | 1518 | print_memory_map(machine_specific_memory_setup()); |
1507 | } | 1519 | } |
1508 | 1520 | ||
1509 | copy_edd(); | 1521 | copy_edd(); |
1510 | 1522 | ||
1511 | if (!MOUNT_ROOT_RDONLY) | 1523 | if (!MOUNT_ROOT_RDONLY) |
1512 | root_mountflags &= ~MS_RDONLY; | 1524 | root_mountflags &= ~MS_RDONLY; |
1513 | init_mm.start_code = (unsigned long) _text; | 1525 | init_mm.start_code = (unsigned long) _text; |
1514 | init_mm.end_code = (unsigned long) _etext; | 1526 | init_mm.end_code = (unsigned long) _etext; |
1515 | init_mm.end_data = (unsigned long) _edata; | 1527 | init_mm.end_data = (unsigned long) _edata; |
1516 | init_mm.brk = init_pg_tables_end + PAGE_OFFSET; | 1528 | init_mm.brk = init_pg_tables_end + PAGE_OFFSET; |
1517 | 1529 | ||
1518 | code_resource.start = virt_to_phys(_text); | 1530 | code_resource.start = virt_to_phys(_text); |
1519 | code_resource.end = virt_to_phys(_etext)-1; | 1531 | code_resource.end = virt_to_phys(_etext)-1; |
1520 | data_resource.start = virt_to_phys(_etext); | 1532 | data_resource.start = virt_to_phys(_etext); |
1521 | data_resource.end = virt_to_phys(_edata)-1; | 1533 | data_resource.end = virt_to_phys(_edata)-1; |
1522 | 1534 | ||
1523 | parse_cmdline_early(cmdline_p); | 1535 | parse_cmdline_early(cmdline_p); |
1524 | 1536 | ||
1525 | max_low_pfn = setup_memory(); | 1537 | max_low_pfn = setup_memory(); |
1526 | 1538 | ||
1527 | /* | 1539 | /* |
1528 | * NOTE: before this point _nobody_ is allowed to allocate | 1540 | * NOTE: before this point _nobody_ is allowed to allocate |
1529 | * any memory using the bootmem allocator. Although the | 1541 | * any memory using the bootmem allocator. Although the |
1530 | * alloctor is now initialised only the first 8Mb of the kernel | 1542 | * alloctor is now initialised only the first 8Mb of the kernel |
1531 | * virtual address space has been mapped. All allocations before | 1543 | * virtual address space has been mapped. All allocations before |
1532 | * paging_init() has completed must use the alloc_bootmem_low_pages() | 1544 | * paging_init() has completed must use the alloc_bootmem_low_pages() |
1533 | * variant (which allocates DMA'able memory) and care must be taken | 1545 | * variant (which allocates DMA'able memory) and care must be taken |
1534 | * not to exceed the 8Mb limit. | 1546 | * not to exceed the 8Mb limit. |
1535 | */ | 1547 | */ |
1536 | 1548 | ||
1537 | #ifdef CONFIG_SMP | 1549 | #ifdef CONFIG_SMP |
1538 | smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ | 1550 | smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ |
1539 | #endif | 1551 | #endif |
1540 | paging_init(); | 1552 | paging_init(); |
1541 | remapped_pgdat_init(); | 1553 | remapped_pgdat_init(); |
1542 | sparse_init(); | 1554 | sparse_init(); |
1543 | zone_sizes_init(); | 1555 | zone_sizes_init(); |
1544 | 1556 | ||
1545 | /* | 1557 | /* |
1546 | * NOTE: at this point the bootmem allocator is fully available. | 1558 | * NOTE: at this point the bootmem allocator is fully available. |
1547 | */ | 1559 | */ |
1548 | 1560 | ||
1549 | #ifdef CONFIG_EARLY_PRINTK | 1561 | #ifdef CONFIG_EARLY_PRINTK |
1550 | { | 1562 | { |
1551 | char *s = strstr(*cmdline_p, "earlyprintk="); | 1563 | char *s = strstr(*cmdline_p, "earlyprintk="); |
1552 | if (s) { | 1564 | if (s) { |
1553 | extern void setup_early_printk(char *); | 1565 | extern void setup_early_printk(char *); |
1554 | 1566 | ||
1555 | setup_early_printk(s); | 1567 | setup_early_printk(s); |
1556 | printk("early console enabled\n"); | 1568 | printk("early console enabled\n"); |
1557 | } | 1569 | } |
1558 | } | 1570 | } |
1559 | #endif | 1571 | #endif |
1560 | 1572 | ||
1561 | 1573 | ||
1562 | dmi_scan_machine(); | 1574 | dmi_scan_machine(); |
1563 | 1575 | ||
1564 | #ifdef CONFIG_X86_GENERICARCH | 1576 | #ifdef CONFIG_X86_GENERICARCH |
1565 | generic_apic_probe(*cmdline_p); | 1577 | generic_apic_probe(*cmdline_p); |
1566 | #endif | 1578 | #endif |
1567 | if (efi_enabled) | 1579 | if (efi_enabled) |
1568 | efi_map_memmap(); | 1580 | efi_map_memmap(); |
1569 | 1581 | ||
1570 | #ifdef CONFIG_ACPI_BOOT | 1582 | #ifdef CONFIG_ACPI_BOOT |
1571 | /* | 1583 | /* |
1572 | * Parse the ACPI tables for possible boot-time SMP configuration. | 1584 | * Parse the ACPI tables for possible boot-time SMP configuration. |
1573 | */ | 1585 | */ |
1574 | acpi_boot_table_init(); | 1586 | acpi_boot_table_init(); |
1575 | acpi_boot_init(); | 1587 | acpi_boot_init(); |
1576 | #endif | 1588 | #endif |
1577 | 1589 | ||
1578 | #ifdef CONFIG_X86_LOCAL_APIC | 1590 | #ifdef CONFIG_X86_LOCAL_APIC |
1579 | if (smp_found_config) | 1591 | if (smp_found_config) |
1580 | get_smp_config(); | 1592 | get_smp_config(); |
1581 | #endif | 1593 | #endif |
1582 | 1594 | ||
1583 | register_memory(); | 1595 | register_memory(); |
1584 | 1596 | ||
1585 | #ifdef CONFIG_VT | 1597 | #ifdef CONFIG_VT |
1586 | #if defined(CONFIG_VGA_CONSOLE) | 1598 | #if defined(CONFIG_VGA_CONSOLE) |
1587 | if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY)) | 1599 | if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY)) |
1588 | conswitchp = &vga_con; | 1600 | conswitchp = &vga_con; |
1589 | #elif defined(CONFIG_DUMMY_CONSOLE) | 1601 | #elif defined(CONFIG_DUMMY_CONSOLE) |
1590 | conswitchp = &dummy_con; | 1602 | conswitchp = &dummy_con; |
1591 | #endif | 1603 | #endif |
1592 | #endif | 1604 | #endif |
1593 | } | 1605 | } |
1594 | 1606 | ||
1595 | #include "setup_arch_post.h" | 1607 | #include "setup_arch_post.h" |
1596 | /* | 1608 | /* |
1597 | * Local Variables: | 1609 | * Local Variables: |
1598 | * mode:c | 1610 | * mode:c |
1599 | * c-file-style:"k&r" | 1611 | * c-file-style:"k&r" |
1600 | * c-basic-offset:8 | 1612 | * c-basic-offset:8 |
1601 | * End: | 1613 | * End: |
1602 | */ | 1614 | */ |
1603 | 1615 |
include/linux/bootmem.h
1 | /* | 1 | /* |
2 | * Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 | 2 | * Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 |
3 | */ | 3 | */ |
4 | #ifndef _LINUX_BOOTMEM_H | 4 | #ifndef _LINUX_BOOTMEM_H |
5 | #define _LINUX_BOOTMEM_H | 5 | #define _LINUX_BOOTMEM_H |
6 | 6 | ||
7 | #include <asm/pgtable.h> | 7 | #include <asm/pgtable.h> |
8 | #include <asm/dma.h> | 8 | #include <asm/dma.h> |
9 | #include <linux/cache.h> | 9 | #include <linux/cache.h> |
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/mmzone.h> | 11 | #include <linux/mmzone.h> |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * simple boot-time physical memory area allocator. | 14 | * simple boot-time physical memory area allocator. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | extern unsigned long max_low_pfn; | 17 | extern unsigned long max_low_pfn; |
18 | extern unsigned long min_low_pfn; | 18 | extern unsigned long min_low_pfn; |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * highest page | 21 | * highest page |
22 | */ | 22 | */ |
23 | extern unsigned long max_pfn; | 23 | extern unsigned long max_pfn; |
24 | 24 | ||
25 | #ifdef CONFIG_CRASH_DUMP | ||
26 | extern unsigned long saved_max_pfn; | ||
27 | #endif | ||
28 | |||
25 | /* | 29 | /* |
26 | * node_bootmem_map is a map pointer - the bits represent all physical | 30 | * node_bootmem_map is a map pointer - the bits represent all physical |
27 | * memory pages (including holes) on the node. | 31 | * memory pages (including holes) on the node. |
28 | */ | 32 | */ |
29 | typedef struct bootmem_data { | 33 | typedef struct bootmem_data { |
30 | unsigned long node_boot_start; | 34 | unsigned long node_boot_start; |
31 | unsigned long node_low_pfn; | 35 | unsigned long node_low_pfn; |
32 | void *node_bootmem_map; | 36 | void *node_bootmem_map; |
33 | unsigned long last_offset; | 37 | unsigned long last_offset; |
34 | unsigned long last_pos; | 38 | unsigned long last_pos; |
35 | unsigned long last_success; /* Previous allocation point. To speed | 39 | unsigned long last_success; /* Previous allocation point. To speed |
36 | * up searching */ | 40 | * up searching */ |
37 | } bootmem_data_t; | 41 | } bootmem_data_t; |
38 | 42 | ||
39 | extern unsigned long __init bootmem_bootmap_pages (unsigned long); | 43 | extern unsigned long __init bootmem_bootmap_pages (unsigned long); |
40 | extern unsigned long __init init_bootmem (unsigned long addr, unsigned long memend); | 44 | extern unsigned long __init init_bootmem (unsigned long addr, unsigned long memend); |
41 | extern void __init free_bootmem (unsigned long addr, unsigned long size); | 45 | extern void __init free_bootmem (unsigned long addr, unsigned long size); |
42 | extern void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal); | 46 | extern void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal); |
43 | #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE | 47 | #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE |
44 | extern void __init reserve_bootmem (unsigned long addr, unsigned long size); | 48 | extern void __init reserve_bootmem (unsigned long addr, unsigned long size); |
45 | #define alloc_bootmem(x) \ | 49 | #define alloc_bootmem(x) \ |
46 | __alloc_bootmem((x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)) | 50 | __alloc_bootmem((x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)) |
47 | #define alloc_bootmem_low(x) \ | 51 | #define alloc_bootmem_low(x) \ |
48 | __alloc_bootmem((x), SMP_CACHE_BYTES, 0) | 52 | __alloc_bootmem((x), SMP_CACHE_BYTES, 0) |
49 | #define alloc_bootmem_pages(x) \ | 53 | #define alloc_bootmem_pages(x) \ |
50 | __alloc_bootmem((x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS)) | 54 | __alloc_bootmem((x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS)) |
51 | #define alloc_bootmem_low_pages(x) \ | 55 | #define alloc_bootmem_low_pages(x) \ |
52 | __alloc_bootmem((x), PAGE_SIZE, 0) | 56 | __alloc_bootmem((x), PAGE_SIZE, 0) |
53 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ | 57 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ |
54 | extern unsigned long __init free_all_bootmem (void); | 58 | extern unsigned long __init free_all_bootmem (void); |
55 | 59 | ||
56 | extern unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn); | 60 | extern unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn); |
57 | extern void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size); | 61 | extern void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size); |
58 | extern void __init free_bootmem_node (pg_data_t *pgdat, unsigned long addr, unsigned long size); | 62 | extern void __init free_bootmem_node (pg_data_t *pgdat, unsigned long addr, unsigned long size); |
59 | extern unsigned long __init free_all_bootmem_node (pg_data_t *pgdat); | 63 | extern unsigned long __init free_all_bootmem_node (pg_data_t *pgdat); |
60 | extern void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal); | 64 | extern void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal); |
61 | #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE | 65 | #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE |
62 | #define alloc_bootmem_node(pgdat, x) \ | 66 | #define alloc_bootmem_node(pgdat, x) \ |
63 | __alloc_bootmem_node((pgdat), (x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)) | 67 | __alloc_bootmem_node((pgdat), (x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)) |
64 | #define alloc_bootmem_pages_node(pgdat, x) \ | 68 | #define alloc_bootmem_pages_node(pgdat, x) \ |
65 | __alloc_bootmem_node((pgdat), (x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS)) | 69 | __alloc_bootmem_node((pgdat), (x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS)) |
66 | #define alloc_bootmem_low_pages_node(pgdat, x) \ | 70 | #define alloc_bootmem_low_pages_node(pgdat, x) \ |
67 | __alloc_bootmem_node((pgdat), (x), PAGE_SIZE, 0) | 71 | __alloc_bootmem_node((pgdat), (x), PAGE_SIZE, 0) |
68 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ | 72 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ |
69 | 73 | ||
70 | #ifdef CONFIG_HAVE_ARCH_ALLOC_REMAP | 74 | #ifdef CONFIG_HAVE_ARCH_ALLOC_REMAP |
71 | extern void *alloc_remap(int nid, unsigned long size); | 75 | extern void *alloc_remap(int nid, unsigned long size); |
72 | #else | 76 | #else |
73 | static inline void *alloc_remap(int nid, unsigned long size) | 77 | static inline void *alloc_remap(int nid, unsigned long size) |
74 | { | 78 | { |
75 | return NULL; | 79 | return NULL; |
76 | } | 80 | } |
77 | #endif | 81 | #endif |
78 | 82 | ||
79 | extern unsigned long __initdata nr_kernel_pages; | 83 | extern unsigned long __initdata nr_kernel_pages; |
80 | extern unsigned long __initdata nr_all_pages; | 84 | extern unsigned long __initdata nr_all_pages; |
81 | 85 | ||
82 | extern void *__init alloc_large_system_hash(const char *tablename, | 86 | extern void *__init alloc_large_system_hash(const char *tablename, |
83 | unsigned long bucketsize, | 87 | unsigned long bucketsize, |
84 | unsigned long numentries, | 88 | unsigned long numentries, |
85 | int scale, | 89 | int scale, |
86 | int flags, | 90 | int flags, |
87 | unsigned int *_hash_shift, | 91 | unsigned int *_hash_shift, |
88 | unsigned int *_hash_mask, | 92 | unsigned int *_hash_mask, |
89 | unsigned long limit); | 93 | unsigned long limit); |
90 | 94 | ||
91 | #define HASH_HIGHMEM 0x00000001 /* Consider highmem? */ | 95 | #define HASH_HIGHMEM 0x00000001 /* Consider highmem? */ |
92 | #define HASH_EARLY 0x00000002 /* Allocating during early boot? */ | 96 | #define HASH_EARLY 0x00000002 /* Allocating during early boot? */ |
93 | 97 | ||
94 | /* Only NUMA needs hash distribution. | 98 | /* Only NUMA needs hash distribution. |
95 | * IA64 is known to have sufficient vmalloc space. | 99 | * IA64 is known to have sufficient vmalloc space. |
96 | */ | 100 | */ |
97 | #if defined(CONFIG_NUMA) && defined(CONFIG_IA64) | 101 | #if defined(CONFIG_NUMA) && defined(CONFIG_IA64) |
98 | #define HASHDIST_DEFAULT 1 | 102 | #define HASHDIST_DEFAULT 1 |
99 | #else | 103 | #else |
100 | #define HASHDIST_DEFAULT 0 | 104 | #define HASHDIST_DEFAULT 0 |
101 | #endif | 105 | #endif |
102 | extern int __initdata hashdist; /* Distribute hashes across NUMA nodes? */ | 106 | extern int __initdata hashdist; /* Distribute hashes across NUMA nodes? */ |
103 | 107 | ||
104 | 108 | ||
105 | #endif /* _LINUX_BOOTMEM_H */ | 109 | #endif /* _LINUX_BOOTMEM_H */ |
106 | 110 |
mm/bootmem.c
1 | /* | 1 | /* |
2 | * linux/mm/bootmem.c | 2 | * linux/mm/bootmem.c |
3 | * | 3 | * |
4 | * Copyright (C) 1999 Ingo Molnar | 4 | * Copyright (C) 1999 Ingo Molnar |
5 | * Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 | 5 | * Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 |
6 | * | 6 | * |
7 | * simple boot-time physical memory area allocator and | 7 | * simple boot-time physical memory area allocator and |
8 | * free memory collector. It's used to deal with reserved | 8 | * free memory collector. It's used to deal with reserved |
9 | * system memory and memory holes as well. | 9 | * system memory and memory holes as well. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
13 | #include <linux/kernel_stat.h> | 13 | #include <linux/kernel_stat.h> |
14 | #include <linux/swap.h> | 14 | #include <linux/swap.h> |
15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/bootmem.h> | 17 | #include <linux/bootmem.h> |
18 | #include <linux/mmzone.h> | 18 | #include <linux/mmzone.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <asm/dma.h> | 20 | #include <asm/dma.h> |
21 | #include <asm/io.h> | 21 | #include <asm/io.h> |
22 | #include "internal.h" | 22 | #include "internal.h" |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Access to this subsystem has to be serialized externally. (this is | 25 | * Access to this subsystem has to be serialized externally. (this is |
26 | * true for the boot process anyway) | 26 | * true for the boot process anyway) |
27 | */ | 27 | */ |
28 | unsigned long max_low_pfn; | 28 | unsigned long max_low_pfn; |
29 | unsigned long min_low_pfn; | 29 | unsigned long min_low_pfn; |
30 | unsigned long max_pfn; | 30 | unsigned long max_pfn; |
31 | 31 | ||
32 | EXPORT_SYMBOL(max_pfn); /* This is exported so | 32 | EXPORT_SYMBOL(max_pfn); /* This is exported so |
33 | * dma_get_required_mask(), which uses | 33 | * dma_get_required_mask(), which uses |
34 | * it, can be an inline function */ | 34 | * it, can be an inline function */ |
35 | 35 | ||
36 | #ifdef CONFIG_CRASH_DUMP | ||
37 | /* | ||
38 | * If we have booted due to a crash, max_pfn will be a very low value. We need | ||
39 | * to know the amount of memory that the previous kernel used. | ||
40 | */ | ||
41 | unsigned long saved_max_pfn; | ||
42 | #endif | ||
43 | |||
36 | /* return the number of _pages_ that will be allocated for the boot bitmap */ | 44 | /* return the number of _pages_ that will be allocated for the boot bitmap */ |
37 | unsigned long __init bootmem_bootmap_pages (unsigned long pages) | 45 | unsigned long __init bootmem_bootmap_pages (unsigned long pages) |
38 | { | 46 | { |
39 | unsigned long mapsize; | 47 | unsigned long mapsize; |
40 | 48 | ||
41 | mapsize = (pages+7)/8; | 49 | mapsize = (pages+7)/8; |
42 | mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK; | 50 | mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK; |
43 | mapsize >>= PAGE_SHIFT; | 51 | mapsize >>= PAGE_SHIFT; |
44 | 52 | ||
45 | return mapsize; | 53 | return mapsize; |
46 | } | 54 | } |
47 | 55 | ||
48 | /* | 56 | /* |
49 | * Called once to set up the allocator itself. | 57 | * Called once to set up the allocator itself. |
50 | */ | 58 | */ |
51 | static unsigned long __init init_bootmem_core (pg_data_t *pgdat, | 59 | static unsigned long __init init_bootmem_core (pg_data_t *pgdat, |
52 | unsigned long mapstart, unsigned long start, unsigned long end) | 60 | unsigned long mapstart, unsigned long start, unsigned long end) |
53 | { | 61 | { |
54 | bootmem_data_t *bdata = pgdat->bdata; | 62 | bootmem_data_t *bdata = pgdat->bdata; |
55 | unsigned long mapsize = ((end - start)+7)/8; | 63 | unsigned long mapsize = ((end - start)+7)/8; |
56 | 64 | ||
57 | pgdat->pgdat_next = pgdat_list; | 65 | pgdat->pgdat_next = pgdat_list; |
58 | pgdat_list = pgdat; | 66 | pgdat_list = pgdat; |
59 | 67 | ||
60 | mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL); | 68 | mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL); |
61 | bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); | 69 | bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); |
62 | bdata->node_boot_start = (start << PAGE_SHIFT); | 70 | bdata->node_boot_start = (start << PAGE_SHIFT); |
63 | bdata->node_low_pfn = end; | 71 | bdata->node_low_pfn = end; |
64 | 72 | ||
65 | /* | 73 | /* |
66 | * Initially all pages are reserved - setup_arch() has to | 74 | * Initially all pages are reserved - setup_arch() has to |
67 | * register free RAM areas explicitly. | 75 | * register free RAM areas explicitly. |
68 | */ | 76 | */ |
69 | memset(bdata->node_bootmem_map, 0xff, mapsize); | 77 | memset(bdata->node_bootmem_map, 0xff, mapsize); |
70 | 78 | ||
71 | return mapsize; | 79 | return mapsize; |
72 | } | 80 | } |
73 | 81 | ||
74 | /* | 82 | /* |
75 | * Marks a particular physical memory range as unallocatable. Usable RAM | 83 | * Marks a particular physical memory range as unallocatable. Usable RAM |
76 | * might be used for boot-time allocations - or it might get added | 84 | * might be used for boot-time allocations - or it might get added |
77 | * to the free page pool later on. | 85 | * to the free page pool later on. |
78 | */ | 86 | */ |
79 | static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size) | 87 | static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size) |
80 | { | 88 | { |
81 | unsigned long i; | 89 | unsigned long i; |
82 | /* | 90 | /* |
83 | * round up, partially reserved pages are considered | 91 | * round up, partially reserved pages are considered |
84 | * fully reserved. | 92 | * fully reserved. |
85 | */ | 93 | */ |
86 | unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE; | 94 | unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE; |
87 | unsigned long eidx = (addr + size - bdata->node_boot_start + | 95 | unsigned long eidx = (addr + size - bdata->node_boot_start + |
88 | PAGE_SIZE-1)/PAGE_SIZE; | 96 | PAGE_SIZE-1)/PAGE_SIZE; |
89 | unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE; | 97 | unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE; |
90 | 98 | ||
91 | BUG_ON(!size); | 99 | BUG_ON(!size); |
92 | BUG_ON(sidx >= eidx); | 100 | BUG_ON(sidx >= eidx); |
93 | BUG_ON((addr >> PAGE_SHIFT) >= bdata->node_low_pfn); | 101 | BUG_ON((addr >> PAGE_SHIFT) >= bdata->node_low_pfn); |
94 | BUG_ON(end > bdata->node_low_pfn); | 102 | BUG_ON(end > bdata->node_low_pfn); |
95 | 103 | ||
96 | for (i = sidx; i < eidx; i++) | 104 | for (i = sidx; i < eidx; i++) |
97 | if (test_and_set_bit(i, bdata->node_bootmem_map)) { | 105 | if (test_and_set_bit(i, bdata->node_bootmem_map)) { |
98 | #ifdef CONFIG_DEBUG_BOOTMEM | 106 | #ifdef CONFIG_DEBUG_BOOTMEM |
99 | printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE); | 107 | printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE); |
100 | #endif | 108 | #endif |
101 | } | 109 | } |
102 | } | 110 | } |
103 | 111 | ||
104 | static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size) | 112 | static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size) |
105 | { | 113 | { |
106 | unsigned long i; | 114 | unsigned long i; |
107 | unsigned long start; | 115 | unsigned long start; |
108 | /* | 116 | /* |
109 | * round down end of usable mem, partially free pages are | 117 | * round down end of usable mem, partially free pages are |
110 | * considered reserved. | 118 | * considered reserved. |
111 | */ | 119 | */ |
112 | unsigned long sidx; | 120 | unsigned long sidx; |
113 | unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE; | 121 | unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE; |
114 | unsigned long end = (addr + size)/PAGE_SIZE; | 122 | unsigned long end = (addr + size)/PAGE_SIZE; |
115 | 123 | ||
116 | BUG_ON(!size); | 124 | BUG_ON(!size); |
117 | BUG_ON(end > bdata->node_low_pfn); | 125 | BUG_ON(end > bdata->node_low_pfn); |
118 | 126 | ||
119 | if (addr < bdata->last_success) | 127 | if (addr < bdata->last_success) |
120 | bdata->last_success = addr; | 128 | bdata->last_success = addr; |
121 | 129 | ||
122 | /* | 130 | /* |
123 | * Round up the beginning of the address. | 131 | * Round up the beginning of the address. |
124 | */ | 132 | */ |
125 | start = (addr + PAGE_SIZE-1) / PAGE_SIZE; | 133 | start = (addr + PAGE_SIZE-1) / PAGE_SIZE; |
126 | sidx = start - (bdata->node_boot_start/PAGE_SIZE); | 134 | sidx = start - (bdata->node_boot_start/PAGE_SIZE); |
127 | 135 | ||
128 | for (i = sidx; i < eidx; i++) { | 136 | for (i = sidx; i < eidx; i++) { |
129 | if (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map))) | 137 | if (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map))) |
130 | BUG(); | 138 | BUG(); |
131 | } | 139 | } |
132 | } | 140 | } |
133 | 141 | ||
134 | /* | 142 | /* |
135 | * We 'merge' subsequent allocations to save space. We might 'lose' | 143 | * We 'merge' subsequent allocations to save space. We might 'lose' |
136 | * some fraction of a page if allocations cannot be satisfied due to | 144 | * some fraction of a page if allocations cannot be satisfied due to |
137 | * size constraints on boxes where there is physical RAM space | 145 | * size constraints on boxes where there is physical RAM space |
138 | * fragmentation - in these cases (mostly large memory boxes) this | 146 | * fragmentation - in these cases (mostly large memory boxes) this |
139 | * is not a problem. | 147 | * is not a problem. |
140 | * | 148 | * |
141 | * On low memory boxes we get it right in 100% of the cases. | 149 | * On low memory boxes we get it right in 100% of the cases. |
142 | * | 150 | * |
143 | * alignment has to be a power of 2 value. | 151 | * alignment has to be a power of 2 value. |
144 | * | 152 | * |
145 | * NOTE: This function is _not_ reentrant. | 153 | * NOTE: This function is _not_ reentrant. |
146 | */ | 154 | */ |
147 | static void * __init | 155 | static void * __init |
148 | __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, | 156 | __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, |
149 | unsigned long align, unsigned long goal) | 157 | unsigned long align, unsigned long goal) |
150 | { | 158 | { |
151 | unsigned long offset, remaining_size, areasize, preferred; | 159 | unsigned long offset, remaining_size, areasize, preferred; |
152 | unsigned long i, start = 0, incr, eidx; | 160 | unsigned long i, start = 0, incr, eidx; |
153 | void *ret; | 161 | void *ret; |
154 | 162 | ||
155 | if(!size) { | 163 | if(!size) { |
156 | printk("__alloc_bootmem_core(): zero-sized request\n"); | 164 | printk("__alloc_bootmem_core(): zero-sized request\n"); |
157 | BUG(); | 165 | BUG(); |
158 | } | 166 | } |
159 | BUG_ON(align & (align-1)); | 167 | BUG_ON(align & (align-1)); |
160 | 168 | ||
161 | eidx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); | 169 | eidx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); |
162 | offset = 0; | 170 | offset = 0; |
163 | if (align && | 171 | if (align && |
164 | (bdata->node_boot_start & (align - 1UL)) != 0) | 172 | (bdata->node_boot_start & (align - 1UL)) != 0) |
165 | offset = (align - (bdata->node_boot_start & (align - 1UL))); | 173 | offset = (align - (bdata->node_boot_start & (align - 1UL))); |
166 | offset >>= PAGE_SHIFT; | 174 | offset >>= PAGE_SHIFT; |
167 | 175 | ||
168 | /* | 176 | /* |
169 | * We try to allocate bootmem pages above 'goal' | 177 | * We try to allocate bootmem pages above 'goal' |
170 | * first, then we try to allocate lower pages. | 178 | * first, then we try to allocate lower pages. |
171 | */ | 179 | */ |
172 | if (goal && (goal >= bdata->node_boot_start) && | 180 | if (goal && (goal >= bdata->node_boot_start) && |
173 | ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) { | 181 | ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) { |
174 | preferred = goal - bdata->node_boot_start; | 182 | preferred = goal - bdata->node_boot_start; |
175 | 183 | ||
176 | if (bdata->last_success >= preferred) | 184 | if (bdata->last_success >= preferred) |
177 | preferred = bdata->last_success; | 185 | preferred = bdata->last_success; |
178 | } else | 186 | } else |
179 | preferred = 0; | 187 | preferred = 0; |
180 | 188 | ||
181 | preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT; | 189 | preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT; |
182 | preferred += offset; | 190 | preferred += offset; |
183 | areasize = (size+PAGE_SIZE-1)/PAGE_SIZE; | 191 | areasize = (size+PAGE_SIZE-1)/PAGE_SIZE; |
184 | incr = align >> PAGE_SHIFT ? : 1; | 192 | incr = align >> PAGE_SHIFT ? : 1; |
185 | 193 | ||
186 | restart_scan: | 194 | restart_scan: |
187 | for (i = preferred; i < eidx; i += incr) { | 195 | for (i = preferred; i < eidx; i += incr) { |
188 | unsigned long j; | 196 | unsigned long j; |
189 | i = find_next_zero_bit(bdata->node_bootmem_map, eidx, i); | 197 | i = find_next_zero_bit(bdata->node_bootmem_map, eidx, i); |
190 | i = ALIGN(i, incr); | 198 | i = ALIGN(i, incr); |
191 | if (test_bit(i, bdata->node_bootmem_map)) | 199 | if (test_bit(i, bdata->node_bootmem_map)) |
192 | continue; | 200 | continue; |
193 | for (j = i + 1; j < i + areasize; ++j) { | 201 | for (j = i + 1; j < i + areasize; ++j) { |
194 | if (j >= eidx) | 202 | if (j >= eidx) |
195 | goto fail_block; | 203 | goto fail_block; |
196 | if (test_bit (j, bdata->node_bootmem_map)) | 204 | if (test_bit (j, bdata->node_bootmem_map)) |
197 | goto fail_block; | 205 | goto fail_block; |
198 | } | 206 | } |
199 | start = i; | 207 | start = i; |
200 | goto found; | 208 | goto found; |
201 | fail_block: | 209 | fail_block: |
202 | i = ALIGN(j, incr); | 210 | i = ALIGN(j, incr); |
203 | } | 211 | } |
204 | 212 | ||
205 | if (preferred > offset) { | 213 | if (preferred > offset) { |
206 | preferred = offset; | 214 | preferred = offset; |
207 | goto restart_scan; | 215 | goto restart_scan; |
208 | } | 216 | } |
209 | return NULL; | 217 | return NULL; |
210 | 218 | ||
211 | found: | 219 | found: |
212 | bdata->last_success = start << PAGE_SHIFT; | 220 | bdata->last_success = start << PAGE_SHIFT; |
213 | BUG_ON(start >= eidx); | 221 | BUG_ON(start >= eidx); |
214 | 222 | ||
215 | /* | 223 | /* |
216 | * Is the next page of the previous allocation-end the start | 224 | * Is the next page of the previous allocation-end the start |
217 | * of this allocation's buffer? If yes then we can 'merge' | 225 | * of this allocation's buffer? If yes then we can 'merge' |
218 | * the previous partial page with this allocation. | 226 | * the previous partial page with this allocation. |
219 | */ | 227 | */ |
220 | if (align < PAGE_SIZE && | 228 | if (align < PAGE_SIZE && |
221 | bdata->last_offset && bdata->last_pos+1 == start) { | 229 | bdata->last_offset && bdata->last_pos+1 == start) { |
222 | offset = (bdata->last_offset+align-1) & ~(align-1); | 230 | offset = (bdata->last_offset+align-1) & ~(align-1); |
223 | BUG_ON(offset > PAGE_SIZE); | 231 | BUG_ON(offset > PAGE_SIZE); |
224 | remaining_size = PAGE_SIZE-offset; | 232 | remaining_size = PAGE_SIZE-offset; |
225 | if (size < remaining_size) { | 233 | if (size < remaining_size) { |
226 | areasize = 0; | 234 | areasize = 0; |
227 | /* last_pos unchanged */ | 235 | /* last_pos unchanged */ |
228 | bdata->last_offset = offset+size; | 236 | bdata->last_offset = offset+size; |
229 | ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset + | 237 | ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset + |
230 | bdata->node_boot_start); | 238 | bdata->node_boot_start); |
231 | } else { | 239 | } else { |
232 | remaining_size = size - remaining_size; | 240 | remaining_size = size - remaining_size; |
233 | areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE; | 241 | areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE; |
234 | ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset + | 242 | ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset + |
235 | bdata->node_boot_start); | 243 | bdata->node_boot_start); |
236 | bdata->last_pos = start+areasize-1; | 244 | bdata->last_pos = start+areasize-1; |
237 | bdata->last_offset = remaining_size; | 245 | bdata->last_offset = remaining_size; |
238 | } | 246 | } |
239 | bdata->last_offset &= ~PAGE_MASK; | 247 | bdata->last_offset &= ~PAGE_MASK; |
240 | } else { | 248 | } else { |
241 | bdata->last_pos = start + areasize - 1; | 249 | bdata->last_pos = start + areasize - 1; |
242 | bdata->last_offset = size & ~PAGE_MASK; | 250 | bdata->last_offset = size & ~PAGE_MASK; |
243 | ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start); | 251 | ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start); |
244 | } | 252 | } |
245 | 253 | ||
246 | /* | 254 | /* |
247 | * Reserve the area now: | 255 | * Reserve the area now: |
248 | */ | 256 | */ |
249 | for (i = start; i < start+areasize; i++) | 257 | for (i = start; i < start+areasize; i++) |
250 | if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map))) | 258 | if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map))) |
251 | BUG(); | 259 | BUG(); |
252 | memset(ret, 0, size); | 260 | memset(ret, 0, size); |
253 | return ret; | 261 | return ret; |
254 | } | 262 | } |
255 | 263 | ||
256 | static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat) | 264 | static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat) |
257 | { | 265 | { |
258 | struct page *page; | 266 | struct page *page; |
259 | unsigned long pfn; | 267 | unsigned long pfn; |
260 | bootmem_data_t *bdata = pgdat->bdata; | 268 | bootmem_data_t *bdata = pgdat->bdata; |
261 | unsigned long i, count, total = 0; | 269 | unsigned long i, count, total = 0; |
262 | unsigned long idx; | 270 | unsigned long idx; |
263 | unsigned long *map; | 271 | unsigned long *map; |
264 | int gofast = 0; | 272 | int gofast = 0; |
265 | 273 | ||
266 | BUG_ON(!bdata->node_bootmem_map); | 274 | BUG_ON(!bdata->node_bootmem_map); |
267 | 275 | ||
268 | count = 0; | 276 | count = 0; |
269 | /* first extant page of the node */ | 277 | /* first extant page of the node */ |
270 | pfn = bdata->node_boot_start >> PAGE_SHIFT; | 278 | pfn = bdata->node_boot_start >> PAGE_SHIFT; |
271 | idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); | 279 | idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); |
272 | map = bdata->node_bootmem_map; | 280 | map = bdata->node_bootmem_map; |
273 | /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */ | 281 | /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */ |
274 | if (bdata->node_boot_start == 0 || | 282 | if (bdata->node_boot_start == 0 || |
275 | ffs(bdata->node_boot_start) - PAGE_SHIFT > ffs(BITS_PER_LONG)) | 283 | ffs(bdata->node_boot_start) - PAGE_SHIFT > ffs(BITS_PER_LONG)) |
276 | gofast = 1; | 284 | gofast = 1; |
277 | for (i = 0; i < idx; ) { | 285 | for (i = 0; i < idx; ) { |
278 | unsigned long v = ~map[i / BITS_PER_LONG]; | 286 | unsigned long v = ~map[i / BITS_PER_LONG]; |
279 | 287 | ||
280 | if (gofast && v == ~0UL) { | 288 | if (gofast && v == ~0UL) { |
281 | int j, order; | 289 | int j, order; |
282 | 290 | ||
283 | page = pfn_to_page(pfn); | 291 | page = pfn_to_page(pfn); |
284 | count += BITS_PER_LONG; | 292 | count += BITS_PER_LONG; |
285 | __ClearPageReserved(page); | 293 | __ClearPageReserved(page); |
286 | order = ffs(BITS_PER_LONG) - 1; | 294 | order = ffs(BITS_PER_LONG) - 1; |
287 | set_page_refs(page, order); | 295 | set_page_refs(page, order); |
288 | for (j = 1; j < BITS_PER_LONG; j++) { | 296 | for (j = 1; j < BITS_PER_LONG; j++) { |
289 | if (j + 16 < BITS_PER_LONG) | 297 | if (j + 16 < BITS_PER_LONG) |
290 | prefetchw(page + j + 16); | 298 | prefetchw(page + j + 16); |
291 | __ClearPageReserved(page + j); | 299 | __ClearPageReserved(page + j); |
292 | } | 300 | } |
293 | __free_pages(page, order); | 301 | __free_pages(page, order); |
294 | i += BITS_PER_LONG; | 302 | i += BITS_PER_LONG; |
295 | page += BITS_PER_LONG; | 303 | page += BITS_PER_LONG; |
296 | } else if (v) { | 304 | } else if (v) { |
297 | unsigned long m; | 305 | unsigned long m; |
298 | 306 | ||
299 | page = pfn_to_page(pfn); | 307 | page = pfn_to_page(pfn); |
300 | for (m = 1; m && i < idx; m<<=1, page++, i++) { | 308 | for (m = 1; m && i < idx; m<<=1, page++, i++) { |
301 | if (v & m) { | 309 | if (v & m) { |
302 | count++; | 310 | count++; |
303 | __ClearPageReserved(page); | 311 | __ClearPageReserved(page); |
304 | set_page_refs(page, 0); | 312 | set_page_refs(page, 0); |
305 | __free_page(page); | 313 | __free_page(page); |
306 | } | 314 | } |
307 | } | 315 | } |
308 | } else { | 316 | } else { |
309 | i+=BITS_PER_LONG; | 317 | i+=BITS_PER_LONG; |
310 | } | 318 | } |
311 | pfn += BITS_PER_LONG; | 319 | pfn += BITS_PER_LONG; |
312 | } | 320 | } |
313 | total += count; | 321 | total += count; |
314 | 322 | ||
315 | /* | 323 | /* |
316 | * Now free the allocator bitmap itself, it's not | 324 | * Now free the allocator bitmap itself, it's not |
317 | * needed anymore: | 325 | * needed anymore: |
318 | */ | 326 | */ |
319 | page = virt_to_page(bdata->node_bootmem_map); | 327 | page = virt_to_page(bdata->node_bootmem_map); |
320 | count = 0; | 328 | count = 0; |
321 | for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) { | 329 | for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) { |
322 | count++; | 330 | count++; |
323 | __ClearPageReserved(page); | 331 | __ClearPageReserved(page); |
324 | set_page_count(page, 1); | 332 | set_page_count(page, 1); |
325 | __free_page(page); | 333 | __free_page(page); |
326 | } | 334 | } |
327 | total += count; | 335 | total += count; |
328 | bdata->node_bootmem_map = NULL; | 336 | bdata->node_bootmem_map = NULL; |
329 | 337 | ||
330 | return total; | 338 | return total; |
331 | } | 339 | } |
332 | 340 | ||
333 | unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn) | 341 | unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn) |
334 | { | 342 | { |
335 | return(init_bootmem_core(pgdat, freepfn, startpfn, endpfn)); | 343 | return(init_bootmem_core(pgdat, freepfn, startpfn, endpfn)); |
336 | } | 344 | } |
337 | 345 | ||
338 | void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size) | 346 | void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size) |
339 | { | 347 | { |
340 | reserve_bootmem_core(pgdat->bdata, physaddr, size); | 348 | reserve_bootmem_core(pgdat->bdata, physaddr, size); |
341 | } | 349 | } |
342 | 350 | ||
343 | void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size) | 351 | void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size) |
344 | { | 352 | { |
345 | free_bootmem_core(pgdat->bdata, physaddr, size); | 353 | free_bootmem_core(pgdat->bdata, physaddr, size); |
346 | } | 354 | } |
347 | 355 | ||
348 | unsigned long __init free_all_bootmem_node (pg_data_t *pgdat) | 356 | unsigned long __init free_all_bootmem_node (pg_data_t *pgdat) |
349 | { | 357 | { |
350 | return(free_all_bootmem_core(pgdat)); | 358 | return(free_all_bootmem_core(pgdat)); |
351 | } | 359 | } |
352 | 360 | ||
353 | unsigned long __init init_bootmem (unsigned long start, unsigned long pages) | 361 | unsigned long __init init_bootmem (unsigned long start, unsigned long pages) |
354 | { | 362 | { |
355 | max_low_pfn = pages; | 363 | max_low_pfn = pages; |
356 | min_low_pfn = start; | 364 | min_low_pfn = start; |
357 | return(init_bootmem_core(NODE_DATA(0), start, 0, pages)); | 365 | return(init_bootmem_core(NODE_DATA(0), start, 0, pages)); |
358 | } | 366 | } |
359 | 367 | ||
360 | #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE | 368 | #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE |
361 | void __init reserve_bootmem (unsigned long addr, unsigned long size) | 369 | void __init reserve_bootmem (unsigned long addr, unsigned long size) |
362 | { | 370 | { |
363 | reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size); | 371 | reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size); |
364 | } | 372 | } |
365 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ | 373 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ |
366 | 374 | ||
367 | void __init free_bootmem (unsigned long addr, unsigned long size) | 375 | void __init free_bootmem (unsigned long addr, unsigned long size) |
368 | { | 376 | { |
369 | free_bootmem_core(NODE_DATA(0)->bdata, addr, size); | 377 | free_bootmem_core(NODE_DATA(0)->bdata, addr, size); |
370 | } | 378 | } |
371 | 379 | ||
372 | unsigned long __init free_all_bootmem (void) | 380 | unsigned long __init free_all_bootmem (void) |
373 | { | 381 | { |
374 | return(free_all_bootmem_core(NODE_DATA(0))); | 382 | return(free_all_bootmem_core(NODE_DATA(0))); |
375 | } | 383 | } |
376 | 384 | ||
377 | void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal) | 385 | void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal) |
378 | { | 386 | { |
379 | pg_data_t *pgdat = pgdat_list; | 387 | pg_data_t *pgdat = pgdat_list; |
380 | void *ptr; | 388 | void *ptr; |
381 | 389 | ||
382 | for_each_pgdat(pgdat) | 390 | for_each_pgdat(pgdat) |
383 | if ((ptr = __alloc_bootmem_core(pgdat->bdata, size, | 391 | if ((ptr = __alloc_bootmem_core(pgdat->bdata, size, |
384 | align, goal))) | 392 | align, goal))) |
385 | return(ptr); | 393 | return(ptr); |
386 | 394 | ||
387 | /* | 395 | /* |
388 | * Whoops, we cannot satisfy the allocation request. | 396 | * Whoops, we cannot satisfy the allocation request. |
389 | */ | 397 | */ |
390 | printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); | 398 | printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); |
391 | panic("Out of memory"); | 399 | panic("Out of memory"); |
392 | return NULL; | 400 | return NULL; |
393 | } | 401 | } |
394 | 402 | ||
395 | void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) | 403 | void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) |
396 | { | 404 | { |
397 | void *ptr; | 405 | void *ptr; |
398 | 406 | ||
399 | ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal); | 407 | ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal); |
400 | if (ptr) | 408 | if (ptr) |
401 | return (ptr); | 409 | return (ptr); |
402 | 410 | ||
403 | return __alloc_bootmem(size, align, goal); | 411 | return __alloc_bootmem(size, align, goal); |
404 | } | 412 | } |
405 | 413 | ||
406 | 414 |