x86, boot, 64bit: Add support for loading ramdisk and bzImage above 4G
Subsystems (13)
cover x86, boot, 64bit: Add support for loading ramdisk and bzImage above 4G
Now we have limit kdump reseved under 896M, because kexec has the limitation. and also bzImage need to stay under 4g.
To make kexec/kdump could use range above 4g, we need to make bzImage and ramdisk could be loaded above 4g.
During booting bzImage will be unpacked on same postion and stay high.
The patches add fields in setup_header and boot_params to
1. get info about ramdisk position info above 4g from bootloader/kexec
2. get info about cmd_line_ptr info above 4g from bootloader/kexec
3. set xloadflags bit0 in header for bzImage and bootloader/kexec load could check that to decide if it could to put bzImage high.
4. use sentinel to make sure ext_* fields in boot_params could be used.
This patches is tested with kexec tools with local changes and they are sent to kexec list later.
could be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-x86-boot
and it is on top of linus's tree 2013-01-24
plus tip:x86/mm, tip:x86/mm2
Thanks a lot for Stefano Stabellini on testing the branch with all xen configurations. Thanks a lot for Konrad on testing with various iommu setups.
Thanks a lot for Borislav Petkov on reviewing and suggestion to make comments and changelog a lot more readable.
-v2: add ext_cmd_line_ptr support, and handle boot_param/cmd_line is above
4G case.
-v3: according to hpa, use xloadflags instead code32_start_offset.
0x200 will not be changed...
-v4: move ext_ramdisk_image/ext_ramdisk_size/ext_cmd_line_ptr to boot_params.
add handling cross GB boundary case.
-v5: put spare pages in BRK,so could avoid wasting about 4 pages.
add check for bit USE_EXT_BOOT_PARAMS in xloadflags
-v6: use sentinel according to HPA
add kdump load high support.
-v7: move sentinel from 0x1f0 to 0x1ef... according to HPA.
Use HPA's #PF handler version instead of ioremap.
-v7u1: update changelog and comments, so it could break KGDB... -v7u2: update changelog and comments, and clear more fields for sentinel.
Update swiotlb autoswitch off patch.
Fix crash with xen PV guest with 2G.
H. Peter Anvin (1):
x86, 64bit: early #PF handler set page table
Yinghai Lu (34):
x86, mm: Fix page table early allocation offset checking
x86: Handle multiple exactmaps and out of order exactmap x86, mm: Introduce memmap=reserveram
x86: Clean up e820 add kernel range
x86, 64bit, mm: Make pgd next calculation consistent with pud/pmd x86, realmode: Set real_mode permissions early
x86, 64bit, mm: Add generic kernel/ident mapping helper
x86, 64bit: Copy zero-page early
x86, 64bit, realmode: Use init_level4_pgt to set trapmoline_pgd directly x86, realmode: Separate real_mode reserve and setup
x86, 64bit: #PF handler set page to cover only 2M per #PF x86, 64bit: Don't set max_pfn_mapped wrong value early on native path
x86: Merge early_reserve_initrd for 32bit and 64bit
x86: Add get_ramdisk_image/size()
x86, boot: Add get_cmd_line_ptr()
x86, boot: Move checking of cmd_line_ptr out of common path x86, boot: Pass cmd_line_ptr with unsigned long instead
x86, boot: Move verify_cpu.S and no_longmode down
x86, boot: Move lldt/ltr out of 64bit code section
x86, kexec: Remove 1024G limitation for kexec buffer on 64bit x86, kexec: Set ident mapping for kernel that is above max_pfn x86, kexec: Replace ident_mapping_init and init_level4_page x86, kexec, 64bit: Only set ident mapping for ram.
x86, boot: Add fields to support load bzImage and ramdisk above 4G x86, boot: Update comments about entries for 64bit image x86, boot: Not need to check setup_header version for setup_data
memblock: Add memblock_mem_size()
x86, kdump: Remove crashkernel range find limit for 64bit
x86: Add Crash kernel low reservation
x86: Merge early kernel reserve for 32bit and 64bit
x86, 64bit, mm: Mark data/bss/brk to nx
x86, 64bit, mm: hibernate use generic mapping_init
mm: Add alloc_bootmem_low_pages_nopanic()
x86: Don't panic if can not alloc buffer for swiotlb
Documentation/kernel-parameters.txt | 3 + Documentation/x86/boot.txt | 53 +++++++- Documentation/x86/zero-page.txt | 4 + arch/mips/cavium-octeon/dma-octeon.c | 3 +- arch/x86/boot/boot.h | 18 ++- arch/x86/boot/cmdline.c | 12 +- arch/x86/boot/compressed/cmdline.c | 12 +- arch/x86/boot/compressed/head_64.S | 48 ++++--- arch/x86/boot/compressed/misc.c | 19 +++ arch/x86/boot/header.S | 12 +- arch/x86/boot/setup.ld | 7 ++ arch/x86/include/asm/init.h | 9 ++ arch/x86/include/asm/kexec.h | 6 +- arch/x86/include/asm/page.h | 4 + arch/x86/include/asm/pgtable_64_types.h | 4 + arch/x86/include/asm/processor.h | 1 + arch/x86/include/asm/realmode.h | 3 +- arch/x86/include/uapi/asm/bootparam.h | 24 +++- arch/x86/kernel/e820.c | 31 ++++- arch/x86/kernel/head32.c | 20 --- arch/x86/kernel/head64.c | 131 ++++++++++++++----- arch/x86/kernel/head_64.S | 210 +++++++++++++++++++------------ arch/x86/kernel/machine_kexec_64.c | 171 ++++++++----------------- arch/x86/kernel/setup.c | 164 +++++++++++++++++------- arch/x86/kernel/traps.c | 9 ++ arch/x86/mm/init.c | 20 ++- arch/x86/mm/init_64.c | 97 ++++++++++++-- arch/x86/power/hibernate_64.c | 66 ++++------ arch/x86/realmode/init.c | 45 ++++--- drivers/xen/swiotlb-xen.c | 4 +- include/linux/bootmem.h | 5 + include/linux/kexec.h | 3 + include/linux/memblock.h | 1 + include/linux/swiotlb.h | 2 +- kernel/kexec.c | 34 ++++- lib/swiotlb.c | 47 ++++--- mm/bootmem.c | 8 ++ mm/memblock.c | 17 +++ mm/nobootmem.c | 8 ++ 39 files changed, 887 insertions(+), 448 deletions(-)
Signature · 1 line
1.7.10.4
PATCH 1/35 x86, mm: Fix page table early allocation offset checking
During debugging loading kernel above 4G, found that one page is not used in pre-allocated BRK area for early page allocation. pgt_buf_top is address that can not be used, so should check if that new end is above that top, otherwise last page will not be used.
Fix that checking and also add print out for allocation from pre-allocated BRK area to catch possible bugs later.
But after we get back that page for pgt, it tiggers one bug in pgt allocation with xen: We need to avoid to use page as pgt to map range that is overlapping with that pgt page.
Add checking about overlapping, when it happens, use memblock allocation instead. That fixes crash on Xen PV guest with 2G that Stefan found.
--- arch/x86/mm/init.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
arch/x86/mm/init.c +12 -1
@@ -25,6 +25,8 @@ static unsigned long __initdata pgt_buf_top;static unsigned long min_pfn_mapped; +static bool __initdata can_use_brk_pgt = true; +/* * Pages returned are already directly mapped. *
@@ -47,7 +49,7 @@ __ref void *alloc_low_pages(unsigned int num) __GFP_ZERO, order); } -if ((pgt_buf_end + num) >= pgt_buf_top) { +if ((pgt_buf_end + num) > pgt_buf_top || !can_use_brk_pgt) {unsigned long ret;if (min_pfn_mapped >= max_pfn_mapped)panic ("alloc_low_page: ran out of memory" );
@@ -61,6 +63,8 @@ __ref void *alloc_low_pages(unsigned int num) }else { pfn = pgt_buf_end; pgt_buf_end += num; +printk (KERN_DEBUG "BRK [%#010lx, %#010lx] PGTABLE\n" , + pfn <<PAGE_SHIFT , (pgt_buf_end <<PAGE_SHIFT ) -1 ); }for (i =0 ; i < num; i++) {
@@ -370,8 +374,15 @@ static unsigned long __init init_range_memory_mapping(if (start >= end)continue ; +/* +* if it is overlapping with brk pgt, we need to +* alloc pgt buf from memblock instead. +*/ + can_use_brk_pgt =max (start, (u64 )pgt_buf_end<<PAGE_SHIFT ) >= +min (end, (u64 )pgt_buf_top<<PAGE_SHIFT );init_memory_mapping (start, end); mapped_ram_size += end - start; + can_use_brk_pgt = true; }return mapped_ram_size;
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, mm: Fix page table early allocation offset checking
Commit-ID: c9b3234a6abadaa12684083d39552939baaed1f4 Gitweb: http://git.kernel.org/tip/c9b3234a6abadaa12684083d39552939baaed1f4 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:42 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:12:23 -0800
x86, mm: Fix page table early allocation offset checking
During debugging loading kernel above 4G, found that one page is not used in pre-allocated BRK area for early page allocation. pgt_buf_top is address that can not be used, so should check if that new end is above that top, otherwise last page will not be used.
Fix that checking and also add print out for allocation from pre-allocated BRK area to catch possible bugs later.
But after we get back that page for pgt, it tiggers one bug in pgt allocation with xen: We need to avoid to use page as pgt to map range that is overlapping with that pgt page.
Add checking about overlapping, when it happens, use memblock allocation instead. That fixes crash on Xen PV guest with 2G that Stefan found.
--- arch/x86/mm/init.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
arch/x86/mm/init.c +12 -1
@@ -25,6 +25,8 @@ static unsigned long __initdata pgt_buf_top;static unsigned long min_pfn_mapped; +static bool __initdata can_use_brk_pgt = true; +/* * Pages returned are already directly mapped. *
@@ -47,7 +49,7 @@ __ref void *alloc_low_pages(unsigned int num) __GFP_ZERO, order); } -if ((pgt_buf_end + num) >= pgt_buf_top) { +if ((pgt_buf_end + num) > pgt_buf_top || !can_use_brk_pgt) {unsigned long ret;if (min_pfn_mapped >= max_pfn_mapped)panic ("alloc_low_page: ran out of memory" );
@@ -61,6 +63,8 @@ __ref void *alloc_low_pages(unsigned int num) }else { pfn = pgt_buf_end; pgt_buf_end += num; +printk (KERN_DEBUG "BRK [%#010lx, %#010lx] PGTABLE\n" , + pfn <<PAGE_SHIFT , (pgt_buf_end <<PAGE_SHIFT ) -1 ); }for (i =0 ; i < num; i++) {
@@ -370,8 +374,15 @@ static unsigned long __init init_range_memory_mapping(if (start >= end)continue ; +/* +* if it is overlapping with brk pgt, we need to +* alloc pgt buf from memblock instead. +*/ + can_use_brk_pgt =max (start, (u64 )pgt_buf_end<<PAGE_SHIFT ) >= +min (end, (u64 )pgt_buf_top<<PAGE_SHIFT );init_memory_mapping (start, end); mapped_ram_size += end - start; + can_use_brk_pgt = true; }return mapped_ram_size;
PATCH 2/35 x86: Handle multiple exactmaps and out of order exactmap
In reply to Yinghai LuCurrent code expect that we only have one exactmap and exactmap need to first one in memmap=.
memmap=exactmap will throw away all original entries, but also until then user defined (through other provided memmap= parameters) areas. That means all memmap= boot parameters passed before a memmap=exactmap parameter are not recognized.
Without this fix:
memmap=x@y memmap=exactmap memmap=i#k
only i#k would get recognized. This is wrong.
This fix will scan the boot_command_line to find if there is exactmap at first and only throw away all original e820 entries once, and then parse other memmap= option.
-v2: incorporate change log from Thomas Renninger.
--- arch/x86/kernel/e820.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/x86/kernel/e820.c +12 -0
@@ -835,6 +835,8 @@ static int __init parse_memopt(char *p) }early_param ("mem" , parse_memopt); +static bool __initdata exactmap_parsed; +static int __init parse_memmap_one (char *p) {char *oldp;
@@ -844,6 +846,10 @@ static int __init parse_memmap_one(char *p)return -EINVAL ;if (!strncmp (p,"exactmap" ,8 )) { +if (exactmap_parsed) +return 0 ; + + exactmap_parsed = true;#ifdef CONFIG_CRASH_DUMP /* * If we are doing a crash dump, we still need to know
@@ -879,6 +885,12 @@ static int __init parse_memmap_one(char *p) }static int __init parse_memmap_opt (char *str) { +char *p = boot_command_line; + + p =strstr (p,"exactmap" ); +if (p) +parse_memmap_one ("exactmap" ); +while (str) {char *k =strchr (str,',' );
Signature · 1 line
1.7.10.4
PATCH 3/35 x86, mm: Introduce memmap=reserveram
In reply to Yinghai Lukdump voided the whole original e820 map with exactmap and half way made it up via memmap= options passed via kdump boot params again.
But this is conceptionally wrong. The whole original memory ranges which are declared reserved, ACPI data/nvs or however are not usable must stay the same and get honored by the kdump kernel.
Therefore memmap=reserveram gets introduced.
kdump passes this one and only the usable e820 ranges are updated to reserved at first by kernel, then when kdump passes the usable ranges to use via memmap=x@y parameter(s), kernel will remove reserved range and add usable range accordingly.
This for example fixes mmconf (extended PCI config access) and possibly other kernel parts which rely on remapped memory to be in reserved or ACPI (data/nvs) declared e820 memory areas.
Changelog is from Thomas Renninger, and updated to reserveram
-v2: According to HPA, use reserveram instead of resetusablemap.
--- arch/x86/kernel/e820.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
arch/x86/kernel/e820.c +17 -2
@@ -836,6 +836,7 @@ static int __init parse_memopt(char *p)early_param ("mem" , parse_memopt);static bool __initdata exactmap_parsed; +static bool __initdata reserveram_parsed;static int __init parse_memmap_one (char *p) {
@@ -845,7 +846,7 @@ static int __init parse_memmap_one(char *p)if (!p)return -EINVAL ; -if (!strncmp (p,"exactmap" ,8 )) { +if (!strncmp (p,"exactmap" ,8 ) || !strncmp (p,"reserveram" ,10 )) {if (exactmap_parsed)return 0 ;
@@ -858,7 +859,12 @@ static int __init parse_memmap_one(char *p)*/ saved_max_pfn =e820_end_of_ram_pfn ();#endif - e820.nr_map =0 ; +if (!strncmp (p,"reserveram" ,10 )) { +e820_update_range (0 ,ULLONG_MAX ,E820_RAM , +E820_RESERVED ); + reserveram_parsed = true; + }else + e820.nr_map =0 ; userdef =1 ;return 0 ; }
@@ -871,6 +877,10 @@ static int __init parse_memmap_one(char *p) userdef =1 ;if (*p =='@' ) { start_at =memparse (p+1 , &p); +if (reserveram_parsed) { +/* Remove old reserved so new ram could take over. */ +e820_remove_range (start_at, mem_size,E820_RESERVED ,0 ); + }e820_add_region (start_at, mem_size,E820_RAM ); }else if (*p =='#' ) { start_at =memparse (p+1 , &p);
@@ -890,6 +900,11 @@ static int __init parse_memmap_opt(char *str) p =strstr (p,"exactmap" );if (p)parse_memmap_one ("exactmap" ); +else { + p =strstr (boot_command_line,"reserveram" ); +if (p) +parse_memmap_one ("reserveram" ); + }while (str) {char *k =strchr (str,',' );
Signature · 1 line
1.7.10.4
PATCH 4/35 x86: Clean up e820 add kernel range
In reply to Yinghai LuSeparate it out to another function instead.
Also add support for case when memmap=xxM$yyM is used without exactmap. Need to remove reserved range at first before we add E820_RAM range, otherwise added E820_RAM range will be ignored.
--- arch/x86/kernel/setup.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-)
arch/x86/kernel/setup.c +22 -14
@@ -702,6 +702,27 @@ static void __init trim_bios_range(void)sanitize_e820_map (e820.map,ARRAY_SIZE (e820.map), &e820.nr_map); } +/* called before trim_bios_range() to spare extra sanitize */ +static void __init e820_add_kernel_range (void ) +{ +u64 start =__pa_symbol (_text); +u64 size =__pa_symbol (_end) - start; + +/* +* Complain if .text .data and .bss are not marked as E820_RAM and +* attempt to fix it by adding the range. We may have a confused BIOS, +* or the user may have used memmap=exactmap or memmap=xxM$yyM to +* exclude kernel range. If we really are running on top non-RAM, +* we will crash later anyways. +*/ +if (e820_all_mapped (start, start + size,E820_RAM )) +return ; + +pr_warn (".text .data .bss are not marked as E820_RAM!\n" ); +e820_remove_range (start, size,E820_RAM ,0 ); +e820_add_region (start, size,E820_RAM ); +} +static int __init parse_reservelow (char *p) {unsigned long long size;
@@ -897,20 +918,7 @@ void __init setup_arch(char **cmdline_p)insert_resource (&iomem_resource, &data_resource);insert_resource (&iomem_resource, &bss_resource); -/* -* Complain if .text .data and .bss are not marked as E820_RAM and -* attempt to fix it by adding the range. We may have a confused BIOS, -* or the user may have incorrectly supplied it via memmap=exactmap. If -* we really are running on top non-RAM, we will crash later anyways. -*/ -if (!e820_all_mapped (code_resource.start,__pa (__brk_limit),E820_RAM )) { -pr_warn (".text .data .bss are not marked as E820_RAM!\n" ); - -e820_add_region (code_resource.start, -__pa (__brk_limit) - code_resource.start +1 , -E820_RAM ); - } - +e820_add_kernel_range ();trim_bios_range ();#ifdef CONFIG_X86_32 if (ppro_with_ram_bug ()) {
Signature · 1 line
1.7.10.4
Re: [PATCH 04/35] x86: Clean up e820 add kernel range
Quoted 8 lines · Yinghai Lu
Separate it out to another function instead.
Also add support for case when memmap=xxM$yyM is used without exactmap. Need to remove reserved range at first before we add
E820_RAMrange, otherwise addedE820_RAMrange will be ignored.Signed-off-by Yinghai Lu <[email protected]>Cc Jacob Shin <[email protected]>
Thanks,
Quoted 62 lines
--- arch/x86/kernel/setup.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-)arch/x86/kernel/setup.c +22
-14@@ -702,6 +702,27 @@ static void __init trim_bios_range(void)sanitize_e820_map (e820.map,ARRAY_SIZE (e820.map), &e820.nr_map); } +/* called before trim_bios_range() to spare extra sanitize */ +static void __init e820_add_kernel_range (void ) +{ +u64 start =__pa_symbol (_text); +u64 size =__pa_symbol (_end) - start; + +/* +* Complain if .text .data and .bss are not marked as E820_RAM and +* attempt to fix it by adding the range. We may have a confused BIOS, +* or the user may have used memmap=exactmap or memmap=xxM$yyM to +* exclude kernel range. If we really are running on top non-RAM, +* we will crash later anyways. +*/ +if (e820_all_mapped (start, start + size,E820_RAM )) +return ; + +pr_warn (".text .data .bss are not marked as E820_RAM!\n" ); +e820_remove_range (start, size,E820_RAM ,0 ); +e820_add_region (start, size,E820_RAM ); +} +static int __init parse_reservelow (char *p) {unsigned long long size;@@ -897,20 +918,7 @@ void __init setup_arch(char **cmdline_p)insert_resource (&iomem_resource, &data_resource);insert_resource (&iomem_resource, &bss_resource); -/* -* Complain if .text .data and .bss are not marked as E820_RAM and -* attempt to fix it by adding the range. We may have a confused BIOS, -* or the user may have incorrectly supplied it via memmap=exactmap. If -* we really are running on top non-RAM, we will crash later anyways. -*/ -if (!e820_all_mapped (code_resource.start,__pa (__brk_limit),E820_RAM )) { -pr_warn (".text .data .bss are not marked as E820_RAM!\n" ); - -e820_add_region (code_resource.start, -__pa (__brk_limit) - code_resource.start +1 , -E820_RAM ); - } - +e820_add_kernel_range ();trim_bios_range ();#ifdef CONFIG_X86_32 if (ppro_with_ram_bug ()) {Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86: Factor out e820_add_kernel_range()
In reply to Yinghai LuCommit-ID: b422a3091748c38b68052e8ba021652590b1f25c Gitweb: http://git.kernel.org/tip/b422a3091748c38b68052e8ba021652590b1f25c Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:45 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:12:24 -0800
x86: Factor out e820_add_kernel_range()
Separate out the reservation of the kernel static memory areas into a separate function.
Also add support for case when memmap=xxM$yyM is used without exactmap. Need to remove reserved range at first before we add E820_RAM range, otherwise added E820_RAM range will be ignored.
--- arch/x86/kernel/setup.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-)
arch/x86/kernel/setup.c +22 -14
@@ -702,6 +702,27 @@ static void __init trim_bios_range(void)sanitize_e820_map (e820.map,ARRAY_SIZE (e820.map), &e820.nr_map); } +/* called before trim_bios_range() to spare extra sanitize */ +static void __init e820_add_kernel_range (void ) +{ +u64 start =__pa_symbol (_text); +u64 size =__pa_symbol (_end) - start; + +/* +* Complain if .text .data and .bss are not marked as E820_RAM and +* attempt to fix it by adding the range. We may have a confused BIOS, +* or the user may have used memmap=exactmap or memmap=xxM$yyM to +* exclude kernel range. If we really are running on top non-RAM, +* we will crash later anyways. +*/ +if (e820_all_mapped (start, start + size,E820_RAM )) +return ; + +pr_warn (".text .data .bss are not marked as E820_RAM!\n" ); +e820_remove_range (start, size,E820_RAM ,0 ); +e820_add_region (start, size,E820_RAM ); +} +static int __init parse_reservelow (char *p) {unsigned long long size;
@@ -897,20 +918,7 @@ void __init setup_arch(char **cmdline_p)insert_resource (&iomem_resource, &data_resource);insert_resource (&iomem_resource, &bss_resource); -/* -* Complain if .text .data and .bss are not marked as E820_RAM and -* attempt to fix it by adding the range. We may have a confused BIOS, -* or the user may have incorrectly supplied it via memmap=exactmap. If -* we really are running on top non-RAM, we will crash later anyways. -*/ -if (!e820_all_mapped (code_resource.start,__pa (__brk_limit),E820_RAM )) { -pr_warn (".text .data .bss are not marked as E820_RAM!\n" ); - -e820_add_region (code_resource.start, -__pa (__brk_limit) - code_resource.start +1 , -E820_RAM ); - } - +e820_add_kernel_range ();trim_bios_range ();#ifdef CONFIG_X86_32 if (ppro_with_ram_bug ()) {
PATCH 5/35 x86, 64bit, mm: Make pgd next calculation consistent with pud/pmd
In reply to Yinghai LuJust like the way we calculate next for pud and pmd, aka round down and add size.
Also, do not do boundary-checking with 'next', and just pass 'end' down to phys_pud_init() instead. Because the loop in phys_pud_init() stops at PTRS_PER_PUD and thus can handle a possibly bigger 'end' properly.
--- arch/x86/mm/init_64.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/x86/mm/init_64.c +2 -4
@@ -530,9 +530,7 @@ kernel_physical_mapping_init(unsigned long start,pgd_t *pgd =pgd_offset_k (start);pud_t *pud; - next = (start +PGDIR_SIZE ) &PGDIR_MASK ; -if (next > end) - next = end; + next = (start &PGDIR_MASK ) +PGDIR_SIZE ;if (pgd_val (*pgd)) { pud = (pud_t *)pgd_page_vaddr (*pgd);
@@ -542,7 +540,7 @@ kernel_physical_mapping_init(unsigned long start, } pud =alloc_low_page (); - last_map_addr =phys_pud_init (pud,__pa (start),__pa (next), + last_map_addr =phys_pud_init (pud,__pa (start),__pa (end), page_size_mask);spin_lock (&init_mm.page_table_lock);
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, 64bit, mm: Make pgd next calculation consistent with pud/pmd
Commit-ID: c2bdee594ebcf4a531afe795baf18da509438392 Gitweb: http://git.kernel.org/tip/c2bdee594ebcf4a531afe795baf18da509438392 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:46 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:12:24 -0800
x86, 64bit, mm: Make pgd next calculation consistent with pud/pmd
Just like the way we calculate next for pud and pmd, aka round down and add size.
Also, do not do boundary-checking with 'next', and just pass 'end' down to phys_pud_init() instead. Because the loop in phys_pud_init() stops at PTRS_PER_PUD and thus can handle a possibly bigger 'end' properly.
--- arch/x86/mm/init_64.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/x86/mm/init_64.c +2 -4
@@ -530,9 +530,7 @@ kernel_physical_mapping_init(unsigned long start,pgd_t *pgd =pgd_offset_k (start);pud_t *pud; - next = (start +PGDIR_SIZE ) &PGDIR_MASK ; -if (next > end) - next = end; + next = (start &PGDIR_MASK ) +PGDIR_SIZE ;if (pgd_val (*pgd)) { pud = (pud_t *)pgd_page_vaddr (*pgd);
@@ -542,7 +540,7 @@ kernel_physical_mapping_init(unsigned long start, } pud =alloc_low_page (); - last_map_addr =phys_pud_init (pud,__pa (start),__pa (next), + last_map_addr =phys_pud_init (pud,__pa (start),__pa (end), page_size_mask);spin_lock (&init_mm.page_table_lock);
PATCH 6/35 x86, realmode: Set real_mode permissions early
In reply to Yinghai LuTrampoline code is executed by APs with kernel low mapping on 64bit. We need to set trampoline code to EXEC early before we boot APs.
Found the problem after switching to #PF handler set page table, and we do not set initial kernel low mapping with EXEC anymore in arch/x86/kernel/head_64.S.
Change to use early_initcall instead that will make sure trampoline will have EXEC set.
-v2: Merge two comments according to Borislav Petkov <[email protected]>
--- arch/x86/realmode/init.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
arch/x86/realmode/init.c +6 -5
@@ -84,10 +84,12 @@ void __init setup_real_mode(void) }/* -* set_real_mode_permissions() gets called very early, to guarantee the -* availability of low memory. This is before the proper kernel page +* setup_real_mode() gets called very early, to guarantee the +* availability of low memory. This is before the proper kernel page * tables are set up, so we cannot set page permissions in that -* function. Thus, we use an arch_initcall instead. +* function. Also trampoline code will be executed by APs so we +* need to mark it executable at do_pre_smp_initcalls() at least, +* thus run it as a early_initcall(). */ static int __init set_real_mode_permissions (void ) {
@@ -111,5 +113,4 @@ static int __init set_real_mode_permissions(void)return 0 ; } - -arch_initcall (set_real_mode_permissions); +early_initcall (set_real_mode_permissions);
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, realmode: Set real_mode permissions early
Commit-ID: 231b3642a3c73fb9f1221dcb96fe8c0fbb658dfd Gitweb: http://git.kernel.org/tip/231b3642a3c73fb9f1221dcb96fe8c0fbb658dfd Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:47 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:12:25 -0800
x86, realmode: Set real_mode permissions early
Trampoline code is executed by APs with kernel low mapping on 64bit. We need to set trampoline code to EXEC early before we boot APs.
Found the problem after switching to #PF handler set page table, and we do not set initial kernel low mapping with EXEC anymore in arch/x86/kernel/head_64.S.
Change to use early_initcall instead that will make sure trampoline will have EXEC set.
-v2: Merge two comments according to Borislav Petkov <[email protected]>
--- arch/x86/realmode/init.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
arch/x86/realmode/init.c +6 -5
@@ -84,10 +84,12 @@ void __init setup_real_mode(void) }/* -* set_real_mode_permissions() gets called very early, to guarantee the -* availability of low memory. This is before the proper kernel page +* setup_real_mode() gets called very early, to guarantee the +* availability of low memory. This is before the proper kernel page * tables are set up, so we cannot set page permissions in that -* function. Thus, we use an arch_initcall instead. +* function. Also trampoline code will be executed by APs so we +* need to mark it executable at do_pre_smp_initcalls() at least, +* thus run it as a early_initcall(). */ static int __init set_real_mode_permissions (void ) {
@@ -111,5 +113,4 @@ static int __init set_real_mode_permissions(void)return 0 ; } - -arch_initcall (set_real_mode_permissions); +early_initcall (set_real_mode_permissions);
PATCH 7/35 x86, 64bit, mm: Add generic kernel/ident mapping helper
In reply to Yinghai LuIt is simple version for kernel_physical_mapping_init. it will work to build one page table that will be used later.
Use mapping_info to control
1. alloc_pg_page method
2. if PMD is EXEC,
3. if pgd is with kernel low mapping or ident mapping.
Will use to replace some local versions in kexec, hibernation and etc.
--- arch/x86/include/asm/init.h | 9 ++++++ arch/x86/mm/init_64.c | 74 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+)
arch/x86/include/asm/init.h +9 -0
@@ -1,5 +1,14 @@#ifndef _ASM_X86_INIT_H#define _ASM_X86_INIT_H +struct x86_mapping_info { +void *(*alloc_pgt_page)(void *);/* allocate buf for page table */ +void *context;/* context for alloc_pgt_page */ +unsigned long pmd_flag;/* page flag for PMD entry */ +bool kernel_mapping;/* kernel mapping or ident mapping */ +}; + +int kernel_ident_mapping_init (struct x86_mapping_info *info,pgd_t *pgd_page, +unsigned long addr,unsigned long end);#endif /* _ASM_X86_INIT_H */
arch/x86/mm/init_64.c +74 -0
80 lines not on this page · raw message
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, 64bit, mm: Add generic kernel/ ident mapping helper
Commit-ID: aece27851d44bde62fc0587e06f5e8e27fd96e5f Gitweb: http://git.kernel.org/tip/aece27851d44bde62fc0587e06f5e8e27fd96e5f Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:48 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:12:25 -0800
x86, 64bit, mm: Add generic kernel/ident mapping helper
It is simple version for kernel_physical_mapping_init. it will work to build one page table that will be used later.
Use mapping_info to control
1. alloc_pg_page method
2. if PMD is EXEC,
3. if pgd is with kernel low mapping or ident mapping.
Will use to replace some local versions in kexec, hibernation and etc.
--- arch/x86/include/asm/init.h | 9 ++++++ arch/x86/mm/init_64.c | 74 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+)
arch/x86/include/asm/init.h +9 -0
@@ -1,5 +1,14 @@#ifndef _ASM_X86_INIT_H#define _ASM_X86_INIT_H +struct x86_mapping_info { +void *(*alloc_pgt_page)(void *);/* allocate buf for page table */ +void *context;/* context for alloc_pgt_page */ +unsigned long pmd_flag;/* page flag for PMD entry */ +bool kernel_mapping;/* kernel mapping or ident mapping */ +}; + +int kernel_ident_mapping_init (struct x86_mapping_info *info,pgd_t *pgd_page, +unsigned long addr,unsigned long end);#endif /* _ASM_X86_INIT_H */
arch/x86/mm/init_64.c +74 -0
80 lines not on this page · raw message
PATCH 8/35 x86, 64bit: Copy zero-page early
In reply to Yinghai Lureal mode data/boot_params aka zero-page could be above 4g. We will have #PF handler to set page table for not accessible ram early, but want to limit it before x86_64_start_reservations to limit the code change to native path only.
Also we will need the ramdisk info in zero-page to access the microcode blob in ramdisk in x86_64_start_kernel, so copy zero-page early makes it accessing ramdisk info simple.
--- arch/x86/kernel/head64.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/x86/kernel/head64.c +5 -1
@@ -87,6 +87,8 @@ void __init x86_64_start_kernel(char * real_mode_data) }load_idt ((const struct desc_ptr *)&idt_descr); +copy_bootdata (__va (real_mode_data)); +if (console_loglevel ==10 )early_printk ("Kernel alive\n" );
@@ -95,7 +97,9 @@ void __init x86_64_start_kernel(char * real_mode_data)void __init x86_64_start_reservations (char *real_mode_data) { -copy_bootdata (__va (real_mode_data)); +/* version is always not zero if it is copied */ +if (!boot_params.hdr.version) +copy_bootdata (__va (real_mode_data));memblock_reserve (__pa_symbol (_text), (unsigned long )__bss_stop - (unsigned long )_text);
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, 64bit: Copy struct boot_params early
Commit-ID: fa2bbce985ca97943305cdc81d9626e6810ed7f2 Gitweb: http://git.kernel.org/tip/fa2bbce985ca97943305cdc81d9626e6810ed7f2 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:49 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:12:26 -0800
x86, 64bit: Copy struct boot_params early
We want to support struct boot_params (formerly known as the zero-page, or real-mode data) above the 4 GiB mark. We will have #PF handler to set page table for not accessible ram early, but want to limit it before x86_64_start_reservations to limit the code change to native path only.
Also we will need the ramdisk info in struct boot_params to access the microcode blob in ramdisk in x86_64_start_kernel, so copy struct boot_params early makes it accessing ramdisk info simple.
--- arch/x86/kernel/head64.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/x86/kernel/head64.c +5 -1
@@ -89,6 +89,8 @@ void __init x86_64_start_kernel(char * real_mode_data) }load_idt ((const struct desc_ptr *)&idt_descr); +copy_bootdata (__va (real_mode_data)); +if (console_loglevel ==10 )early_printk ("Kernel alive\n" );
@@ -97,7 +99,9 @@ void __init x86_64_start_kernel(char * real_mode_data)void __init x86_64_start_reservations (char *real_mode_data) { -copy_bootdata (__va (real_mode_data)); +/* version is always not zero if it is copied */ +if (!boot_params.hdr.version) +copy_bootdata (__va (real_mode_data));memblock_reserve (__pa_symbol (&_text),__pa_symbol (&__bss_stop) -__pa_symbol (&_text));
PATCH 9/35 x86, 64bit, realmode: Use init_level4_pgt to set trapmoline_pgd directly
In reply to Yinghai Luwith #PF handler way to set early page table, level3_ident will go away with 64bit native path.
So just use entries in init_level4_pgt to set them in trampoline_pgd.
--- arch/x86/realmode/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/realmode/init.c +2 -2
@@ -78,8 +78,8 @@ void __init setup_real_mode(void) *trampoline_cr4_features =read_cr4 (); trampoline_pgd = (u64 *)__va (real_mode_header->trampoline_pgd); - trampoline_pgd[0 ] =__pa_symbol (level3_ident_pgt) + _KERNPG_TABLE; - trampoline_pgd[511 ] =__pa_symbol (level3_kernel_pgt) + _KERNPG_TABLE; + trampoline_pgd[0 ] = init_level4_pgt[pgd_index (__PAGE_OFFSET)].pgd; + trampoline_pgd[511 ] = init_level4_pgt[511 ].pgd;#endif }
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, 64bit, realmode: Use init_level4_pgt to set trampoline_pgd directly
Commit-ID: 9735e91e9c29c0d8fe432aef1152e43e50bdb316 Gitweb: http://git.kernel.org/tip/9735e91e9c29c0d8fe432aef1152e43e50bdb316 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:50 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:12:30 -0800
x86, 64bit, realmode: Use init_level4_pgt to set trampoline_pgd directly
with #PF handler way to set early page table, level3_ident will go away with 64bit native path.
So just use entries in init_level4_pgt to set them in trampoline_pgd.
--- arch/x86/realmode/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/realmode/init.c +2 -2
@@ -78,8 +78,8 @@ void __init setup_real_mode(void) *trampoline_cr4_features =read_cr4 (); trampoline_pgd = (u64 *)__va (real_mode_header->trampoline_pgd); - trampoline_pgd[0 ] =__pa (level3_ident_pgt) + _KERNPG_TABLE; - trampoline_pgd[511 ] =__pa (level3_kernel_pgt) + _KERNPG_TABLE; + trampoline_pgd[0 ] = init_level4_pgt[pgd_index (__PAGE_OFFSET)].pgd; + trampoline_pgd[511 ] = init_level4_pgt[511 ].pgd;#endif }
PATCH 10/35 x86, realmode: Separate real_mode reserve and setup
In reply to Yinghai LuAfter we switch to use #PF handler help to set page table, init_level4_pgt will only have entries set after init_mem_mapping().
We need to move copying init_level4_pgt to trampoline_pgd after that.
So split reserve and setup, and move the setup after init_mem_mapping()
--- arch/x86/include/asm/realmode.h | 3 ++- arch/x86/kernel/setup.c | 4 +++- arch/x86/realmode/init.c | 32 ++++++++++++++++++++------------ 3 files changed, 25 insertions(+), 14 deletions(-)
arch/x86/include/asm/realmode.h +2 -1
@@ -58,6 +58,7 @@ extern unsigned char boot_gdt[];extern unsigned char secondary_startup_64[];#endif -extern void __init setup_real_mode (void ); +void reserve_real_mode (void ); +void setup_real_mode (void );#endif /* _ARCH_X86_REALMODE_H */
arch/x86/kernel/setup.c +3 -1
@@ -999,12 +999,14 @@ void __init setup_arch(char **cmdline_p)printk (KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n" , (max_pfn_mapped<<PAGE_SHIFT ) -1 ); -setup_real_mode (); +reserve_real_mode ();trim_platform_memory_ranges ();init_mem_mapping (); +setup_real_mode (); + memblock.current_limit =get_max_mapped ();dma_contiguous_reserve (0 );
arch/x86/realmode/init.c +20 -12
@@ -8,9 +8,26 @@struct real_mode_header *real_mode_header;u32 *trampoline_cr4_features; -void __init setup_real_mode (void ) +void __init reserve_real_mode (void ) {phys_addr_t mem; +unsigned char *base; +size_t size =PAGE_ALIGN (real_mode_blob_end - real_mode_blob); + +/* Has to be under 1M so we can execute real-mode AP code. */ + mem =memblock_find_in_range (0 ,1 <<20 , size,PAGE_SIZE ); +if (!mem) +panic ("Cannot allocate trampoline\n" ); + + base =__va (mem); +memblock_reserve (mem, size); + real_mode_header = (struct real_mode_header *) base; +printk (KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n" , + base, (unsigned long long )mem, size); +} + +void __init setup_real_mode (void ) +{u16 real_mode_seg;u32 *rel;u32 count;
@@ -25,16 +42,7 @@ void __init setup_real_mode(void)u64 efer;#endif -/* Has to be in very low memory so we can execute real-mode AP code. */ - mem =memblock_find_in_range (0 ,1 <<20 , size,PAGE_SIZE ); -if (!mem) -panic ("Cannot allocate trampoline\n" ); - - base =__va (mem); -memblock_reserve (mem, size); - real_mode_header = (struct real_mode_header *) base; -printk (KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n" , - base, (unsigned long long )mem, size); + base = (unsigned char *)real_mode_header;memcpy (base, real_mode_blob, size);
@@ -84,7 +92,7 @@ void __init setup_real_mode(void) }/* -* setup_real_mode() gets called very early, to guarantee the +* reserve_real_mode() gets called very early, to guarantee the * availability of low memory. This is before the proper kernel page * tables are set up, so we cannot set page permissions in that * function. Also trampoline code will be executed by APs so we
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, realmode: Separate real_mode reserve and setup
Commit-ID: 4f7b92263ad68cdc72b11808320d9c881bfa857e Gitweb: http://git.kernel.org/tip/4f7b92263ad68cdc72b11808320d9c881bfa857e Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:51 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:13:24 -0800
x86, realmode: Separate real_mode reserve and setup
After we switch to use #PF handler help to set page table, init_level4_pgt will only have entries set after init_mem_mapping().
We need to move copying init_level4_pgt to trampoline_pgd after that.
So split reserve and setup, and move the setup after init_mem_mapping()
--- arch/x86/include/asm/realmode.h | 3 ++- arch/x86/kernel/setup.c | 4 +++- arch/x86/realmode/init.c | 32 ++++++++++++++++++++------------ 3 files changed, 25 insertions(+), 14 deletions(-)
arch/x86/include/asm/realmode.h +2 -1
@@ -58,6 +58,7 @@ extern unsigned char boot_gdt[];extern unsigned char secondary_startup_64[];#endif -extern void __init setup_real_mode (void ); +void reserve_real_mode (void ); +void setup_real_mode (void );#endif /* _ARCH_X86_REALMODE_H */
arch/x86/kernel/setup.c +3 -1
@@ -999,12 +999,14 @@ void __init setup_arch(char **cmdline_p)printk (KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n" , (max_pfn_mapped<<PAGE_SHIFT ) -1 ); -setup_real_mode (); +reserve_real_mode ();trim_platform_memory_ranges ();init_mem_mapping (); +setup_real_mode (); + memblock.current_limit =get_max_mapped ();dma_contiguous_reserve (0 );
arch/x86/realmode/init.c +20 -12
@@ -8,9 +8,26 @@struct real_mode_header *real_mode_header;u32 *trampoline_cr4_features; -void __init setup_real_mode (void ) +void __init reserve_real_mode (void ) {phys_addr_t mem; +unsigned char *base; +size_t size =PAGE_ALIGN (real_mode_blob_end - real_mode_blob); + +/* Has to be under 1M so we can execute real-mode AP code. */ + mem =memblock_find_in_range (0 ,1 <<20 , size,PAGE_SIZE ); +if (!mem) +panic ("Cannot allocate trampoline\n" ); + + base =__va (mem); +memblock_reserve (mem, size); + real_mode_header = (struct real_mode_header *) base; +printk (KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n" , + base, (unsigned long long )mem, size); +} + +void __init setup_real_mode (void ) +{u16 real_mode_seg;u32 *rel;u32 count;
@@ -25,16 +42,7 @@ void __init setup_real_mode(void)u64 efer;#endif -/* Has to be in very low memory so we can execute real-mode AP code. */ - mem =memblock_find_in_range (0 ,1 <<20 , size,PAGE_SIZE ); -if (!mem) -panic ("Cannot allocate trampoline\n" ); - - base =__va (mem); -memblock_reserve (mem, size); - real_mode_header = (struct real_mode_header *) base; -printk (KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n" , - base, (unsigned long long )mem, size); + base = (unsigned char *)real_mode_header;memcpy (base, real_mode_blob, size);
@@ -84,7 +92,7 @@ void __init setup_real_mode(void) }/* -* setup_real_mode() gets called very early, to guarantee the +* reserve_real_mode() gets called very early, to guarantee the * availability of low memory. This is before the proper kernel page * tables are set up, so we cannot set page permissions in that * function. Also trampoline code will be executed by APs so we
PATCH 11/35 x86, 64bit: early #PF handler set page table
In reply to Yinghai LuFrom: "H. Peter Anvin" <[email protected]>
two use cases:
1. We will support load and run kernel above 4G, and zero_page, ramdisk will be above 4G, too
2. need to access ramdisk early to get microcode to update that as early possible.
We could use early_iomap to access them too, but it will make code to messy and hard to be unified with 32bit.
So here comes #PF handler to set page page.
When #PF happens, the handler will use pages in __initdata to set page table to cover accessed page.
those code and page in __INIT sections, so will not increase ram usages for runtime.
The good point is: with help of #PF handler, we can set final kernel mapping from blank, and switch to init_level4_pgt later.
switchover in head_64.S is only using three pages to handle kernel crossing 1G, 512G boundaries with sharing page, most insteresting part.
early_make_pgtable is using kernel high mapping address to access pages to set page table.
-v4: Add phys_base offset to make kexec happy, and add
init_mapping_kernel() - Yinghai
-v5: fix compiling with xen, and add back ident level3 and level2 for xen
also move back init_level4_pgt from BSS to DATA again. because we have to clear it anyway. - Yinghai
-v6: switch to init_level4_pgt in init_mem_mapping. - Yinghai -v7: remove not needed clear_page for init_level4_page
it is with fill 512,8,0 already in head_64.S - Yinghai
-v8: we need to keep that handler alive until init_mem_mapping and don't
let early_trap_init to trash that early #PF handler.
So split early_trap_pf_init out and move it down. - Yinghai
-v9: switchover only cover kernel space instead of 1G so could avoid
touch possible mem holes. - Yinghai
-v11: change far jmp back to far return to initial_code, that is needed
to fix failure that is reported by Konrad on AMD systems. - Yinghai
--- arch/x86/include/asm/pgtable_64_types.h | 4 + arch/x86/include/asm/processor.h | 1 + arch/x86/kernel/head64.c | 81 ++++++++++-- arch/x86/kernel/head_64.S | 210 +++++++++++++++++++------------ arch/x86/kernel/setup.c | 2 + arch/x86/kernel/traps.c | 9 ++ arch/x86/mm/init.c | 3 +- 7 files changed, 219 insertions(+), 91 deletions(-)
arch/x86/include/asm/pgtable_64_types.h +4 -0
@@ -1,6 +1,8 @@#ifndef _ASM_X86_PGTABLE_64_DEFS_H#define _ASM_X86_PGTABLE_64_DEFS_H +#include <asm/sparsemem.h> +#ifndef __ASSEMBLY__#include <linux/types.h>
@@ -60,4 +62,6 @@ typedef struct { pteval_t pte; } pte_t;#define MODULES_END _AC(0xffffffffff000000, UL)#define MODULES_LEN (MODULES_END - MODULES_VADDR) +#define EARLY_DYNAMIC_PAGE_TABLES 64 +#endif /* _ASM_X86_PGTABLE_64_DEFS_H */
arch/x86/include/asm/processor.h +1 -0
@@ -731,6 +731,7 @@ extern void enable_sep_cpu(void);extern int sysenter_setup (void );extern void early_trap_init (void ); +void early_trap_pf_init (void );/* Defined in head.S */ extern struct desc_ptr early_gdt_descr;
arch/x86/kernel/head64.c +74 -7
103 lines not on this page · raw message
arch/x86/kernel/head_64.S +127 -83
371 lines not on this page · raw message
arch/x86/kernel/setup.c +2 -0
@@ -1005,6 +1005,8 @@ void __init setup_arch(char **cmdline_p)init_mem_mapping (); +early_trap_pf_init (); +setup_real_mode (); memblock.current_limit =get_max_mapped ();
arch/x86/kernel/traps.c +9 -0
@@ -688,10 +688,19 @@ void __init early_trap_init(void)set_intr_gate_ist (X86_TRAP_DB , &debug,DEBUG_STACK );/* int3 can be called from all */ set_system_intr_gate_ist (X86_TRAP_BP , &int3,DEBUG_STACK ); +#ifdef CONFIG_X86_32 set_intr_gate (X86_TRAP_PF , &page_fault); +#endif load_idt (&idt_descr); } +void __init early_trap_pf_init (void ) +{ +#ifdef CONFIG_X86_64 +set_intr_gate (X86_TRAP_PF , &page_fault); +#endif +} +void __init trap_init (void ) {int i;
arch/x86/mm/init.c +2 -1
@@ -446,9 +446,10 @@ void __init init_mem_mapping(void) }#else early_ioremap_page_table_range_init (); +#endif +load_cr3 (swapper_pg_dir);__flush_tlb_all (); -#endif early_memtest (0 , max_pfn_mapped <<PAGE_SHIFT ); }
Signature · 1 line
1.7.10.4
tip-bot for H. Peter Anvin
reviewer[tip:x86/mm2] x86, 64bit: Use a #PF handler to materialize early mappings on demand
Commit-ID: 8170e6bed465b4b0c7687f93e9948aca4358a33b Gitweb: http://git.kernel.org/tip/8170e6bed465b4b0c7687f93e9948aca4358a33b Author: H. Peter Anvin <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:52 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:20:06 -0800
x86, 64bit: Use a #PF handler to materialize early mappings on demand
Linear mode (CR0.PG = 0) is mutually exclusive with 64-bit mode; all 64-bit code has to use page tables. This makes it awkward before we have first set up properly all-covering page tables to access objects that are outside the static kernel range.
So far we have dealt with that simply by mapping a fixed amount of low memory, but that fails in at least two upcoming use cases:
1. We will support load and run kernel, struct boot_params, ramdisk, command line, etc. above the 4 GiB mark.
2. need to access ramdisk early to get microcode to update that as early possible.
We could use early_iomap to access them too, but it will make code to messy and hard to be unified with 32 bit.
Hence, set up a #PF table and use a fixed number of buffers to set up page tables on demand. If the buffers fill up then we simply flush them and start over. These buffers are all in __initdata, so it does not increase RAM usage at runtime.
Thus, with the help of the #PF handler, we can set the final kernel mapping from blank, and switch to init_level4_pgt later.
During the switchover in head_64.S, before #PF handler is available, we use three pages to handle kernel crossing 1G, 512G boundaries with sharing page by playing games with page aliasing: the same page is mapped twice in the higher-level tables with appropriate wraparound. The kernel region itself will be properly mapped; other mappings may be spurious.
early_make_pgtable is using kernel high mapping address to access pages to set page table.
-v4: Add phys_base offset to make kexec happy, and add
init_mapping_kernel() - Yinghai
-v5: fix compiling with xen, and add back ident level3 and level2 for xen
also move back init_level4_pgt from BSS to DATA again. because we have to clear it anyway. - Yinghai
-v6: switch to init_level4_pgt in init_mem_mapping. - Yinghai -v7: remove not needed clear_page for init_level4_page
it is with fill 512,8,0 already in head_64.S - Yinghai
-v8: we need to keep that handler alive until init_mem_mapping and don't
let early_trap_init to trash that early #PF handler.
So split early_trap_pf_init out and move it down. - Yinghai
-v9: switchover only cover kernel space instead of 1G so could avoid
touch possible mem holes. - Yinghai
-v11: change far jmp back to far return to initial_code, that is needed
to fix failure that is reported by Konrad on AMD systems. - Yinghai
--- arch/x86/include/asm/pgtable_64_types.h | 4 + arch/x86/include/asm/processor.h | 1 + arch/x86/kernel/head64.c | 81 ++++++++++-- arch/x86/kernel/head_64.S | 210 +++++++++++++++++++------------- arch/x86/kernel/setup.c | 2 + arch/x86/kernel/traps.c | 9 ++ arch/x86/mm/init.c | 3 +- 7 files changed, 219 insertions(+), 91 deletions(-)
arch/x86/include/asm/pgtable_64_types.h +4 -0
@@ -1,6 +1,8 @@#ifndef _ASM_X86_PGTABLE_64_DEFS_H#define _ASM_X86_PGTABLE_64_DEFS_H +#include <asm/sparsemem.h> +#ifndef __ASSEMBLY__#include <linux/types.h>
@@ -60,4 +62,6 @@ typedef struct { pteval_t pte; } pte_t;#define MODULES_END _AC(0xffffffffff000000, UL)#define MODULES_LEN (MODULES_END - MODULES_VADDR) +#define EARLY_DYNAMIC_PAGE_TABLES 64 +#endif /* _ASM_X86_PGTABLE_64_DEFS_H */
arch/x86/include/asm/processor.h +1 -0
@@ -731,6 +731,7 @@ extern void enable_sep_cpu(void);extern int sysenter_setup (void );extern void early_trap_init (void ); +void early_trap_pf_init (void );/* Defined in head.S */ extern struct desc_ptr early_gdt_descr;
arch/x86/kernel/head64.c +74 -7
103 lines not on this page · raw message
arch/x86/kernel/head_64.S +127 -83
371 lines not on this page · raw message
arch/x86/kernel/setup.c +2 -0
@@ -1005,6 +1005,8 @@ void __init setup_arch(char **cmdline_p)init_mem_mapping (); +early_trap_pf_init (); +setup_real_mode (); memblock.current_limit =get_max_mapped ();
arch/x86/kernel/traps.c +9 -0
@@ -688,10 +688,19 @@ void __init early_trap_init(void)set_intr_gate_ist (X86_TRAP_DB , &debug,DEBUG_STACK );/* int3 can be called from all */ set_system_intr_gate_ist (X86_TRAP_BP , &int3,DEBUG_STACK ); +#ifdef CONFIG_X86_32 set_intr_gate (X86_TRAP_PF , &page_fault); +#endif load_idt (&idt_descr); } +void __init early_trap_pf_init (void ) +{ +#ifdef CONFIG_X86_64 +set_intr_gate (X86_TRAP_PF , &page_fault); +#endif +} +void __init trap_init (void ) {int i;
arch/x86/mm/init.c +2 -1
@@ -446,9 +446,10 @@ void __init init_mem_mapping(void) }#else early_ioremap_page_table_range_init (); +#endif +load_cr3 (swapper_pg_dir);__flush_tlb_all (); -#endif early_memtest (0 , max_pfn_mapped <<PAGE_SHIFT ); }
PATCH 12/35 x86, 64bit: #PF handler set page to cover only 2M per #PF
In reply to Yinghai LuNow #PF hanlder map 1G per #PF, That causes same problem that is fixed by
x86, mm: Only direct map addresses that are marked as E820_RAM
add only one 2M mapping per #PF instead.
--- arch/x86/kernel/head64.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-)
arch/x86/kernel/head64.c +25 -17
@@ -52,15 +52,15 @@ int __init early_make_pgtable(unsigned long address)unsigned long physaddr = address - __PAGE_OFFSET;unsigned long i;pgdval_t pgd, *pgd_p; -pudval_t *pud_p; +pudval_t pud, *pud_p;pmdval_t pmd, *pmd_p;/* Invalid address or early pgt is done ? */ if (physaddr >=MAXMEM ||read_cr3 () !=__pa (early_level4_pgt))return -1 ; - i = (address >>PGDIR_SHIFT ) & (PTRS_PER_PGD -1 ); - pgd_p = &early_level4_pgt[i].pgd; +again: + pgd_p = &early_level4_pgt[pgd_index (address)].pgd; pgd = *pgd_p;/*
@@ -68,29 +68,37 @@ int __init early_make_pgtable(unsigned long address)* critical -- __PAGE_OFFSET would point us back into the dynamic * range and we might end up looping forever... */ -if (pgd && next_early_pgt <EARLY_DYNAMIC_PAGE_TABLES ) { +if (pgd) pud_p = (pudval_t *)((pgd &PTE_PFN_MASK ) + __START_KERNEL_map - phys_base); - }else { -if (next_early_pgt >=EARLY_DYNAMIC_PAGE_TABLES -1 ) +else { +if (next_early_pgt >=EARLY_DYNAMIC_PAGE_TABLES ) {reset_early_page_tables (); + goto again; + } pud_p = (pudval_t *)early_dynamic_pgts[next_early_pgt++];for (i =0 ; i <PTRS_PER_PUD ; i++) pud_p[i] =0 ; - *pgd_p = (pgdval_t )pud_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE; } - i = (address >>PUD_SHIFT ) & (PTRS_PER_PUD -1 ); - pud_p += i; - - pmd_p = (pmdval_t *)early_dynamic_pgts[next_early_pgt++]; - pmd = (physaddr &PUD_MASK ) + (__PAGE_KERNEL_LARGE & ~_PAGE_GLOBAL); -for (i =0 ; i <PTRS_PER_PMD ; i++) { - pmd_p[i] = pmd; - pmd +=PMD_SIZE ; - } + pud_p +=pud_index (address); + pud = *pud_p; - *pud_p = (pudval_t )pmd_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE; +if (pud) + pmd_p = (pmdval_t *)((pud &PTE_PFN_MASK ) + __START_KERNEL_map - phys_base); +else { +if (next_early_pgt >=EARLY_DYNAMIC_PAGE_TABLES ) { +reset_early_page_tables (); + goto again; + } + + pmd_p = (pmdval_t *)early_dynamic_pgts[next_early_pgt++]; +for (i =0 ; i <PTRS_PER_PMD ; i++) + pmd_p[i] =0 ; + *pud_p = (pudval_t )pmd_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE; + } + pmd = (physaddr &PMD_MASK ) + (__PAGE_KERNEL_LARGE & ~_PAGE_GLOBAL); + pmd_p[pmd_index (address)] = pmd;return 0 ; }
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, 64bit: #PF handler set page to cover only 2M per #PF
Commit-ID: 6b9c75aca6cba4d99a6e8d8274b1788d4d4b50d9 Gitweb: http://git.kernel.org/tip/6b9c75aca6cba4d99a6e8d8274b1788d4d4b50d9 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:53 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:20:13 -0800
x86, 64bit: #PF handler set page to cover only 2M per #PF
We only map a single 2 MiB page per #PF, even though we should be able to do this a full gigabyte at a time with no additional memory cost. This is a workaround for a broken AMD reference BIOS (and its derivatives in shipping system) which maps a large chunk of memory as WB in the MTRR system but will #MC if the processor wanders off and tries to prefetch that memory, which can happen any time the memory is mapped in the TLB.
--- arch/x86/kernel/head64.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-)
arch/x86/kernel/head64.c +25 -17
@@ -53,15 +53,15 @@ int __init early_make_pgtable(unsigned long address)unsigned long physaddr = address - __PAGE_OFFSET;unsigned long i;pgdval_t pgd, *pgd_p; -pudval_t *pud_p; +pudval_t pud, *pud_p;pmdval_t pmd, *pmd_p;/* Invalid address or early pgt is done ? */ if (physaddr >=MAXMEM ||read_cr3 () !=__pa (early_level4_pgt))return -1 ; - i = (address >>PGDIR_SHIFT ) & (PTRS_PER_PGD -1 ); - pgd_p = &early_level4_pgt[i].pgd; +again: + pgd_p = &early_level4_pgt[pgd_index (address)].pgd; pgd = *pgd_p;/*
@@ -69,29 +69,37 @@ int __init early_make_pgtable(unsigned long address)* critical -- __PAGE_OFFSET would point us back into the dynamic * range and we might end up looping forever... */ -if (pgd && next_early_pgt <EARLY_DYNAMIC_PAGE_TABLES ) { +if (pgd) pud_p = (pudval_t *)((pgd &PTE_PFN_MASK ) + __START_KERNEL_map - phys_base); - }else { -if (next_early_pgt >=EARLY_DYNAMIC_PAGE_TABLES -1 ) +else { +if (next_early_pgt >=EARLY_DYNAMIC_PAGE_TABLES ) {reset_early_page_tables (); + goto again; + } pud_p = (pudval_t *)early_dynamic_pgts[next_early_pgt++];for (i =0 ; i <PTRS_PER_PUD ; i++) pud_p[i] =0 ; - *pgd_p = (pgdval_t )pud_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE; } - i = (address >>PUD_SHIFT ) & (PTRS_PER_PUD -1 ); - pud_p += i; - - pmd_p = (pmdval_t *)early_dynamic_pgts[next_early_pgt++]; - pmd = (physaddr &PUD_MASK ) + (__PAGE_KERNEL_LARGE & ~_PAGE_GLOBAL); -for (i =0 ; i <PTRS_PER_PMD ; i++) { - pmd_p[i] = pmd; - pmd +=PMD_SIZE ; - } + pud_p +=pud_index (address); + pud = *pud_p; - *pud_p = (pudval_t )pmd_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE; +if (pud) + pmd_p = (pmdval_t *)((pud &PTE_PFN_MASK ) + __START_KERNEL_map - phys_base); +else { +if (next_early_pgt >=EARLY_DYNAMIC_PAGE_TABLES ) { +reset_early_page_tables (); + goto again; + } + + pmd_p = (pmdval_t *)early_dynamic_pgts[next_early_pgt++]; +for (i =0 ; i <PTRS_PER_PMD ; i++) + pmd_p[i] =0 ; + *pud_p = (pudval_t )pmd_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE; + } + pmd = (physaddr &PMD_MASK ) + (__PAGE_KERNEL_LARGE & ~_PAGE_GLOBAL); + pmd_p[pmd_index (address)] = pmd;return 0 ; }
PATCH 13/35 x86, 64bit: Don't set max_pfn_mapped wrong value early on native path
In reply to Yinghai LuWe are not having max_pfn_mapped set correctly until init_memory_mapping. So don't print its initial value for 64bit
Also need to use KERNEL_IMAGE_SIZE directly for highmap cleanup.
-v2: update comments about max_pfn_mapped according to Stefano Stabellini.
--- arch/x86/kernel/head64.c | 3 --- arch/x86/kernel/setup.c | 2 ++ arch/x86/mm/init_64.c | 10 +++++++++- 3 files changed, 11 insertions(+), 4 deletions(-)
arch/x86/kernel/head64.c +0 -3
@@ -146,9 +146,6 @@ void __init x86_64_start_kernel(char * real_mode_data)/* clear bss before set_intr_gate with early_idt_handler */ clear_bss (); -/* XXX - this is wrong... we need to build page tables from scratch */ - max_pfn_mapped =KERNEL_IMAGE_SIZE >>PAGE_SHIFT ; -for (i =0 ; i <NUM_EXCEPTION_VECTORS ; i++) {#ifdef CONFIG_EARLY_PRINTK set_intr_gate (i, &early_idt_handlers[i]);
arch/x86/kernel/setup.c +2 -0
@@ -996,8 +996,10 @@ void __init setup_arch(char **cmdline_p)setup_bios_corruption_check ();#endif +#ifdef CONFIG_X86_32 printk (KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n" , (max_pfn_mapped<<PAGE_SHIFT ) -1 ); +#endif reserve_real_mode ();
arch/x86/mm/init_64.c +9 -1
@@ -378,10 +378,18 @@ void __init init_extra_mapping_uc(unsigned long phys, unsigned long size)void __init cleanup_highmap (void ) {unsigned long vaddr = __START_KERNEL_map; -unsigned long vaddr_end = __START_KERNEL_map + (max_pfn_mapped <<PAGE_SHIFT ); +unsigned long vaddr_end = __START_KERNEL_map +KERNEL_IMAGE_SIZE ;unsigned long end =roundup ((unsigned long )_brk_end,PMD_SIZE ) -1 ;pmd_t *pmd = level2_kernel_pgt; +/* +* Native path, max_pfn_mapped is not set yet. +* Xen has valid max_pfn_mapped set in +* arch/x86/xen/mmu.c:xen_setup_kernel_pagetable(). +*/ +if (max_pfn_mapped) + vaddr_end = __START_KERNEL_map + (max_pfn_mapped <<PAGE_SHIFT ); +for (; vaddr +PMD_SIZE -1 < vaddr_end; pmd++, vaddr +=PMD_SIZE ) {if (pmd_none (*pmd))continue ;
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, 64bit: Don' t set max_pfn_mapped wrong value early on native path
Commit-ID: 100542306f644fc580857a8ca4896fb12b794d41 Gitweb: http://git.kernel.org/tip/100542306f644fc580857a8ca4896fb12b794d41 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:54 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:20:16 -0800
x86, 64bit: Don't set max_pfn_mapped wrong value early on native path
We are not having max_pfn_mapped set correctly until init_memory_mapping. So don't print its initial value for 64bit
Also need to use KERNEL_IMAGE_SIZE directly for highmap cleanup.
-v2: update comments about max_pfn_mapped according to Stefano Stabellini.
--- arch/x86/kernel/head64.c | 3 --- arch/x86/kernel/setup.c | 2 ++ arch/x86/mm/init_64.c | 10 +++++++++- 3 files changed, 11 insertions(+), 4 deletions(-)
arch/x86/kernel/head64.c +0 -3
@@ -148,9 +148,6 @@ void __init x86_64_start_kernel(char * real_mode_data)/* clear bss before set_intr_gate with early_idt_handler */ clear_bss (); -/* XXX - this is wrong... we need to build page tables from scratch */ - max_pfn_mapped =KERNEL_IMAGE_SIZE >>PAGE_SHIFT ; -for (i =0 ; i <NUM_EXCEPTION_VECTORS ; i++) {#ifdef CONFIG_EARLY_PRINTK set_intr_gate (i, &early_idt_handlers[i]);
arch/x86/kernel/setup.c +2 -0
@@ -996,8 +996,10 @@ void __init setup_arch(char **cmdline_p)setup_bios_corruption_check ();#endif +#ifdef CONFIG_X86_32 printk (KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n" , (max_pfn_mapped<<PAGE_SHIFT ) -1 ); +#endif reserve_real_mode ();
arch/x86/mm/init_64.c +9 -1
@@ -378,10 +378,18 @@ void __init init_extra_mapping_uc(unsigned long phys, unsigned long size)void __init cleanup_highmap (void ) {unsigned long vaddr = __START_KERNEL_map; -unsigned long vaddr_end = __START_KERNEL_map + (max_pfn_mapped <<PAGE_SHIFT ); +unsigned long vaddr_end = __START_KERNEL_map +KERNEL_IMAGE_SIZE ;unsigned long end =roundup ((unsigned long )_brk_end,PMD_SIZE ) -1 ;pmd_t *pmd = level2_kernel_pgt; +/* +* Native path, max_pfn_mapped is not set yet. +* Xen has valid max_pfn_mapped set in +* arch/x86/xen/mmu.c:xen_setup_kernel_pagetable(). +*/ +if (max_pfn_mapped) + vaddr_end = __START_KERNEL_map + (max_pfn_mapped <<PAGE_SHIFT ); +for (; vaddr +PMD_SIZE -1 < vaddr_end; pmd++, vaddr +=PMD_SIZE ) {if (pmd_none (*pmd))continue ;
PATCH 14/35 x86: Merge early_reserve_initrd for 32bit and 64bit
In reply to Yinghai LuThey are the same, could move them out from head32/64.c to setup.c.
We are using memblock, and it could handle overlapping properly, so we don't need to reserve some at first to hold the location, and just need to make sure we reserve them before we are using memblock to find free mem to use.
--- arch/x86/kernel/head32.c | 11 ----------- arch/x86/kernel/head64.c | 11 ----------- arch/x86/kernel/setup.c | 22 ++++++++++++++++++---- 3 files changed, 18 insertions(+), 26 deletions(-)
arch/x86/kernel/head32.c +0 -11
@@ -33,17 +33,6 @@ void __init i386_start_kernel(void)memblock_reserve (__pa_symbol (_text), (unsigned long )__bss_stop - (unsigned long )_text); -#ifdef CONFIG_BLK_DEV_INITRD -/* Reserve INITRD */ -if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { -/* Assume only end is not page aligned */ -u64 ramdisk_image = boot_params.hdr.ramdisk_image; -u64 ramdisk_size = boot_params.hdr.ramdisk_size; -u64 ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size); -memblock_reserve (ramdisk_image, ramdisk_end - ramdisk_image); - } -#endif -/* Call the subarch specific early setup function */ switch (boot_params.hdr.hardware_subarch) {case X86_SUBARCH_MRST :
arch/x86/kernel/head64.c +0 -11
@@ -176,17 +176,6 @@ void __init x86_64_start_reservations(char *real_mode_data)memblock_reserve (__pa_symbol (_text), (unsigned long )__bss_stop - (unsigned long )_text); -#ifdef CONFIG_BLK_DEV_INITRD -/* Reserve INITRD */ -if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { -/* Assume only end is not page aligned */ -unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; -unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; -unsigned long ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size); -memblock_reserve (ramdisk_image, ramdisk_end - ramdisk_image); - } -#endif -reserve_ebda_region ();/*
arch/x86/kernel/setup.c +18 -4
@@ -360,6 +360,19 @@ static u64 __init get_mem_size(unsigned long limit_pfn)return mapped_pages <<PAGE_SHIFT ; } +static void __init early_reserve_initrd (void ) +{ +/* Assume only end is not page aligned */ +u64 ramdisk_image = boot_params.hdr.ramdisk_image; +u64 ramdisk_size = boot_params.hdr.ramdisk_size; +u64 ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size); + +if (!boot_params.hdr.type_of_loader || + !ramdisk_image || !ramdisk_size) +return ;/* No initrd provided by bootloader */ + +memblock_reserve (ramdisk_image, ramdisk_end - ramdisk_image); +}static void __init reserve_initrd (void ) {/* Assume only end is not page aligned */
@@ -386,10 +399,6 @@ static void __init reserve_initrd(void)if (pfn_range_is_mapped (PFN_DOWN (ramdisk_image),PFN_DOWN (ramdisk_end))) {/* All are mapped, easy case */ -/* -* don't need to reserve again, already reserved early -* in i386_start_kernel -*/ initrd_start = ramdisk_image +PAGE_OFFSET ; initrd_end = initrd_start + ramdisk_size;return ;
@@ -400,6 +409,9 @@ static void __init reserve_initrd(void) memblock_free(ramdisk_image, ramdisk_end - ramdisk_image); }#else +static void __init early_reserve_initrd (void ) +{ +}static void __init reserve_initrd (void ) { }
@@ -760,6 +772,8 @@ early_param("reservelow", parse_reservelow);void __init setup_arch (char **cmdline_p) { +early_reserve_initrd (); +#ifdef CONFIG_X86_32 memcpy (&boot_cpu_data, &new_cpu_data,sizeof (new_cpu_data));visws_early_detect ();
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86: Merge early_reserve_initrd for 32bit and 64bit
Commit-ID: 1b8c78be01203e1c95ec5dfef6db307796fe0bc7 Gitweb: http://git.kernel.org/tip/1b8c78be01203e1c95ec5dfef6db307796fe0bc7 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:55 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:20:41 -0800
x86: Merge early_reserve_initrd for 32bit and 64bit
They are the same, could move them out from head32/64.c to setup.c.
We are using memblock, and it could handle overlapping properly, so we don't need to reserve some at first to hold the location, and just need to make sure we reserve them before we are using memblock to find free mem to use.
--- arch/x86/kernel/head32.c | 11 ----------- arch/x86/kernel/head64.c | 11 ----------- arch/x86/kernel/setup.c | 22 ++++++++++++++++++---- 3 files changed, 18 insertions(+), 26 deletions(-)
arch/x86/kernel/head32.c +0 -11
@@ -36,17 +36,6 @@ void __init i386_start_kernel(void)memblock_reserve (__pa_symbol (&_text),__pa_symbol (&__bss_stop) -__pa_symbol (&_text)); -#ifdef CONFIG_BLK_DEV_INITRD -/* Reserve INITRD */ -if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { -/* Assume only end is not page aligned */ -u64 ramdisk_image = boot_params.hdr.ramdisk_image; -u64 ramdisk_size = boot_params.hdr.ramdisk_size; -u64 ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size); -memblock_reserve (ramdisk_image, ramdisk_end - ramdisk_image); - } -#endif -/* Call the subarch specific early setup function */ switch (boot_params.hdr.hardware_subarch) {case X86_SUBARCH_MRST :
arch/x86/kernel/head64.c +0 -11
@@ -178,17 +178,6 @@ void __init x86_64_start_reservations(char *real_mode_data)memblock_reserve (__pa_symbol (&_text),__pa_symbol (&__bss_stop) -__pa_symbol (&_text)); -#ifdef CONFIG_BLK_DEV_INITRD -/* Reserve INITRD */ -if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { -/* Assume only end is not page aligned */ -unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; -unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; -unsigned long ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size); -memblock_reserve (ramdisk_image, ramdisk_end - ramdisk_image); - } -#endif -reserve_ebda_region ();/*
arch/x86/kernel/setup.c +18 -4
@@ -360,6 +360,19 @@ static u64 __init get_mem_size(unsigned long limit_pfn)return mapped_pages <<PAGE_SHIFT ; } +static void __init early_reserve_initrd (void ) +{ +/* Assume only end is not page aligned */ +u64 ramdisk_image = boot_params.hdr.ramdisk_image; +u64 ramdisk_size = boot_params.hdr.ramdisk_size; +u64 ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size); + +if (!boot_params.hdr.type_of_loader || + !ramdisk_image || !ramdisk_size) +return ;/* No initrd provided by bootloader */ + +memblock_reserve (ramdisk_image, ramdisk_end - ramdisk_image); +}static void __init reserve_initrd (void ) {/* Assume only end is not page aligned */
@@ -386,10 +399,6 @@ static void __init reserve_initrd(void)if (pfn_range_is_mapped (PFN_DOWN (ramdisk_image),PFN_DOWN (ramdisk_end))) {/* All are mapped, easy case */ -/* -* don't need to reserve again, already reserved early -* in i386_start_kernel -*/ initrd_start = ramdisk_image +PAGE_OFFSET ; initrd_end = initrd_start + ramdisk_size;return ;
@@ -400,6 +409,9 @@ static void __init reserve_initrd(void) memblock_free(ramdisk_image, ramdisk_end - ramdisk_image); }#else +static void __init early_reserve_initrd (void ) +{ +}static void __init reserve_initrd (void ) { }
@@ -760,6 +772,8 @@ early_param("reservelow", parse_reservelow);void __init setup_arch (char **cmdline_p) { +early_reserve_initrd (); +#ifdef CONFIG_X86_32 memcpy (&boot_cpu_data, &new_cpu_data,sizeof (new_cpu_data));visws_early_detect ();
PATCH 15/35 x86: Add get_ramdisk_image/size()
In reply to Yinghai LuThere are several places to find ramdisk information early for reserving and relocating.
Use functions to make code more readable and consistent.
Later will add ext_ramdisk_image/size in those functions to support loading ramdisk above 4g.
--- arch/x86/kernel/setup.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-)
arch/x86/kernel/setup.c +21 -8
@@ -294,12 +294,25 @@ static void __init reserve_brk(void)#ifdef CONFIG_BLK_DEV_INITRD +static u64 __init get_ramdisk_image (void ) +{ +u64 ramdisk_image = boot_params.hdr.ramdisk_image; + +return ramdisk_image; +} +static u64 __init get_ramdisk_size (void ) +{ +u64 ramdisk_size = boot_params.hdr.ramdisk_size; + +return ramdisk_size; +} +#define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT)static void __init relocate_initrd (void ) {/* Assume only end is not page aligned */ -u64 ramdisk_image = boot_params.hdr.ramdisk_image; -u64 ramdisk_size = boot_params.hdr.ramdisk_size; +u64 ramdisk_image =get_ramdisk_image (); +u64 ramdisk_size =get_ramdisk_size ();u64 area_size =PAGE_ALIGN (ramdisk_size);u64 ramdisk_here;unsigned long slop, clen, mapaddr;
@@ -338,8 +351,8 @@ static void __init relocate_initrd(void) ramdisk_size -= clen; } - ramdisk_image = boot_params.hdr.ramdisk_image; - ramdisk_size = boot_params.hdr.ramdisk_size; + ramdisk_image =get_ramdisk_image (); + ramdisk_size =get_ramdisk_size (); printk(KERN_INFO "Move RAMDISK from [mem %#010llx-%#010llx] to" " [mem %#010llx-%#010llx]\n", ramdisk_image, ramdisk_image + ramdisk_size - 1,
@@ -363,8 +376,8 @@ static u64 __init get_mem_size(unsigned long limit_pfn)static void __init early_reserve_initrd (void ) {/* Assume only end is not page aligned */ -u64 ramdisk_image = boot_params.hdr.ramdisk_image; -u64 ramdisk_size = boot_params.hdr.ramdisk_size; +u64 ramdisk_image =get_ramdisk_image (); +u64 ramdisk_size =get_ramdisk_size ();u64 ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size); if (!boot_params.hdr.type_of_loader ||
@@ -376,8 +389,8 @@ static void __init early_reserve_initrd(void)static void __init reserve_initrd (void ) {/* Assume only end is not page aligned */ -u64 ramdisk_image = boot_params.hdr.ramdisk_image; -u64 ramdisk_size = boot_params.hdr.ramdisk_size; +u64 ramdisk_image =get_ramdisk_image (); +u64 ramdisk_size =get_ramdisk_size ();u64 ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size);u64 mapped_size;
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86: Add get_ramdisk_image/size()
Commit-ID: a8a51a88d5152aa40e5e07dcdd939c7fafc42224 Gitweb: http://git.kernel.org/tip/a8a51a88d5152aa40e5e07dcdd939c7fafc42224 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:56 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:21:05 -0800
x86: Add get_ramdisk_image/size()
There are several places to find ramdisk information early for reserving and relocating.
Use accessor functions to make code more readable and consistent.
Later will add ext_ramdisk_image/size in those functions to support loading ramdisk above 4g.
--- arch/x86/kernel/setup.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-)
arch/x86/kernel/setup.c +21 -8
@@ -294,12 +294,25 @@ static void __init reserve_brk(void)#ifdef CONFIG_BLK_DEV_INITRD +static u64 __init get_ramdisk_image (void ) +{ +u64 ramdisk_image = boot_params.hdr.ramdisk_image; + +return ramdisk_image; +} +static u64 __init get_ramdisk_size (void ) +{ +u64 ramdisk_size = boot_params.hdr.ramdisk_size; + +return ramdisk_size; +} +#define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT)static void __init relocate_initrd (void ) {/* Assume only end is not page aligned */ -u64 ramdisk_image = boot_params.hdr.ramdisk_image; -u64 ramdisk_size = boot_params.hdr.ramdisk_size; +u64 ramdisk_image =get_ramdisk_image (); +u64 ramdisk_size =get_ramdisk_size ();u64 area_size =PAGE_ALIGN (ramdisk_size);u64 ramdisk_here;unsigned long slop, clen, mapaddr;
@@ -338,8 +351,8 @@ static void __init relocate_initrd(void) ramdisk_size -= clen; } - ramdisk_image = boot_params.hdr.ramdisk_image; - ramdisk_size = boot_params.hdr.ramdisk_size; + ramdisk_image =get_ramdisk_image (); + ramdisk_size =get_ramdisk_size (); printk(KERN_INFO "Move RAMDISK from [mem %#010llx-%#010llx] to" " [mem %#010llx-%#010llx]\n", ramdisk_image, ramdisk_image + ramdisk_size - 1,
@@ -363,8 +376,8 @@ static u64 __init get_mem_size(unsigned long limit_pfn)static void __init early_reserve_initrd (void ) {/* Assume only end is not page aligned */ -u64 ramdisk_image = boot_params.hdr.ramdisk_image; -u64 ramdisk_size = boot_params.hdr.ramdisk_size; +u64 ramdisk_image =get_ramdisk_image (); +u64 ramdisk_size =get_ramdisk_size ();u64 ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size); if (!boot_params.hdr.type_of_loader ||
@@ -376,8 +389,8 @@ static void __init early_reserve_initrd(void)static void __init reserve_initrd (void ) {/* Assume only end is not page aligned */ -u64 ramdisk_image = boot_params.hdr.ramdisk_image; -u64 ramdisk_size = boot_params.hdr.ramdisk_size; +u64 ramdisk_image =get_ramdisk_image (); +u64 ramdisk_size =get_ramdisk_size ();u64 ramdisk_end =PAGE_ALIGN (ramdisk_image + ramdisk_size);u64 mapped_size;
PATCH 16/35 x86, boot: Add get_cmd_line_ptr()
In reply to Yinghai Lulater will check ext_cmd_line_ptr at the same time.
--- arch/x86/boot/compressed/cmdline.c | 10 ++++++++-- arch/x86/kernel/head64.c | 13 +++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-)
arch/x86/boot/compressed/cmdline.c +8 -2
@@ -13,13 +13,19 @@ static inline char rdfs8(addr_t addr) return *((char *)(fs + addr)); }#include "../cmdline.c" +static unsigned long get_cmd_line_ptr (void ) +{ +unsigned long cmd_line_ptr = real_mode->hdr.cmd_line_ptr; + +return cmd_line_ptr; +}int cmdline_find_option (const char *option,char *buffer,int bufsize) { -return __cmdline_find_option (real_mode->hdr.cmd_line_ptr, option, buffer, bufsize); +return __cmdline_find_option (get_cmd_line_ptr (), option, buffer, bufsize); }int cmdline_find_option_bool (const char *option) { -return __cmdline_find_option_bool (real_mode->hdr.cmd_line_ptr, option); +return __cmdline_find_option_bool (get_cmd_line_ptr (), option); }#endif
arch/x86/kernel/head64.c +11 -2
@@ -111,13 +111,22 @@ static void __init clear_bss(void) (unsigned long) __bss_stop - (unsigned long) __bss_start); } +static unsigned long get_cmd_line_ptr (void ) +{ +unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + +return cmd_line_ptr; +} +static void __init copy_bootdata (char *real_mode_data) {char * command_line; +unsigned long cmd_line_ptr;memcpy (&boot_params, real_mode_data,sizeof boot_params); -if (boot_params.hdr.cmd_line_ptr) { - command_line =__va (boot_params.hdr.cmd_line_ptr); + cmd_line_ptr =get_cmd_line_ptr (); +if (cmd_line_ptr) { + command_line =__va (cmd_line_ptr);memcpy (boot_command_line, command_line,COMMAND_LINE_SIZE ); } }
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, boot: Add get_cmd_line_ptr()
Commit-ID: f1da834cd902f5e5df0b11a3948fc43c6071b590 Gitweb: http://git.kernel.org/tip/f1da834cd902f5e5df0b11a3948fc43c6071b590 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:57 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:25:45 -0800
x86, boot: Add get_cmd_line_ptr()
Add an accessor function for the command line address.
Later we will add support for holding a 64-bit address via ext_cmd_line_ptr.
--- arch/x86/boot/compressed/cmdline.c | 10 ++++++++-- arch/x86/kernel/head64.c | 13 +++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-)
arch/x86/boot/compressed/cmdline.c +8 -2
@@ -13,13 +13,19 @@ static inline char rdfs8(addr_t addr) return *((char *)(fs + addr)); }#include "../cmdline.c" +static unsigned long get_cmd_line_ptr (void ) +{ +unsigned long cmd_line_ptr = real_mode->hdr.cmd_line_ptr; + +return cmd_line_ptr; +}int cmdline_find_option (const char *option,char *buffer,int bufsize) { -return __cmdline_find_option (real_mode->hdr.cmd_line_ptr, option, buffer, bufsize); +return __cmdline_find_option (get_cmd_line_ptr (), option, buffer, bufsize); }int cmdline_find_option_bool (const char *option) { -return __cmdline_find_option_bool (real_mode->hdr.cmd_line_ptr, option); +return __cmdline_find_option_bool (get_cmd_line_ptr (), option); }#endif
arch/x86/kernel/head64.c +11 -2
@@ -112,14 +112,23 @@ static void __init clear_bss(void) (unsigned long) __bss_stop - (unsigned long) __bss_start); } +static unsigned long get_cmd_line_ptr (void ) +{ +unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + +return cmd_line_ptr; +} +static void __init copy_bootdata (char *real_mode_data) {char * command_line; +unsigned long cmd_line_ptr;memcpy (&boot_params, real_mode_data,sizeof boot_params);sanitize_boot_params (&boot_params); -if (boot_params.hdr.cmd_line_ptr) { - command_line =__va (boot_params.hdr.cmd_line_ptr); + cmd_line_ptr =get_cmd_line_ptr (); +if (cmd_line_ptr) { + command_line =__va (cmd_line_ptr);memcpy (boot_command_line, command_line,COMMAND_LINE_SIZE ); } }
PATCH 17/35 x86, boot: Move checking of cmd_line_ptr out of common path
In reply to Yinghai Lucmdline.c::__cmdline_find_option... are shared between 16-bit setup code and 32/64 bit decompressor code.
for 32/64 only path via kexec, we should not check if ptr is less 1M. as those cmdline could be put above 1M, or even 4G.
Move out accessible checking out of __cmdline_find_option() So decompressor in misc.c can parse cmdline correctly.
--- arch/x86/boot/boot.h | 14 ++++++++++++-- arch/x86/boot/cmdline.c | 8 ++++---- 2 files changed, 16 insertions(+), 6 deletions(-)
arch/x86/boot/boot.h +12 -2
@@ -289,12 +289,22 @@ int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, intint __cmdline_find_option_bool (u32 cmdline_ptr,const char *option);static inline int cmdline_find_option (const char *option,char *buffer,int bufsize) { -return __cmdline_find_option (boot_params.hdr.cmd_line_ptr, option, buffer, bufsize); +u32 cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + +if (cmd_line_ptr >=0x100000 ) +return -1 ;/* inaccessible */ + +return __cmdline_find_option (cmd_line_ptr, option, buffer, bufsize); }static inline int cmdline_find_option_bool (const char *option) { -return __cmdline_find_option_bool (boot_params.hdr.cmd_line_ptr, option); +u32 cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + +if (cmd_line_ptr >=0x100000 ) +return -1 ;/* inaccessible */ + +return __cmdline_find_option_bool (cmd_line_ptr, option); }
arch/x86/boot/cmdline.c +4 -4
@@ -41,8 +41,8 @@ int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int st_bufcpy /* Copying this to buffer */ } state = st_wordstart; -if (!cmdline_ptr || cmdline_ptr >=0x100000 ) -return -1 ;/* No command line, or inaccessible */ +if (!cmdline_ptr) +return -1 ;/* No command line */ cptr = cmdline_ptr &0xf ;set_fs (cmdline_ptr >>4 );
@@ -111,8 +111,8 @@ int __cmdline_find_option_bool(u32 cmdline_ptr, const char *option) st_wordskip,/* Miscompare, skip */ } state = st_wordstart; -if (!cmdline_ptr || cmdline_ptr >=0x100000 ) -return -1 ;/* No command line, or inaccessible */ +if (!cmdline_ptr) +return -1 ;/* No command line */ cptr = cmdline_ptr &0xf ;set_fs (cmdline_ptr >>4 );
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, boot: Move checking of cmd_line_ptr out of common path
Commit-ID: 16a4baa642cf448742aaf150c4daa093f9dbebbb Gitweb: http://git.kernel.org/tip/16a4baa642cf448742aaf150c4daa093f9dbebbb Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:58 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:26:01 -0800
x86, boot: Move checking of cmd_line_ptr out of common path
cmdline.c::__cmdline_find_option... are shared between 16-bit setup code and 32/64 bit decompressor code.
for 32/64 only path via kexec, we should not check if ptr is less 1M. as those cmdline could be put above 1M, or even 4G.
Move out accessible checking out of __cmdline_find_option() So decompressor in misc.c can parse cmdline correctly.
--- arch/x86/boot/boot.h | 14 ++++++++++++-- arch/x86/boot/cmdline.c | 8 ++++---- 2 files changed, 16 insertions(+), 6 deletions(-)
arch/x86/boot/boot.h +12 -2
@@ -289,12 +289,22 @@ int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, intint __cmdline_find_option_bool (u32 cmdline_ptr,const char *option);static inline int cmdline_find_option (const char *option,char *buffer,int bufsize) { -return __cmdline_find_option (boot_params.hdr.cmd_line_ptr, option, buffer, bufsize); +u32 cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + +if (cmd_line_ptr >=0x100000 ) +return -1 ;/* inaccessible */ + +return __cmdline_find_option (cmd_line_ptr, option, buffer, bufsize); }static inline int cmdline_find_option_bool (const char *option) { -return __cmdline_find_option_bool (boot_params.hdr.cmd_line_ptr, option); +u32 cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + +if (cmd_line_ptr >=0x100000 ) +return -1 ;/* inaccessible */ + +return __cmdline_find_option_bool (cmd_line_ptr, option); }
arch/x86/boot/cmdline.c +4 -4
@@ -41,8 +41,8 @@ int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int st_bufcpy /* Copying this to buffer */ } state = st_wordstart; -if (!cmdline_ptr || cmdline_ptr >=0x100000 ) -return -1 ;/* No command line, or inaccessible */ +if (!cmdline_ptr) +return -1 ;/* No command line */ cptr = cmdline_ptr &0xf ;set_fs (cmdline_ptr >>4 );
@@ -111,8 +111,8 @@ int __cmdline_find_option_bool(u32 cmdline_ptr, const char *option) st_wordskip,/* Miscompare, skip */ } state = st_wordstart; -if (!cmdline_ptr || cmdline_ptr >=0x100000 ) -return -1 ;/* No command line, or inaccessible */ +if (!cmdline_ptr) +return -1 ;/* No command line */ cptr = cmdline_ptr &0xf ;set_fs (cmdline_ptr >>4 );
PATCH 18/35 x86, boot: Pass cmd_line_ptr with unsigned long instead
In reply to Yinghai Luboot/compressed/misc.c is used for bzImage in 64bit and 32bit, and cmd_line_ptr could point to buffer that is above 4g, cmd_line_ptr should be 64bit otherwise high 32bit will be capped out.
So need to change data type to unsigned long, that will be 64bit get correct address of command line buffer.
And it is still ok with 32bit bzImage, because unsigned long on 32bit kernel is still 32bit.
--- arch/x86/boot/boot.h | 8 ++++---- arch/x86/boot/cmdline.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-)
arch/x86/boot/boot.h +4 -4
@@ -285,11 +285,11 @@ struct biosregs {void intcall (u8 int_no,const struct biosregs *ireg,struct biosregs *oreg);/* cmdline.c */ -int __cmdline_find_option (u32 cmdline_ptr,const char *option,char *buffer,int bufsize); -int __cmdline_find_option_bool (u32 cmdline_ptr,const char *option); +int __cmdline_find_option (unsigned long cmdline_ptr,const char *option,char *buffer,int bufsize); +int __cmdline_find_option_bool (unsigned long cmdline_ptr,const char *option);static inline int cmdline_find_option (const char *option,char *buffer,int bufsize) { -u32 cmd_line_ptr = boot_params.hdr.cmd_line_ptr; +unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr;if (cmd_line_ptr >=0x100000 )return -1 ;/* inaccessible */
@@ -299,7 +299,7 @@ static inline int cmdline_find_option(const char *option, char *buffer, int bufsstatic inline int cmdline_find_option_bool (const char *option) { -u32 cmd_line_ptr = boot_params.hdr.cmd_line_ptr; +unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr;if (cmd_line_ptr >=0x100000 )return -1 ;/* inaccessible */
arch/x86/boot/cmdline.c +2 -2
@@ -27,7 +27,7 @@ static inline int myisspace(u8 c)* Returns the length of the argument (regardless of if it was * truncated to fit in the buffer), or -1 on not found. */ -int __cmdline_find_option (u32 cmdline_ptr,const char *option,char *buffer,int bufsize) +int __cmdline_find_option (unsigned long cmdline_ptr,const char *option,char *buffer,int bufsize) {addr_t cptr;char c;
@@ -99,7 +99,7 @@ int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int* Returns the position of that option (starts counting with 1) * or 0 on not found */ -int __cmdline_find_option_bool (u32 cmdline_ptr,const char *option) +int __cmdline_find_option_bool (unsigned long cmdline_ptr,const char *option) {addr_t cptr;char c;
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, boot: Pass cmd_line_ptr with unsigned long instead
Commit-ID: 3db07e70f0b4742f8daeda5c4aa8fbe7aeb3799e Gitweb: http://git.kernel.org/tip/3db07e70f0b4742f8daeda5c4aa8fbe7aeb3799e Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:19:59 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:26:09 -0800
x86, boot: Pass cmd_line_ptr with unsigned long instead
boot/compressed/misc.c is used for bzImage in 64bit and 32bit, and cmd_line_ptr could point to buffer that is above 4g, cmd_line_ptr should be 64bit otherwise high 32bit will be capped out.
So need to change data type to unsigned long, that will be 64bit get correct address of command line buffer.
And it is still ok with 32bit bzImage, because unsigned long on 32bit kernel is still 32bit.
--- arch/x86/boot/boot.h | 8 ++++---- arch/x86/boot/cmdline.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-)
arch/x86/boot/boot.h +4 -4
@@ -285,11 +285,11 @@ struct biosregs {void intcall (u8 int_no,const struct biosregs *ireg,struct biosregs *oreg);/* cmdline.c */ -int __cmdline_find_option (u32 cmdline_ptr,const char *option,char *buffer,int bufsize); -int __cmdline_find_option_bool (u32 cmdline_ptr,const char *option); +int __cmdline_find_option (unsigned long cmdline_ptr,const char *option,char *buffer,int bufsize); +int __cmdline_find_option_bool (unsigned long cmdline_ptr,const char *option);static inline int cmdline_find_option (const char *option,char *buffer,int bufsize) { -u32 cmd_line_ptr = boot_params.hdr.cmd_line_ptr; +unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr;if (cmd_line_ptr >=0x100000 )return -1 ;/* inaccessible */
@@ -299,7 +299,7 @@ static inline int cmdline_find_option(const char *option, char *buffer, int bufsstatic inline int cmdline_find_option_bool (const char *option) { -u32 cmd_line_ptr = boot_params.hdr.cmd_line_ptr; +unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr;if (cmd_line_ptr >=0x100000 )return -1 ;/* inaccessible */
arch/x86/boot/cmdline.c +2 -2
@@ -27,7 +27,7 @@ static inline int myisspace(u8 c)* Returns the length of the argument (regardless of if it was * truncated to fit in the buffer), or -1 on not found. */ -int __cmdline_find_option (u32 cmdline_ptr,const char *option,char *buffer,int bufsize) +int __cmdline_find_option (unsigned long cmdline_ptr,const char *option,char *buffer,int bufsize) {addr_t cptr;char c;
@@ -99,7 +99,7 @@ int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int* Returns the position of that option (starts counting with 1) * or 0 on not found */ -int __cmdline_find_option_bool (u32 cmdline_ptr,const char *option) +int __cmdline_find_option_bool (unsigned long cmdline_ptr,const char *option) {addr_t cptr;char c;
PATCH 19/35 x86, boot: Move verify_cpu.S and no_longmode down
In reply to Yinghai LuWe need to move some code to 32bit section in following patch:
x86, boot: Move lldt/ltr out of 64bit code section
but that will push startup_64 down from 0x200.
According to hpa, we can not change startup_64 position and that is an ABI.
We could move function verify_cpu and no_longmode down, because verify_cpu is used via function call and no_longmode will not return, then we don't need to add extra code for jumping back.
--- arch/x86/boot/compressed/head_64.S | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
arch/x86/boot/compressed/head_64.S +9 -8
@@ -176,14 +176,6 @@ ENTRY(startup_32) lret ENDPROC(startup_32) -no_longmode: - /* This isn't an x86-64 CPU so hang */ -1: - hlt - jmp 1b - -#include "../../kernel/verify_cpu.S" - /* * Be careful here startup_64 needs to be at a predictable * address so I can export it in an ELF header. Bootloaders
@@ -349,6 +341,15 @@ relocated: */ jmp *%rbp + .code32 +no_longmode: + /* This isn't an x86-64 CPU so hang */ +1: + hlt + jmp 1b + +#include "../../kernel/verify_cpu.S" + .data gdt: .word gdt_end - gdt
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, boot: Move verify_cpu.S and no_longmode down
Commit-ID: 187a8a73cee295b9407de0d6bfba65471a1f39d6 Gitweb: http://git.kernel.org/tip/187a8a73cee295b9407de0d6bfba65471a1f39d6 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:00 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:26:15 -0800
x86, boot: Move verify_cpu.S and no_longmode down
We need to move some code to 32bit section in following patch:
x86, boot: Move lldt/ltr out of 64bit code section
but that will push startup_64 down from 0x200.
According to hpa, we can not change startup_64 position and that is an ABI.
We could move function verify_cpu and no_longmode down, because verify_cpu is used via function call and no_longmode will not return, then we don't need to add extra code for jumping back.
--- arch/x86/boot/compressed/head_64.S | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
arch/x86/boot/compressed/head_64.S +9 -8
@@ -176,14 +176,6 @@ ENTRY(startup_32) lret ENDPROC(startup_32) -no_longmode: - /* This isn't an x86-64 CPU so hang */ -1: - hlt - jmp 1b - -#include "../../kernel/verify_cpu.S" - /* * Be careful here startup_64 needs to be at a predictable * address so I can export it in an ELF header. Bootloaders
@@ -349,6 +341,15 @@ relocated: */ jmp *%rbp + .code32 +no_longmode: + /* This isn't an x86-64 CPU so hang */ +1: + hlt + jmp 1b + +#include "../../kernel/verify_cpu.S" + .data gdt: .word gdt_end - gdt
PATCH 20/35 x86, boot: Move lldt/ltr out of 64bit code section
In reply to Yinghai Lucommit 08da5a2ca
x86_64: Early segment setup for VT
sets up LDT and TR into a valid state in order to speed up boot decompression under VT.
Those code are put in code64, and it is using GDT that is only loaded from code32 path.
That breaks booting with 64bit bootloader that does not go through code32 path and jump to startup_64 directly, and it has different GDT.
Move those lines into code32 after their GDT is loaded.
--- arch/x86/boot/compressed/head_64.S | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
arch/x86/boot/compressed/head_64.S +6 -3
@@ -154,6 +154,12 @@ ENTRY(startup_32) btsl $_EFER_LME, %eax wrmsr + /* After gdt is loaded */ + xorl %eax, %eax + lldt %ax + movl $0x20, %eax + ltr %ax + /* * Setup for the jump to 64bit mode *
@@ -239,9 +245,6 @@ preferred_addr: movl %eax, %ss movl %eax, %fs movl %eax, %gs - lldt %ax - movl $0x20, %eax - ltr %ax /* * Compute the decompressed kernel start address. It is where
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, boot: Move lldt/ltr out of 64bit code section
Commit-ID: d3c433bf9a01b6951286ec2cbf52e3549623d878 Gitweb: http://git.kernel.org/tip/d3c433bf9a01b6951286ec2cbf52e3549623d878 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:01 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:26:19 -0800
x86, boot: Move lldt/ltr out of 64bit code section
commit 08da5a2ca
x86_64: Early segment setup for VT
sets up LDT and TR into a valid state in order to speed up boot decompression under VT.
Those code are put in code64, and it is using GDT that is only loaded from code32 path.
That breaks booting with 64bit bootloader that does not go through code32 path and jump to startup_64 directly, and it has different GDT.
Move those lines into code32 after their GDT is loaded.
--- arch/x86/boot/compressed/head_64.S | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
arch/x86/boot/compressed/head_64.S +6 -3
@@ -154,6 +154,12 @@ ENTRY(startup_32) btsl $_EFER_LME, %eax wrmsr + /* After gdt is loaded */ + xorl %eax, %eax + lldt %ax + movl $0x20, %eax + ltr %ax + /* * Setup for the jump to 64bit mode *
@@ -239,9 +245,6 @@ preferred_addr: movl %eax, %ss movl %eax, %fs movl %eax, %gs - lldt %ax - movl $0x20, %eax - ltr %ax /* * Compute the decompressed kernel start address. It is where
PATCH 21/35 x86, kexec: Remove 1024G limitation for kexec buffer on 64bit
In reply to Yinghai LuNow 64bit kernel supports more than 1T ram and kexec tools could find buffer above 1T, remove that obsolete limitation. and use MAXMEM instead.
Tested on system with more than 1024G ram.
--- arch/x86/include/asm/kexec.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/include/asm/kexec.h +3 -3
@@ -48,11 +48,11 @@# define vmcore_elf_check_arch_cross (x) ((x)->e_machine == EM_X86_64)#else /* Maximum physical address we can use pages from */ -# define KEXEC_SOURCE_MEMORY_LIMIT (0xFFFFFFFFFFUL) +# define KEXEC_SOURCE_MEMORY_LIMIT (MAXMEM-1)/* Maximum address we can reach in physical address mode */ -# define KEXEC_DESTINATION_MEMORY_LIMIT (0xFFFFFFFFFFUL) +# define KEXEC_DESTINATION_MEMORY_LIMIT (MAXMEM-1)/* Maximum address we can use for the control pages */ -# define KEXEC_CONTROL_MEMORY_LIMIT (0xFFFFFFFFFFUL) +# define KEXEC_CONTROL_MEMORY_LIMIT (MAXMEM-1)/* Allocate one page for the pdp and the second for the code */ # define KEXEC_CONTROL_PAGE_SIZE (4096UL + 4096UL)
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, kexec: Remove 1024G limitation for kexec buffer on 64bit
Commit-ID: 577af55d802d9fe114287e750504e09e7c677c9c Gitweb: http://git.kernel.org/tip/577af55d802d9fe114287e750504e09e7c677c9c Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:02 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:26:23 -0800
x86, kexec: Remove 1024G limitation for kexec buffer on 64bit
Now 64bit kernel supports more than 1T ram and kexec tools could find buffer above 1T, remove that obsolete limitation. and use MAXMEM instead.
Tested on system with more than 1024G ram.
--- arch/x86/include/asm/kexec.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/include/asm/kexec.h +3 -3
@@ -48,11 +48,11 @@# define vmcore_elf_check_arch_cross (x) ((x)->e_machine == EM_X86_64)#else /* Maximum physical address we can use pages from */ -# define KEXEC_SOURCE_MEMORY_LIMIT (0xFFFFFFFFFFUL) +# define KEXEC_SOURCE_MEMORY_LIMIT (MAXMEM-1)/* Maximum address we can reach in physical address mode */ -# define KEXEC_DESTINATION_MEMORY_LIMIT (0xFFFFFFFFFFUL) +# define KEXEC_DESTINATION_MEMORY_LIMIT (MAXMEM-1)/* Maximum address we can use for the control pages */ -# define KEXEC_CONTROL_MEMORY_LIMIT (0xFFFFFFFFFFUL) +# define KEXEC_CONTROL_MEMORY_LIMIT (MAXMEM-1)/* Allocate one page for the pdp and the second for the code */ # define KEXEC_CONTROL_PAGE_SIZE (4096UL + 4096UL)
PATCH 22/35 x86, kexec: Set ident mapping for kernel that is above max_pfn
In reply to Yinghai LuWhen first kernel is booted with memmap= or mem= to limit max_pfn. kexec can load second kernel above that max_pfn.
We need to set ident mapping for whole image in this case instead of just for first 2M.
--- arch/x86/kernel/machine_kexec_64.c | 43 +++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-)
arch/x86/kernel/machine_kexec_64.c +37 -6
@@ -56,6 +56,25 @@ out:return result; } +static int ident_mapping_init (struct kimage *image,pgd_t *level4p, +unsigned long mstart,unsigned long mend) +{ +int result; + + mstart =round_down (mstart,PMD_SIZE ); + mend =round_up (mend -1 ,PMD_SIZE ); + +while (mstart < mend) { + result =init_one_level2_page (image, level4p, mstart); +if (result) +return result; + + mstart +=PMD_SIZE ; + } + +return 0 ; +} +static void init_level2_page (pmd_t *level2p,unsigned long addr) {unsigned long end_addr;
@@ -184,22 +203,34 @@ err:return result; } -static int init_pgtable (struct kimage *image,unsigned long start_pgtable) { +unsigned long mstart, mend;pgd_t *level4p;int result; +int i; + level4p = (pgd_t *)__va (start_pgtable); result =init_level4_page (image, level4p,0 , max_pfn <<PAGE_SHIFT );if (result)return result; +/* -* image->start may be outside 0 ~ max_pfn, for example when -* jump back to original kernel from kexeced kernel +* segments's mem ranges could be outside 0 ~ max_pfn, +* for example when jump back to original kernel from kexeced kernel. +* or first kernel is booted with user mem map, and second kernel +* could be loaded out of that range. */ - result =init_one_level2_page (image, level4p, image->start); -if (result) -return result; +for (i =0 ; i < image->nr_segments; i++) { + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + + result =ident_mapping_init (image, level4p, mstart, mend); + +if (result) +return result; + } +return init_transition_pgtable (image, level4p); }
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, kexec: Set ident mapping for kernel that is above max_pfn
Commit-ID: 084d1283986a530828b8898f206adf44d5d3146d Gitweb: http://git.kernel.org/tip/084d1283986a530828b8898f206adf44d5d3146d Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:03 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:26:26 -0800
x86, kexec: Set ident mapping for kernel that is above max_pfn
When first kernel is booted with memmap= or mem= to limit max_pfn. kexec can load second kernel above that max_pfn.
We need to set ident mapping for whole image in this case instead of just for first 2M.
--- arch/x86/kernel/machine_kexec_64.c | 43 ++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-)
arch/x86/kernel/machine_kexec_64.c +37 -6
@@ -56,6 +56,25 @@ out:return result; } +static int ident_mapping_init (struct kimage *image,pgd_t *level4p, +unsigned long mstart,unsigned long mend) +{ +int result; + + mstart =round_down (mstart,PMD_SIZE ); + mend =round_up (mend -1 ,PMD_SIZE ); + +while (mstart < mend) { + result =init_one_level2_page (image, level4p, mstart); +if (result) +return result; + + mstart +=PMD_SIZE ; + } + +return 0 ; +} +static void init_level2_page (pmd_t *level2p,unsigned long addr) {unsigned long end_addr;
@@ -184,22 +203,34 @@ err:return result; } -static int init_pgtable (struct kimage *image,unsigned long start_pgtable) { +unsigned long mstart, mend;pgd_t *level4p;int result; +int i; + level4p = (pgd_t *)__va (start_pgtable); result =init_level4_page (image, level4p,0 , max_pfn <<PAGE_SHIFT );if (result)return result; +/* -* image->start may be outside 0 ~ max_pfn, for example when -* jump back to original kernel from kexeced kernel +* segments's mem ranges could be outside 0 ~ max_pfn, +* for example when jump back to original kernel from kexeced kernel. +* or first kernel is booted with user mem map, and second kernel +* could be loaded out of that range. */ - result =init_one_level2_page (image, level4p, image->start); -if (result) -return result; +for (i =0 ; i < image->nr_segments; i++) { + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + + result =ident_mapping_init (image, level4p, mstart, mend); + +if (result) +return result; + } +return init_transition_pgtable (image, level4p); }
PATCH 23/35 x86, kexec: Replace ident_mapping_init and init_level4_page
In reply to Yinghai LuNow ident_mapping_init is checking if pgd/pud is present for every 2M, so several 2Ms are in same PUD, it will keep checking if pud is there with same pud.
init_level4_page just does not check existing pgd/pud.
We could use generic mapping_init with different settings in info to replace those two local grown version functions.
--- arch/x86/kernel/machine_kexec_64.c | 161 ++++++------------------------------ 1 file changed, 26 insertions(+), 135 deletions(-)
arch/x86/kernel/machine_kexec_64.c +26 -135
@@ -16,144 +16,12 @@#include <linux/io.h> #include <linux/suspend.h> +#include <asm/init.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> #include <asm/mmu_context.h> #include <asm/debugreg.h> -static int init_one_level2_page (struct kimage *image,pgd_t *pgd, -unsigned long addr) -{ -pud_t *pud; -pmd_t *pmd; -struct page *page; -int result = -ENOMEM ; - - addr &=PMD_MASK ; - pgd +=pgd_index (addr); -if (!pgd_present (*pgd)) { - page =kimage_alloc_control_pages (image,0 ); -if (!page) - goto out; - pud = (pud_t *)page_address (page); -clear_page (pud); -set_pgd (pgd,__pgd (__pa (pud) | _KERNPG_TABLE)); - } - pud =pud_offset (pgd, addr); -if (!pud_present (*pud)) { - page =kimage_alloc_control_pages (image,0 ); -if (!page) - goto out; - pmd = (pmd_t *)page_address (page); -clear_page (pmd); -set_pud (pud,__pud (__pa (pmd) | _KERNPG_TABLE)); - } - pmd =pmd_offset (pud, addr); -if (!pmd_present (*pmd)) -set_pmd (pmd,__pmd (addr | __PAGE_KERNEL_LARGE_EXEC)); - result =0 ; -out: -return result; -} - -static int ident_mapping_init (struct kimage *image,pgd_t *level4p, -unsigned long mstart,unsigned long mend) -{ -int result; - - mstart =round_down (mstart,PMD_SIZE ); - mend =round_up (mend -1 ,PMD_SIZE ); - -while (mstart < mend) { - result =init_one_level2_page (image, level4p, mstart); -if (result) -return result; - - mstart +=PMD_SIZE ; - } - -return 0 ; -} - -static void init_level2_page (pmd_t *level2p,unsigned long addr) -{ -unsigned long end_addr; - - addr &=PAGE_MASK ; - end_addr = addr +PUD_SIZE ; -while (addr < end_addr) { -set_pmd (level2p++,__pmd (addr | __PAGE_KERNEL_LARGE_EXEC)); - addr +=PMD_SIZE ; - } -} - -static int init_level3_page (struct kimage *image,pud_t *level3p, -unsigned long addr,unsigned long last_addr) -{ -unsigned long end_addr; -int result; - - result =0 ; - addr &=PAGE_MASK ; - end_addr = addr +PGDIR_SIZE ; -while ((addr < last_addr) && (addr < end_addr)) { -struct page *page; -pmd_t *level2p; - - page =kimage_alloc_control_pages (image,0 ); -if (!page) { - result = -ENOMEM ; - goto out; - } - level2p = (pmd_t *)page_address (page); -init_level2_page (level2p, addr); -set_pud (level3p++,__pud (__pa (level2p) | _KERNPG_TABLE)); - addr +=PUD_SIZE ; - } -/* clear the unused entries */ -while (addr < end_addr) { -pud_clear (level3p++); - addr +=PUD_SIZE ; - } -out: -return result; -} - - -static int init_level4_page (struct kimage *image,pgd_t *level4p, -unsigned long addr,unsigned long last_addr) -{ -unsigned long end_addr; -int result; - - result =0 ; - addr &=PAGE_MASK ; - end_addr = addr + (PTRS_PER_PGD *PGDIR_SIZE ); -while ((addr < last_addr) && (addr < end_addr)) { -struct page *page; -pud_t *level3p; - - page =kimage_alloc_control_pages (image,0 ); -if (!page) { - result = -ENOMEM ; - goto out; - } - level3p = (pud_t *)page_address (page); - result =init_level3_page (image, level3p, addr, last_addr); -if (result) - goto out; -set_pgd (level4p++,__pgd (__pa (level3p) | _KERNPG_TABLE)); - addr +=PGDIR_SIZE ; - } -/* clear the unused entries */ -while (addr < end_addr) { -pgd_clear (level4p++); - addr +=PGDIR_SIZE ; - } -out: -return result; -} -static void free_transition_pgtable (struct kimage *image) {free_page ((unsigned long )image->arch.pud);
@@ -203,15 +71,37 @@ err:return result; } +static void *alloc_pgt_page (void *data) +{ +struct kimage *image = (struct kimage *)data; +struct page *page; +void *p =NULL ; + + page =kimage_alloc_control_pages (image,0 ); +if (page) { + p =page_address (page); +clear_page (p); + } + +return p; +} +static int init_pgtable (struct kimage *image,unsigned long start_pgtable) { +struct x86_mapping_info info = { + .alloc_pgt_page = alloc_pgt_page, + .context = image, + .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, + };unsigned long mstart, mend;pgd_t *level4p;int result;int i; level4p = (pgd_t *)__va (start_pgtable); - result =init_level4_page (image, level4p,0 , max_pfn <<PAGE_SHIFT ); +clear_page (level4p); + result =kernel_ident_mapping_init (&info, level4p, +0 , max_pfn <<PAGE_SHIFT );if (result)return result;
@@ -225,7 +115,8 @@ static int init_pgtable(struct kimage *image, unsigned long start_pgtable) mstart = image->segment[i].mem; mend = mstart + image->segment[i].memsz; - result =ident_mapping_init (image, level4p, mstart, mend); + result =kernel_ident_mapping_init (&info, + level4p, mstart, mend);if (result)return result;
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, kexec: Replace ident_mapping_init and init_level4_page
Commit-ID: 9ebdc79f7a177d3098b89ba8ef2dd2b235163685 Gitweb: http://git.kernel.org/tip/9ebdc79f7a177d3098b89ba8ef2dd2b235163685 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:04 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:26:29 -0800
x86, kexec: Replace ident_mapping_init and init_level4_page
Now ident_mapping_init is checking if pgd/pud is present for every 2M, so several 2Ms are in same PUD, it will keep checking if pud is there with same pud.
init_level4_page just does not check existing pgd/pud.
We could use generic mapping_init with different settings in info to replace those two local grown version functions.
--- arch/x86/kernel/machine_kexec_64.c | 161 ++++++------------------------------- 1 file changed, 26 insertions(+), 135 deletions(-)
arch/x86/kernel/machine_kexec_64.c +26 -135
@@ -16,144 +16,12 @@#include <linux/io.h> #include <linux/suspend.h> +#include <asm/init.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> #include <asm/mmu_context.h> #include <asm/debugreg.h> -static int init_one_level2_page (struct kimage *image,pgd_t *pgd, -unsigned long addr) -{ -pud_t *pud; -pmd_t *pmd; -struct page *page; -int result = -ENOMEM ; - - addr &=PMD_MASK ; - pgd +=pgd_index (addr); -if (!pgd_present (*pgd)) { - page =kimage_alloc_control_pages (image,0 ); -if (!page) - goto out; - pud = (pud_t *)page_address (page); -clear_page (pud); -set_pgd (pgd,__pgd (__pa (pud) | _KERNPG_TABLE)); - } - pud =pud_offset (pgd, addr); -if (!pud_present (*pud)) { - page =kimage_alloc_control_pages (image,0 ); -if (!page) - goto out; - pmd = (pmd_t *)page_address (page); -clear_page (pmd); -set_pud (pud,__pud (__pa (pmd) | _KERNPG_TABLE)); - } - pmd =pmd_offset (pud, addr); -if (!pmd_present (*pmd)) -set_pmd (pmd,__pmd (addr | __PAGE_KERNEL_LARGE_EXEC)); - result =0 ; -out: -return result; -} - -static int ident_mapping_init (struct kimage *image,pgd_t *level4p, -unsigned long mstart,unsigned long mend) -{ -int result; - - mstart =round_down (mstart,PMD_SIZE ); - mend =round_up (mend -1 ,PMD_SIZE ); - -while (mstart < mend) { - result =init_one_level2_page (image, level4p, mstart); -if (result) -return result; - - mstart +=PMD_SIZE ; - } - -return 0 ; -} - -static void init_level2_page (pmd_t *level2p,unsigned long addr) -{ -unsigned long end_addr; - - addr &=PAGE_MASK ; - end_addr = addr +PUD_SIZE ; -while (addr < end_addr) { -set_pmd (level2p++,__pmd (addr | __PAGE_KERNEL_LARGE_EXEC)); - addr +=PMD_SIZE ; - } -} - -static int init_level3_page (struct kimage *image,pud_t *level3p, -unsigned long addr,unsigned long last_addr) -{ -unsigned long end_addr; -int result; - - result =0 ; - addr &=PAGE_MASK ; - end_addr = addr +PGDIR_SIZE ; -while ((addr < last_addr) && (addr < end_addr)) { -struct page *page; -pmd_t *level2p; - - page =kimage_alloc_control_pages (image,0 ); -if (!page) { - result = -ENOMEM ; - goto out; - } - level2p = (pmd_t *)page_address (page); -init_level2_page (level2p, addr); -set_pud (level3p++,__pud (__pa (level2p) | _KERNPG_TABLE)); - addr +=PUD_SIZE ; - } -/* clear the unused entries */ -while (addr < end_addr) { -pud_clear (level3p++); - addr +=PUD_SIZE ; - } -out: -return result; -} - - -static int init_level4_page (struct kimage *image,pgd_t *level4p, -unsigned long addr,unsigned long last_addr) -{ -unsigned long end_addr; -int result; - - result =0 ; - addr &=PAGE_MASK ; - end_addr = addr + (PTRS_PER_PGD *PGDIR_SIZE ); -while ((addr < last_addr) && (addr < end_addr)) { -struct page *page; -pud_t *level3p; - - page =kimage_alloc_control_pages (image,0 ); -if (!page) { - result = -ENOMEM ; - goto out; - } - level3p = (pud_t *)page_address (page); - result =init_level3_page (image, level3p, addr, last_addr); -if (result) - goto out; -set_pgd (level4p++,__pgd (__pa (level3p) | _KERNPG_TABLE)); - addr +=PGDIR_SIZE ; - } -/* clear the unused entries */ -while (addr < end_addr) { -pgd_clear (level4p++); - addr +=PGDIR_SIZE ; - } -out: -return result; -} -static void free_transition_pgtable (struct kimage *image) {free_page ((unsigned long )image->arch.pud);
@@ -203,15 +71,37 @@ err:return result; } +static void *alloc_pgt_page (void *data) +{ +struct kimage *image = (struct kimage *)data; +struct page *page; +void *p =NULL ; + + page =kimage_alloc_control_pages (image,0 ); +if (page) { + p =page_address (page); +clear_page (p); + } + +return p; +} +static int init_pgtable (struct kimage *image,unsigned long start_pgtable) { +struct x86_mapping_info info = { + .alloc_pgt_page = alloc_pgt_page, + .context = image, + .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, + };unsigned long mstart, mend;pgd_t *level4p;int result;int i; level4p = (pgd_t *)__va (start_pgtable); - result =init_level4_page (image, level4p,0 , max_pfn <<PAGE_SHIFT ); +clear_page (level4p); + result =kernel_ident_mapping_init (&info, level4p, +0 , max_pfn <<PAGE_SHIFT );if (result)return result;
@@ -225,7 +115,8 @@ static int init_pgtable(struct kimage *image, unsigned long start_pgtable) mstart = image->segment[i].mem; mend = mstart + image->segment[i].memsz; - result =ident_mapping_init (image, level4p, mstart, mend); + result =kernel_ident_mapping_init (&info, + level4p, mstart, mend);if (result)return result;
PATCH 24/35 x86, kexec, 64bit: Only set ident mapping for ram.
In reply to Yinghai LuWe should set mappings only for usable memory ranges under max_pfn Otherwise causes same problem that is fixed by
x86, mm: Only direct map addresses that are marked as E820_RAM
This patch exposes pfn_mapped array, and only sets ident mapping for ranges in that array.
This patch relies on new kernel_ident_mapping_init that could handle existing pgd/pud between different calls.
--- arch/x86/include/asm/page.h | 4 ++++ arch/x86/kernel/machine_kexec_64.c | 13 +++++++++---- arch/x86/mm/init.c | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-)
arch/x86/include/asm/page.h +4 -0
@@ -17,6 +17,10 @@struct page ; +#include <linux/range.h> +extern struct range pfn_mapped[]; +extern int nr_pfn_mapped; +static inline void clear_user_page (void *page,unsigned long vaddr,struct page *pg) {
arch/x86/kernel/machine_kexec_64.c +9 -4
@@ -100,10 +100,15 @@ static int init_pgtable(struct kimage *image, unsigned long start_pgtable) level4p = (pgd_t *)__va (start_pgtable);clear_page (level4p); - result =kernel_ident_mapping_init (&info, level4p, -0 , max_pfn <<PAGE_SHIFT ); -if (result) -return result; +for (i =0 ; i < nr_pfn_mapped; i++) { + mstart = pfn_mapped[i].start <<PAGE_SHIFT ; + mend = pfn_mapped[i].end <<PAGE_SHIFT ; + + result =kernel_ident_mapping_init (&info, + level4p, mstart, mend); +if (result) +return result; + }/* * segments's mem ranges could be outside 0 ~ max_pfn,
arch/x86/mm/init.c +2 -2
@@ -302,8 +302,8 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range,return nr_range; } -static struct range pfn_mapped[E820_X_MAX ]; -static int nr_pfn_mapped; +struct range pfn_mapped[E820_X_MAX ]; +int nr_pfn_mapped;static void add_pfn_range_mapped (unsigned long start_pfn,unsigned long end_pfn) {
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, kexec, 64bit: Only set ident mapping for ram.
Commit-ID: 0e691cf824f76adefb4498fe39c300aba2c2575a Gitweb: http://git.kernel.org/tip/0e691cf824f76adefb4498fe39c300aba2c2575a Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:05 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:26:35 -0800
x86, kexec, 64bit: Only set ident mapping for ram.
We should set mappings only for usable memory ranges under max_pfn Otherwise causes same problem that is fixed by
x86, mm: Only direct map addresses that are marked as E820_RAM
This patch exposes pfn_mapped array, and only sets ident mapping for ranges in that array.
This patch relies on new kernel_ident_mapping_init that could handle existing pgd/pud between different calls.
--- arch/x86/include/asm/page.h | 4 ++++ arch/x86/kernel/machine_kexec_64.c | 13 +++++++++---- arch/x86/mm/init.c | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-)
arch/x86/include/asm/page.h +4 -0
@@ -17,6 +17,10 @@struct page ; +#include <linux/range.h> +extern struct range pfn_mapped[]; +extern int nr_pfn_mapped; +static inline void clear_user_page (void *page,unsigned long vaddr,struct page *pg) {
arch/x86/kernel/machine_kexec_64.c +9 -4
@@ -100,10 +100,15 @@ static int init_pgtable(struct kimage *image, unsigned long start_pgtable) level4p = (pgd_t *)__va (start_pgtable);clear_page (level4p); - result =kernel_ident_mapping_init (&info, level4p, -0 , max_pfn <<PAGE_SHIFT ); -if (result) -return result; +for (i =0 ; i < nr_pfn_mapped; i++) { + mstart = pfn_mapped[i].start <<PAGE_SHIFT ; + mend = pfn_mapped[i].end <<PAGE_SHIFT ; + + result =kernel_ident_mapping_init (&info, + level4p, mstart, mend); +if (result) +return result; + }/* * segments's mem ranges could be outside 0 ~ max_pfn,
arch/x86/mm/init.c +2 -2
@@ -302,8 +302,8 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range,return nr_range; } -static struct range pfn_mapped[E820_X_MAX ]; -static int nr_pfn_mapped; +struct range pfn_mapped[E820_X_MAX ]; +int nr_pfn_mapped;static void add_pfn_range_mapped (unsigned long start_pfn,unsigned long end_pfn) {
PATCH 25/35 x86, boot: Add fields to support load bzImage and ramdisk above 4G
In reply to Yinghai Luxloadflags bit0 is set if kernel is relocatable and 64bit.
bootloader will check if xloadflags bit0 is set to decicde if it could load ramdisk and kernel high above 4G.
bootloader will fill value to ext_ramdisk_image/size for high 32bits when it load ramdisk above 4G.
kernel use get_ramdisk_image/size to use ext_ramdisk_image/size to get right positon for ramdisk.
sentinel is used so kernel could find out if ext_* and other fields have valid values set in boot_params from bootloader.
Update header version to 2.12.
-v2: add ext_cmd_line_ptr for above 4G support.
-v3: update to xloadflags from HPA.
-v4: use fields from bootparam instead setup_header according to HPA. -v5: add checking for USE_EXT_BOOT_PARAMS
-v6: use sentinel to check if ext_* are valid suggested by HPA.
HPA said:
1. add a field in the uninitialized portion, call it "sentinel";
2. make sure the byte position corresponding to the "sentinel" field is nonzero in the bzImage file;
3. if the kernel boots up and sentinel is nonzero, erase those fields that you identified as uninitialized;
-v7: change to 0x1ef instead of 0x1f0, HPA said:
it is quite plausible that someone may (fairly sanely) start the copy range at 0x1f0 instead of 0x1f1
-v8: add some comments for sentinel
and clear more bits for sentinel according to HPA.
--- Documentation/x86/boot.txt | 15 ++++++++++++++- Documentation/x86/zero-page.txt | 4 ++++ arch/x86/boot/compressed/cmdline.c | 2 ++ arch/x86/boot/compressed/misc.c | 19 +++++++++++++++++++ arch/x86/boot/header.S | 12 ++++++++++-- arch/x86/boot/setup.ld | 7 +++++++ arch/x86/include/uapi/asm/bootparam.h | 24 +++++++++++++++++++++--- arch/x86/kernel/head64.c | 2 ++ arch/x86/kernel/setup.c | 4 ++++ 9 files changed, 83 insertions(+), 6 deletions(-)
Documentation/x86/boot.txt +14 -1
@@ -57,6 +57,9 @@ Protocol 2.10: (Kernel 2.6.31) Added a protocol for relaxed alignment Protocol 2.11: (Kernel 3.6) Added a field for offset of EFI handover protocol entry point. +Protocol 2.12: (Kernel 3.9) Added three fields to bootparam for loading + bzImage and ramdisk above 4G in 64bit. + **** MEMORY LAYOUT The traditional memory map for the kernel loader, used for Image or
@@ -182,7 +185,7 @@ Offset Proto Name Meaning 0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel 0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not 0235/1 2.10+ min_alignment Minimum alignment, as a power of two -0236/2 N/A pad3 Unused +0236/2 2.12+ xloadflags Boot protocol option flags 0238/4 2.06+ cmdline_size Maximum size of the kernel command line 023C/4 2.07+ hardware_subarch Hardware subarchitecture 0240/8 2.07+ hardware_subarch_data Subarchitecture-specific data
@@ -582,6 +585,16 @@ Protocol: 2.10+ misaligned kernel. Therefore, a loader should typically try each power-of-two alignment from kernel_alignment down to this alignment. +Field name: xloadflags +Type: modify (obligatory) +Offset/size: 0x236/2 +Protocol: 2.12+ + + This field is a bitmask. + + Bit 0 (read): CAN_BE_LOADED_ABOVE_4G + - If 1, kernel/boot_params/cmdline/ramdisk can be above 4G. + Field name: cmdline_size Type: read Offset/size: 0x238/4
Documentation/x86/zero-page.txt +4 -0
@@ -19,6 +19,9 @@ Offset Proto Name Meaning 090/010 ALL hd1_info hd1 disk parameter, OBSOLETE!! 0A0/010 ALL sys_desc_table System description table (struct sys_desc_table) 0B0/010 ALL olpc_ofw_header OLPC's OpenFirmware CIF and friends +0C0/004 ALL ext_ramdisk_image ramdisk_image high 32bits +0C4/004 ALL ext_ramdisk_size ramdisk_size high 32bits +0C8/004 ALL ext_cmd_line_ptr cmd_line_ptr high 32bits 140/080 ALL edid_info Video mode setup (struct edid_info) 1C0/020 ALL efi_info EFI 32 information (struct efi_info) 1E0/004 ALL alk_mem_k Alternative mem check, in KB
@@ -27,6 +30,7 @@ Offset Proto Name Meaning 1E9/001 ALL eddbuf_entries Number of entries in eddbuf (below) 1EA/001 ALL edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer (below) +1EF/001 ALL sentinel 0: states _ext_* fields are valid 290/040 ALL edd_mbr_sig_buffer EDD MBR signatures 2D0/A00 ALL e820_map E820 memory map table (array of struct e820entry)
arch/x86/boot/compressed/cmdline.c +2 -0
@@ -17,6 +17,8 @@ static unsigned long get_cmd_line_ptr(void) {unsigned long cmd_line_ptr = real_mode->hdr.cmd_line_ptr; + cmd_line_ptr |= (u64 )real_mode->ext_cmd_line_ptr <<32 ; +return cmd_line_ptr; }int cmdline_find_option (const char *option,char *buffer,int bufsize)
arch/x86/boot/compressed/misc.c +19 -0
@@ -318,6 +318,23 @@ static void parse_elf(void *output)free (phdrs); } +static void sanitize_real_mode (struct boot_params *real_mode) +{ +if (real_mode->sentinel) { +/*fields in boot_params are not valid, clear them */ +memset (&real_mode->olpc_ofw_header,0 , + (char *)&real_mode->alt_mem_k - + (char *)&real_mode->olpc_ofw_header); +memset (&real_mode->_pad7[0 ],0 , + (char *)&real_mode->edd_mbr_sig_buffer[0 ] - + (char *)&real_mode->_pad7[0 ]); +memset (&real_mode->_pad8[0 ],0 , + (char *)&real_mode->eddbuf[0 ] - + (char *)&real_mode->_pad8[0 ]); +memset (&real_mode->_pad9[0 ],0 ,sizeof (real_mode->_pad9)); + } +} + asmlinkage void decompress_kernel(void *rmode, memptr heap, unsigned char *input_data, unsigned long input_len,
@@ -325,6 +342,8 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, { real_mode = rmode; +sanitize_real_mode (real_mode); +if (real_mode->screen_info.orig_video_mode ==7 ) { vidmem = (char *)0xb0000 ; vidport =0x3b4 ;
arch/x86/boot/header.S +10 -2
@@ -279,7 +279,7 @@ _start: # Part 2 of the header, from the old setup.S .ascii "HdrS" # header signature - .word 0x020b # header version number (>= 0x0105) + .word 0x020c # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) .globl realmode_swtch realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
@@ -369,7 +369,15 @@ relocatable_kernel: .byte 1 relocatable_kernel: .byte 0 #endif min_alignment: .byte MIN_KERNEL_ALIGN_LG2 # minimum alignment -pad3: .word 0 + +xloadflags: +CAN_BE_LOADED_ABOVE_4G = 1 # If set, the kernel/boot_param/ + # ramdisk could be loaded above 4g +#if defined(CONFIG_X86_64) && defined(CONFIG_RELOCATABLE) + .word CAN_BE_LOADED_ABOVE_4G +#else + .word 0 +#endif cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, #added with boot protocol
arch/x86/boot/setup.ld +7 -0
@@ -13,6 +13,13 @@ SECTIONS .bstext : { *(.bstext) } .bsdata : { *(.bsdata) } + /* sentinel: make sure if boot_params from bootloader is right */ + . = 495; + .sentinel : { + sentinel = .; + BYTE(0xff); + } + . = 497; .header : { *(.header) } .entrytext : { *(.entrytext) }
arch/x86/include/uapi/asm/bootparam.h +21 -3
@@ -58,7 +58,9 @@ struct setup_header {__u32 initrd_addr_max;__u32 kernel_alignment;__u8 relocatable_kernel; -__u8 _pad2[3 ]; +__u8 min_alignment; +__u16 xloadflags; +#define CAN_BE_LOADED_ABOVE_4G (1<<0)__u32 cmdline_size;__u32 hardware_subarch;__u64 hardware_subarch_data;
@@ -106,7 +108,10 @@ struct boot_params {__u8 hd1_info[16 ];/* obsolete! */ /* 0x090 */ struct sys_desc_table sys_desc_table;/* 0x0a0 */ struct olpc_ofw_header olpc_ofw_header;/* 0x0b0 */ -__u8 _pad4[128 ];/* 0x0c0 */ +__u32 ext_ramdisk_image;/* 0x0c0 */ +__u32 ext_ramdisk_size;/* 0x0c4 */ +__u32 ext_cmd_line_ptr;/* 0x0c8 */ +__u8 _pad4[116 ];/* 0x0cc */ struct edid_info edid_info;/* 0x140 */ struct efi_info efi_info;/* 0x1c0 */ __u32 alt_mem_k;/* 0x1e0 */
@@ -115,7 +120,20 @@ struct boot_params {__u8 eddbuf_entries;/* 0x1e9 */ __u8 edd_mbr_sig_buf_entries;/* 0x1ea */ __u8 kbd_status;/* 0x1eb */ -__u8 _pad6[5 ];/* 0x1ec */ +__u8 _pad5[3 ];/* 0x1ec */ +/* +* The sentinel is set to 0xff via the linker script (setup.ld). +* A bootloader is supposed to only take setup_header and put +* it into a clean boot_params buffer. If it turns out that +* it is clumsy or too generous with the buffer, it most +* probably will pick up the sentinel variable too. The fact +* that this variable then is still 0xff will let kernel +* know that some variables in boot_params are invalid and +* kernel should zero out certain portions of boot_params +* (see sanitize_real_mode()). +*/ +__u8 sentinel;/* 0x1ef */ +__u8 _pad6[1 ];/* 0x1f0 */ struct setup_header hdr;/* setup header */ /* 0x1f1 */ __u8 _pad7[0x290 -0x1f1 -sizeof (struct setup_header )];__u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX ];/* 0x290 */
arch/x86/kernel/head64.c +2 -0
@@ -115,6 +115,8 @@ static unsigned long get_cmd_line_ptr(void) {unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + cmd_line_ptr |= (u64 )boot_params.ext_cmd_line_ptr <<32 ; +return cmd_line_ptr; }
arch/x86/kernel/setup.c +4 -0
@@ -298,12 +298,16 @@ static u64 __init get_ramdisk_image(void) {u64 ramdisk_image = boot_params.hdr.ramdisk_image; + ramdisk_image |= (u64 )boot_params.ext_ramdisk_image <<32 ; +return ramdisk_image; }static u64 __init get_ramdisk_size (void ) {u64 ramdisk_size = boot_params.hdr.ramdisk_size; + ramdisk_size |= (u64 )boot_params.ext_ramdisk_size <<32 ; +return ramdisk_size; }
Signature · 1 line
1.7.10.4
[tip:x86/boot] x86, boot: Define the 2.12 bzImage boot protocol
Commit-ID: 09c205afde70c15f20ca76ba0a57409dad175fd0 Gitweb: http://git.kernel.org/tip/09c205afde70c15f20ca76ba0a57409dad175fd0 Author: H. Peter Anvin <[email protected]> AuthorDate: Sun, 27 Jan 2013 10:43:28 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Sun, 27 Jan 2013 15:56:37 -0800
x86, boot: Define the 2.12 bzImage boot protocol
Define the 2.12 bzImage boot protocol: add xloadflags and additional fields to allow the command line, initramfs and struct boot_params to live above the 4 GiB mark.
The xloadflags now communicates if this is a 64-bit kernel with the legacy 64-bit entry point and which of the EFI handover entry points are supported.
Avoid adding new read flags to loadflags because of claimed bootloaders testing the whole byte for == 1 to determine bzImageness at least until the issue can be researched further.
This is based on patches by Yinghai Lu and David Woodhouse.
--- Documentation/x86/boot.txt | 27 ++++++++++++++- Documentation/x86/zero-page.txt | 4 +++ arch/x86/boot/header.S | 39 ++++++++++++++++------ arch/x86/boot/setup.ld | 2 +- arch/x86/include/uapi/asm/bootparam.h | 63 +++++++++++++++++++++++++---------- 5 files changed, 106 insertions(+), 29 deletions(-)
Documentation/x86/boot.txt +26 -1
@@ -57,6 +57,10 @@ Protocol 2.10: (Kernel 2.6.31) Added a protocol for relaxed alignment Protocol 2.11: (Kernel 3.6) Added a field for offset of EFI handover protocol entry point. +Protocol 2.12: (Kernel 3.9) Added the xloadflags field and extension fields + to struct boot_params for for loading bzImage and ramdisk + above 4G in 64bit. + **** MEMORY LAYOUT The traditional memory map for the kernel loader, used for Image or
@@ -182,7 +186,7 @@ Offset Proto Name Meaning 0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel 0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not 0235/1 2.10+ min_alignment Minimum alignment, as a power of two -0236/2 N/A pad3 Unused +0236/2 2.12+ xloadflags Boot protocol option flags 0238/4 2.06+ cmdline_size Maximum size of the kernel command line 023C/4 2.07+ hardware_subarch Hardware subarchitecture 0240/8 2.07+ hardware_subarch_data Subarchitecture-specific data
@@ -582,6 +586,27 @@ Protocol: 2.10+ misaligned kernel. Therefore, a loader should typically try each power-of-two alignment from kernel_alignment down to this alignment. +Field name: xloadflags +Type: read +Offset/size: 0x236/2 +Protocol: 2.12+ + + This field is a bitmask. + + Bit 0 (read): XLF_KERNEL_64 + - If 1, this kernel has the legacy 64-bit entry point at 0x200. + + Bit 1 (read): XLF_CAN_BE_LOADED_ABOVE_4G + - If 1, kernel/boot_params/cmdline/ramdisk can be above 4G. + + Bit 2 (read): XLF_EFI_HANDOVER_32 + - If 1, the kernel supports the 32-bit EFI handoff entry point + given at handover_offset. + + Bit 3 (read): XLF_EFI_HANDOVER_64 + - If 1, the kernel supports the 64-bit EFI handoff entry point + given at handover_offset + 0x200. + Field name: cmdline_size Type: read Offset/size: 0x238/4
Documentation/x86/zero-page.txt +4 -0
@@ -19,6 +19,9 @@ Offset Proto Name Meaning 090/010 ALL hd1_info hd1 disk parameter, OBSOLETE!! 0A0/010 ALL sys_desc_table System description table (struct sys_desc_table) 0B0/010 ALL olpc_ofw_header OLPC's OpenFirmware CIF and friends +0C0/004 ALL ext_ramdisk_image ramdisk_image high 32bits +0C4/004 ALL ext_ramdisk_size ramdisk_size high 32bits +0C8/004 ALL ext_cmd_line_ptr cmd_line_ptr high 32bits 140/080 ALL edid_info Video mode setup (struct edid_info) 1C0/020 ALL efi_info EFI 32 information (struct efi_info) 1E0/004 ALL alk_mem_k Alternative mem check, in KB
@@ -27,6 +30,7 @@ Offset Proto Name Meaning 1E9/001 ALL eddbuf_entries Number of entries in eddbuf (below) 1EA/001 ALL edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer (below) +1EF/001 ALL sentinel Used to detect broken bootloaders 290/040 ALL edd_mbr_sig_buffer EDD MBR signatures 2D0/A00 ALL e820_map E820 memory map table (array of struct e820entry)
arch/x86/boot/header.S +29 -10
@@ -21,6 +21,7 @@ #include <asm/e820.h> #include <asm/page_types.h> #include <asm/setup.h> +#include <asm/bootparam.h> #include "boot.h" #include "voffset.h" #include "zoffset.h"
@@ -255,6 +256,9 @@ section_table: # header, from the old boot sector. .section ".header", "a" + .globl sentinel +sentinel: .byte 0xff, 0xff /* Used to detect broken loaders */ + .globl hdr hdr: setup_sects: .byte 0 /* Filled in by build.c */
@@ -279,7 +283,7 @@ _start: # Part 2 of the header, from the old setup.S .ascii "HdrS" # header signature - .word 0x020b # header version number (>= 0x0105) + .word 0x020c # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) .globl realmode_swtch realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
@@ -297,13 +301,7 @@ type_of_loader: .byte 0 # 0 means ancient bootloader, newer # flags, unused bits must be zero (RFU) bit within loadflags loadflags: -LOADED_HIGH = 1 # If set, the kernel is loaded high -CAN_USE_HEAP = 0x80 # If set, the loader also has set - # heap_end_ptr to tell how much - # space behind setup.S can be used for - # heap purposes. - # Only the loader knows what is free - .byte LOADED_HIGH + .byte LOADED_HIGH # The kernel is to be loaded high setup_move_size: .word 0x8000 # size to move, when setup is not # loaded at 0x90000. We will move setup
@@ -369,7 +367,23 @@ relocatable_kernel: .byte 1 relocatable_kernel: .byte 0 #endif min_alignment: .byte MIN_KERNEL_ALIGN_LG2 # minimum alignment -pad3: .word 0 + +xloadflags: +#ifdef CONFIG_X86_64 +# define XLF0 XLF_KERNEL_64 /* 64-bit kernel */ +#else +# define XLF0 0 +#endif +#ifdef CONFIG_EFI_STUB +# ifdef CONFIG_X86_64 +# define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */ +# else +# define XLF23 XLF_EFI_HANDOVER_32 /* 32-bit EFI handover ok */ +# endif +#else +# define XLF23 0 +#endif + .word XLF0 | XLF23 cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, #added with boot protocol
@@ -397,8 +411,13 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr #define INIT_SIZE VO_INIT_SIZE #endif init_size: .long INIT_SIZE # kernel initialization size -handover_offset: .long 0x30 # offset to the handover +handover_offset: +#ifdef CONFIG_EFI_STUB + .long 0x30 # offset to the handover # protocol entry point +#else + .long 0 +#endif # End of setup header #####################################################
arch/x86/boot/setup.ld +1 -1
@@ -13,7 +13,7 @@ SECTIONS .bstext : { *(.bstext) } .bsdata : { *(.bsdata) } - . = 497; + . = 495; .header : { *(.header) } .entrytext : { *(.entrytext) } .inittext : { *(.inittext) }
arch/x86/include/uapi/asm/bootparam.h +46 -17
110 lines not on this page · raw message
[tip:x86/boot] x86, boot: Sanitize boot_params if not zeroed on creation
In reply to Yinghai LuCommit-ID: 5dcd14ecd41ea2b3ae3295a9b30d98769d52165f Gitweb: http://git.kernel.org/tip/5dcd14ecd41ea2b3ae3295a9b30d98769d52165f Author: H. Peter Anvin <[email protected]> AuthorDate: Tue, 29 Jan 2013 01:05:24 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 01:22:17 -0800
x86, boot: Sanitize boot_params if not zeroed on creation
Use the new sentinel field to detect bootloaders which fail to follow protocol and don't initialize fields in struct boot_params that they do not explicitly initialize to zero.
Based on an original patch and research by Yinghai Lu. Changed by hpa to be invoked both in the decompression path and in the kernel proper; the latter for the case where a bootloader takes over decompression.
--- arch/x86/boot/compressed/misc.c | 2 ++ arch/x86/boot/compressed/misc.h | 1 + arch/x86/include/asm/bootparam_utils.h | 38 ++++++++++++++++++++++++++++++++++ arch/x86/kernel/head32.c | 3 +++ arch/x86/kernel/head64.c | 2 ++ 5 files changed, 46 insertions(+)
arch/x86/boot/compressed/misc.c +2 -0
@@ -325,6 +325,8 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, { real_mode = rmode; +sanitize_boot_params (real_mode); +if (real_mode->screen_info.orig_video_mode ==7 ) { vidmem = (char *)0xb0000 ; vidport =0x3b4 ;
arch/x86/boot/compressed/misc.h +1 -0
@@ -18,6 +18,7 @@#include <asm/page.h> #include <asm/boot.h> #include <asm/bootparam.h> +#include <asm/bootparam_utils.h> #define BOOT_BOOT_H #include "../ctype.h"
arch/x86/include/asm/bootparam_utils.h new file +38 -0
@@ -0,0 +1,38 @@ +#ifndef _ASM_X86_BOOTPARAM_UTILS_H +#define _ASM_X86_BOOTPARAM_UTILS_H + +#include <asm/bootparam.h> + +/* +* This file is included from multiple environments. Do not +* add completing #includes to make it standalone. +*/ + +/* +* Deal with bootloaders which fail to initialize unknown fields in +* boot_params to zero. The list fields in this list are taken from +* analysis of kexec-tools; if other broken bootloaders initialize a +* different set of fields we will need to figure out how to disambiguate. +* +*/ +static void sanitize_boot_params (struct boot_params *boot_params) +{ +if (boot_params->sentinel) { +/*fields in boot_params are not valid, clear them */ +memset (&boot_params->olpc_ofw_header,0 , + (char *)&boot_params->alt_mem_k - + (char *)&boot_params->olpc_ofw_header); +memset (&boot_params->kbd_status,0 , + (char *)&boot_params->hdr - + (char *)&boot_params->kbd_status); +memset (&boot_params->_pad7[0 ],0 , + (char *)&boot_params->edd_mbr_sig_buffer[0 ] - + (char *)&boot_params->_pad7[0 ]); +memset (&boot_params->_pad8[0 ],0 , + (char *)&boot_params->eddbuf[0 ] - + (char *)&boot_params->_pad8[0 ]); +memset (&boot_params->_pad9[0 ],0 ,sizeof (boot_params->_pad9)); + } +} + +#endif /* _ASM_X86_BOOTPARAM_UTILS_H */
arch/x86/kernel/head32.c +3 -0
@@ -18,6 +18,7 @@#include <asm/io_apic.h> #include <asm/bios_ebda.h> #include <asm/tlbflush.h> +#include <asm/bootparam_utils.h> static void __init i386_default_early_setup (void ) {
@@ -30,6 +31,8 @@ static void __init i386_default_early_setup(void)void __init i386_start_kernel (void ) { +sanitize_boot_params (&boot_params); +memblock_reserve (__pa_symbol (&_text),__pa_symbol (&__bss_stop) -__pa_symbol (&_text));
arch/x86/kernel/head64.c +2 -0
@@ -25,6 +25,7 @@#include <asm/kdebug.h> #include <asm/e820.h> #include <asm/bios_ebda.h> +#include <asm/bootparam_utils.h> static void __init zap_identity_mappings (void ) {
@@ -46,6 +47,7 @@ static void __init copy_bootdata(char *real_mode_data)char * command_line;memcpy (&boot_params, real_mode_data,sizeof boot_params); +sanitize_boot_params (&boot_params);if (boot_params.hdr.cmd_line_ptr) { command_line =__va (boot_params.hdr.cmd_line_ptr);memcpy (boot_command_line, command_line,COMMAND_LINE_SIZE );
[tip:x86/mm2] x86, boot: enable support load bzImage and ramdisk above 4G
In reply to Yinghai LuCommit-ID: 8cf52eb755e5c5046d2a5d5d3b64d839677ed8ae Gitweb: http://git.kernel.org/tip/8cf52eb755e5c5046d2a5d5d3b64d839677ed8ae Author: Yinghai Lu <[email protected]> AuthorDate: Mon, 28 Jan 2013 20:16:44 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:30:22 -0800
x86, boot: enable support load bzImage and ramdisk above 4G
xloadflags bit 1 indicates that we can load the kernel and all data structure above 4G; it is set if kernel is relocatable and 64bit.
bootloader will check if xloadflags bit1 is set to decicde if it could load ramdisk and kernel high above 4G.
bootloader will fill value to ext_ramdisk_image/size for high 32bits when it load ramdisk above 4G.
kernel use get_ramdisk_image/size to use ext_ramdisk_image/size to get right positon for ramdisk.
--- arch/x86/boot/compressed/cmdline.c | 2 ++ arch/x86/boot/compressed/misc.c | 19 +++++++++++++++++++ arch/x86/boot/header.S | 10 +++++++++- arch/x86/kernel/head64.c | 2 ++ arch/x86/kernel/setup.c | 4 ++++ 5 files changed, 36 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/cmdline.c +2 -0
@@ -17,6 +17,8 @@ static unsigned long get_cmd_line_ptr(void) {unsigned long cmd_line_ptr = real_mode->hdr.cmd_line_ptr; + cmd_line_ptr |= (u64 )real_mode->ext_cmd_line_ptr <<32 ; +return cmd_line_ptr; }int cmdline_find_option (const char *option,char *buffer,int bufsize)
arch/x86/boot/compressed/misc.c +19 -0
@@ -318,6 +318,23 @@ static void parse_elf(void *output)free (phdrs); } +static void sanitize_real_mode (struct boot_params *real_mode) +{ +if (real_mode->sentinel) { +/*fields in boot_params are not valid, clear them */ +memset (&real_mode->olpc_ofw_header,0 , + (char *)&real_mode->alt_mem_k - + (char *)&real_mode->olpc_ofw_header); +memset (&real_mode->_pad7[0 ],0 , + (char *)&real_mode->edd_mbr_sig_buffer[0 ] - + (char *)&real_mode->_pad7[0 ]); +memset (&real_mode->_pad8[0 ],0 , + (char *)&real_mode->eddbuf[0 ] - + (char *)&real_mode->_pad8[0 ]); +memset (&real_mode->_pad9[0 ],0 ,sizeof (real_mode->_pad9)); + } +} + asmlinkage void decompress_kernel(void *rmode, memptr heap, unsigned char *input_data, unsigned long input_len,
@@ -327,6 +344,8 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,sanitize_boot_params (real_mode); +sanitize_real_mode (real_mode); +if (real_mode->screen_info.orig_video_mode ==7 ) { vidmem = (char *)0xb0000 ; vidport =0x3b4 ;
arch/x86/boot/header.S +9 -1
@@ -374,6 +374,14 @@ xloadflags: #else # define XLF0 0 #endif + +#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64) + /* kernel/boot_param/ramdisk could be loaded above 4g */ +# define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G +#else +# define XLF1 0 +#endif + #ifdef CONFIG_EFI_STUB # ifdef CONFIG_X86_64 # define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
@@ -383,7 +391,7 @@ xloadflags: #else # define XLF23 0 #endif - .word XLF0 | XLF23 + .word XLF0 | XLF1 | XLF23 cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, #added with boot protocol
arch/x86/kernel/head64.c +2 -0
@@ -116,6 +116,8 @@ static unsigned long get_cmd_line_ptr(void) {unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + cmd_line_ptr |= (u64 )boot_params.ext_cmd_line_ptr <<32 ; +return cmd_line_ptr; }
arch/x86/kernel/setup.c +4 -0
@@ -298,12 +298,16 @@ static u64 __init get_ramdisk_image(void) {u64 ramdisk_image = boot_params.hdr.ramdisk_image; + ramdisk_image |= (u64 )boot_params.ext_ramdisk_image <<32 ; +return ramdisk_image; }static u64 __init get_ramdisk_size (void ) {u64 ramdisk_size = boot_params.hdr.ramdisk_size; + ramdisk_size |= (u64 )boot_params.ext_ramdisk_size <<32 ; +return ramdisk_size; }
Re: [tip:x86/mm2] x86, boot: enable support load bzImage and ramdisk above 4G
Quoted 78 lines · tip-bot for Yinghai Lu
Commit-ID: 8cf52eb755e5c5046d2a5d5d3b64d839677ed8ae Gitweb: http://git.kernel.org/tip/8cf52eb755e5c5046d2a5d5d3b64d839677ed8ae Author: Yinghai Lu <[email protected]> AuthorDate: Mon, 28 Jan 2013 20:16:44 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:30:22 -0800x86, boot: enable support load bzImage and ramdisk above 4G
xloadflags bit 1 indicates that we can load the kernel and all data structure above 4G; it is set if kernel is relocatable and 64bit.
bootloader will check if xloadflags bit1 is set to decicde if it could load ramdisk and kernel high above 4G.
bootloader will fill value to ext_ramdisk_image/size for high 32bits when it load ramdisk above 4G.
kernel use get_ramdisk_image/size to use ext_ramdisk_image/size to get right positon for ramdisk.Signed-off-by Yinghai Lu <[email protected]>Cc Rob Landley <[email protected]>Cc Matt Fleming <[email protected]>Cc Gokul Caushik <[email protected]>Cc Josh Triplett <[email protected]>Cc Joe Millenbach <[email protected]>Signed-off-by H. Peter Anvin <[email protected]>--- arch/x86/boot/compressed/cmdline.c | 2 ++ arch/x86/boot/compressed/misc.c | 19 +++++++++++++++++++ arch/x86/boot/header.S | 10 +++++++++- arch/x86/kernel/head64.c | 2 ++ arch/x86/kernel/setup.c | 4 ++++ 5 files changed, 36 insertions(+), 1 deletion(-)arch/x86/boot/compressed/cmdline.c +2
-0@@ -17,6 +17,8 @@ static unsigned long get_cmd_line_ptr(void) {unsigned long cmd_line_ptr = real_mode->hdr.cmd_line_ptr; + cmd_line_ptr |= (u64 )real_mode->ext_cmd_line_ptr <<32 ; +return cmd_line_ptr; }int cmdline_find_option (const char *option,char *buffer,int bufsize)arch/x86/boot/compressed/misc.c +17
-0@@ -318,6 +318,23 @@ static void parse_elf(void *output)free (phdrs); } +static void sanitize_real_mode (struct boot_params *real_mode) +{ +if (real_mode->sentinel) { +/*fields in boot_params are not valid, clear them */ +memset (&real_mode->olpc_ofw_header,0 , + (char *)&real_mode->alt_mem_k - + (char *)&real_mode->olpc_ofw_header); +memset (&real_mode->_pad7[0 ],0 , + (char *)&real_mode->edd_mbr_sig_buffer[0 ] - + (char *)&real_mode->_pad7[0 ]); +memset (&real_mode->_pad8[0 ],0 , + (char *)&real_mode->eddbuf[0 ] - + (char *)&real_mode->_pad8[0 ]); +memset (&real_mode->_pad9[0 ],0 ,sizeof (real_mode->_pad9)); + } +} + asmlinkage void decompress_kernel(void *rmode, memptr heap, unsigned char *input_data, unsigned long input_len,
arch/x86/boot/compressed/misc.c asmlinkage void decompress_kernel(void *rmode, memptr heap, · line 348
Quoted 5 lines
arch/x86/boot/compressed/misc.c +2
-0@@ -327,6 +344,8 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,sanitize_boot_params (real_mode); +sanitize_real_mode (real_mode); +
Hi, Peter,
sanitize_real_mode() need to be dropped from this patch.
You already have complete patch sanitize_boot_params() applied before.
Thanks
Yinghai
H. Peter Anvin
reviewerRe: [tip:x86/mm2] x86, boot: enable support load bzImage and ramdisk above 4G
Argh. Too tired.
Quoted 103 lines · Yinghai Lu
Quoted 2 lines · tip-bot for Yinghai Lu
Commit-ID:
8cf52eb755e5c5046d2a5d5d3b64d839677ed8aeGitweb:http://git.kernel.org/tip/8cf52eb755e5c5046d2a5d5d3b64d839677ed8ae
Quoted 10 lines
Author: Yinghai Lu <[email protected]> AuthorDate: Mon, 28 Jan 2013 20:16:44 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:30:22 -0800x86, boot: enable support load bzImage and ramdisk above 4G
xloadflags bit 1 indicates that we can load the kernel and all data structure above 4G; it is set if kernel is relocatable and 64bit.
Quoted 6 lines
bootloader will check if xloadflags bit1 is set to decicde if it could load ramdisk and kernel high above 4G.
bootloader will fill value to ext_ramdisk_image/size for high 32bits when it load ramdisk above 4G.
kernel use get_ramdisk_image/size to use ext_ramdisk_image/size toget
Quoted 9 lines
right positon for ramdisk.
Signed-off-by Yinghai Lu <[email protected]>Cc Rob Landley <[email protected]>Cc Matt Fleming <[email protected]>Cc Gokul Caushik <[email protected]>Cc Josh Triplett <[email protected]>Cc Joe Millenbach <[email protected]>Link:
http://lkml.kernel.org/r/[email protected]
Review
Quoted 10 lines
Signed-off-by H. Peter Anvin <[email protected]>--- arch/x86/boot/compressed/cmdline.c | 2 ++ arch/x86/boot/compressed/misc.c | 19 +++++++++++++++++++ arch/x86/boot/header.S | 10 +++++++++- arch/x86/kernel/head64.c | 2 ++ arch/x86/kernel/setup.c | 4 ++++ 5 files changed, 36 insertions(+), 1 deletion(-)(quoted diff) +0
-0
b/arch/x86/boot/compressed/cmdline.carch/x86/boot/compressed/cmdline.c static unsigned long get_cmd_line_ptr(void) · line 24
Quoted 12 lines
index b4c913c..bffd73b 100644
arch/x86/boot/compressed/cmdline.c +2
-0@@ -17,6 +17,8 @@ static unsigned long get_cmd_line_ptr(void) {unsigned long cmd_line_ptr = real_mode->hdr.cmd_line_ptr; + cmd_line_ptr |= (u64 )real_mode->ext_cmd_line_ptr <<32 ; +return cmd_line_ptr; } int cmdline_find_option(const char *option, char *buffer, intbufsize)
Review
Quoted 1 line
(quoted diff) +0
-0
b/arch/x86/boot/compressed/misc.cQuoted 11 lines
index 7cb56c6..5d8dc86 100644
arch/x86/boot/compressed/misc.c +4
-0@@ -318,6 +318,23 @@ static void parse_elf(void *output)free (phdrs); } +static void sanitize_real_mode (struct boot_params *real_mode) +{ +if (real_mode->sentinel) { +/*fields in boot_params are not valid, clear them */ arch/x86/boot/compressed/misc.c static void parse_elf(void *output) · line 334
Quoted 10 lines
arch/x86/boot/compressed/misc.c +10
-0+memset (&real_mode->olpc_ofw_header,0 , + (char *)&real_mode->alt_mem_k - + (char *)&real_mode->olpc_ofw_header); +memset (&real_mode->_pad7[0 ],0 , + (char *)&real_mode->edd_mbr_sig_buffer[0 ] - + (char *)&real_mode->_pad7[0 ]); +memset (&real_mode->_pad8[0 ],0 , + (char *)&real_mode->eddbuf[0 ] - + (char *)&real_mode->_pad8[0 ]); + memset(&real_mode->_pad9[0], 0,
sizeof(real_mode->_pad9));arch/x86/boot/compressed/misc.c asmlinkage void decompress_kernel(void *rmode,
Quoted 7 lines
arch/x86/boot/compressed/misc.c +3
-0+ } +} + asmlinkage void decompress_kernel(void *rmode, memptr heap, unsigned char *input_data, unsigned long input_len,@@ -327,6 +344,8 @@ asmlinkage void decompress_kernel(void *rmode,memptr heap,
arch/x86/boot/compressed/misc.c asmlinkage void decompress_kernel(void *rmode, memptr heap, · line 348
Quoted 5 lines
arch/x86/boot/compressed/misc.c +2
-0sanitize_boot_params (real_mode); +sanitize_real_mode (real_mode); +Hi, Peter,
sanitize_real_mode()need to be dropped from this patch.You already have complete patch
sanitize_boot_params()applied before.Thanks
Yinghai
Signature · 1 line
Sent from my mobile phone. Please excuse brevity and lack of formatting.
[tip:x86/mm2] x86, boot: Support loading bzImage, boot_params and ramdisk above 4G
In reply to Yinghai LuCommit-ID: ee92d815027a76ef92f3ec7b155b0c8aa345f239 Gitweb: http://git.kernel.org/tip/ee92d815027a76ef92f3ec7b155b0c8aa345f239 Author: Yinghai Lu <[email protected]> AuthorDate: Mon, 28 Jan 2013 20:16:44 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:33 -0800
x86, boot: Support loading bzImage, boot_params and ramdisk above 4G
xloadflags bit 1 indicates that we can load the kernel and all data structures above 4G; it is set if kernel is relocatable and 64bit.
bootloader will check if xloadflags bit 1 is set to decide if it could load ramdisk and kernel high above 4G.
bootloader will fill value to ext_ramdisk_image/size for high 32bits when it load ramdisk above 4G.
kernel use get_ramdisk_image/size to use ext_ramdisk_image/size to get right positon for ramdisk.
--- arch/x86/boot/compressed/cmdline.c | 2 ++ arch/x86/boot/header.S | 10 +++++++++- arch/x86/kernel/head64.c | 2 ++ arch/x86/kernel/setup.c | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/cmdline.c +2 -0
@@ -17,6 +17,8 @@ static unsigned long get_cmd_line_ptr(void) {unsigned long cmd_line_ptr = real_mode->hdr.cmd_line_ptr; + cmd_line_ptr |= (u64 )real_mode->ext_cmd_line_ptr <<32 ; +return cmd_line_ptr; }int cmdline_find_option (const char *option,char *buffer,int bufsize)
arch/x86/boot/header.S +9 -1
@@ -374,6 +374,14 @@ xloadflags: #else # define XLF0 0 #endif + +#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64) + /* kernel/boot_param/ramdisk could be loaded above 4g */ +# define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G +#else +# define XLF1 0 +#endif + #ifdef CONFIG_EFI_STUB # ifdef CONFIG_X86_64 # define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
@@ -383,7 +391,7 @@ xloadflags: #else # define XLF23 0 #endif - .word XLF0 | XLF23 + .word XLF0 | XLF1 | XLF23 cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, #added with boot protocol
arch/x86/kernel/head64.c +2 -0
@@ -116,6 +116,8 @@ static unsigned long get_cmd_line_ptr(void) {unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + cmd_line_ptr |= (u64 )boot_params.ext_cmd_line_ptr <<32 ; +return cmd_line_ptr; }
arch/x86/kernel/setup.c +4 -0
@@ -298,12 +298,16 @@ static u64 __init get_ramdisk_image(void) {u64 ramdisk_image = boot_params.hdr.ramdisk_image; + ramdisk_image |= (u64 )boot_params.ext_ramdisk_image <<32 ; +return ramdisk_image; }static u64 __init get_ramdisk_size (void ) {u64 ramdisk_size = boot_params.hdr.ramdisk_size; + ramdisk_size |= (u64 )boot_params.ext_ramdisk_size <<32 ; +return ramdisk_size; }
PATCH 26/35 x86, boot: Update comments about entries for 64bit image
In reply to Yinghai LuNow 64bit entry is fixed on 0x200, can not be changed anymore.
Update the comments to reflect that.
Also put info about it in boot.txt
-v2: fix some grammar error
--- Documentation/x86/boot.txt | 38 ++++++++++++++++++++++++++++++++++++ arch/x86/boot/compressed/head_64.S | 22 ++++++++++++--------- 2 files changed, 51 insertions(+), 9 deletions(-)
Documentation/x86/boot.txt +38 -0
@@ -1042,6 +1042,44 @@ must have read/write permission; CS must be __BOOT_CS and DS, ES, SS must be __BOOT_DS; interrupt must be disabled; %esi must hold the base address of the struct boot_params; %ebp, %edi and %ebx must be zero. +**** 64-bit BOOT PROTOCOL + +For machine with 64bit cpus and 64bit kernel, we could use 64bit bootloader +and we need a 64-bit boot protocol. + +In 64-bit boot protocol, the first step in loading a Linux kernel +should be to setup the boot parameters (struct boot_params, +traditionally known as "zero page"). The memory for struct boot_params +could be allocated anywhere (even above 4G) and initialized to all zero. +Then, the setup header at offset 0x01f1 of kernel image on should be +loaded into struct boot_params and examined. The end of setup header +can be calculated as follows: + + 0x0202 + byte value at offset 0x0201 + +In addition to read/modify/write the setup header of the struct +boot_params as that of 16-bit boot protocol, the boot loader should +also fill the additional fields of the struct boot_params as described +in zero-page.txt. + +After setting up the struct boot_params, the boot loader can load +64-bit kernel in the same way as that of 16-bit boot protocol, but +kernel could be loaded above 4G. + +In 64-bit boot protocol, the kernel is started by jumping to the +64-bit kernel entry point, which is the start address of loaded +64-bit kernel plus 0x200. + +At entry, the CPU must be in 64-bit mode with paging enabled. +The range with setup_header.init_size from start address of loaded +kernel and zero page and command line buffer get ident mapping; +a GDT must be loaded with the descriptors for selectors +__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat +segment; __BOOT_CS must have execute/read permission, and __BOOT_DS +must have read/write permission; CS must be __BOOT_CS and DS, ES, SS +must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base +address of the struct boot_params. + **** EFI HANDOVER PROTOCOL This protocol allows boot loaders to defer initialisation to the EFI
arch/x86/boot/compressed/head_64.S +13 -9
@@ -37,6 +37,12 @@ __HEAD .code32 ENTRY(startup_32) + /* + * 32bit entry is 0 and it is ABI so immutable! + * If we come here directly from a bootloader, + * kernel(text+data+bss+brk) ramdisk, zero_page, command line + * all need to be under the 4G limit. + */ cld /* * Test KEEP_SEGMENTS flag to see if the bootloader is asking
@@ -182,20 +188,18 @@ ENTRY(startup_32) lret ENDPROC(startup_32) - /* - * Be careful here startup_64 needs to be at a predictable - * address so I can export it in an ELF header. Bootloaders - * should look at the ELF header to find this address, as - * it may change in the future. - */ .code64 .org 0x200 ENTRY(startup_64) /* + * 64bit entry is 0x200 and it is ABI so immutable! * We come here either from startup_32 or directly from a - * 64bit bootloader. If we come here from a bootloader we depend on - * an identity mapped page table being provied that maps our - * entire text+data+bss and hopefully all of memory. + * 64bit bootloader. + * If we come here from a bootloader, kernel(text+data+bss+brk), + * ramdisk, zero_page, command line could be above 4G. + * We depend on an identity mapped page table being provided + * that maps our entire kernel(text+data+bss+brk), zero page + * and command line. */ #ifdef CONFIG_EFI_STUB /*
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, boot: Update comments about entries for 64bit image
Commit-ID: 80aa46df14fa53cc20d72685a8d7065283463ddb Gitweb: http://git.kernel.org/tip/80aa46df14fa53cc20d72685a8d7065283463ddb Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:07 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:31:49 -0800
x86, boot: Update comments about entries for 64bit image
Now 64bit entry is fixed on 0x200, can not be changed anymore.
Update the comments to reflect that.
Also put info about it in boot.txt
-v2: fix some grammar error
--- Documentation/x86/boot.txt | 38 ++++++++++++++++++++++++++++++++++++++ arch/x86/boot/compressed/head_64.S | 22 +++++++++++++--------- 2 files changed, 51 insertions(+), 9 deletions(-)
Documentation/x86/boot.txt +38 -0
@@ -1054,6 +1054,44 @@ must have read/write permission; CS must be __BOOT_CS and DS, ES, SS must be __BOOT_DS; interrupt must be disabled; %esi must hold the base address of the struct boot_params; %ebp, %edi and %ebx must be zero. +**** 64-bit BOOT PROTOCOL + +For machine with 64bit cpus and 64bit kernel, we could use 64bit bootloader +and we need a 64-bit boot protocol. + +In 64-bit boot protocol, the first step in loading a Linux kernel +should be to setup the boot parameters (struct boot_params, +traditionally known as "zero page"). The memory for struct boot_params +could be allocated anywhere (even above 4G) and initialized to all zero. +Then, the setup header at offset 0x01f1 of kernel image on should be +loaded into struct boot_params and examined. The end of setup header +can be calculated as follows: + + 0x0202 + byte value at offset 0x0201 + +In addition to read/modify/write the setup header of the struct +boot_params as that of 16-bit boot protocol, the boot loader should +also fill the additional fields of the struct boot_params as described +in zero-page.txt. + +After setting up the struct boot_params, the boot loader can load +64-bit kernel in the same way as that of 16-bit boot protocol, but +kernel could be loaded above 4G. + +In 64-bit boot protocol, the kernel is started by jumping to the +64-bit kernel entry point, which is the start address of loaded +64-bit kernel plus 0x200. + +At entry, the CPU must be in 64-bit mode with paging enabled. +The range with setup_header.init_size from start address of loaded +kernel and zero page and command line buffer get ident mapping; +a GDT must be loaded with the descriptors for selectors +__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat +segment; __BOOT_CS must have execute/read permission, and __BOOT_DS +must have read/write permission; CS must be __BOOT_CS and DS, ES, SS +must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base +address of the struct boot_params. + **** EFI HANDOVER PROTOCOL This protocol allows boot loaders to defer initialisation to the EFI
arch/x86/boot/compressed/head_64.S +13 -9
@@ -37,6 +37,12 @@ __HEAD .code32 ENTRY(startup_32) + /* + * 32bit entry is 0 and it is ABI so immutable! + * If we come here directly from a bootloader, + * kernel(text+data+bss+brk) ramdisk, zero_page, command line + * all need to be under the 4G limit. + */ cld /* * Test KEEP_SEGMENTS flag to see if the bootloader is asking
@@ -182,20 +188,18 @@ ENTRY(startup_32) lret ENDPROC(startup_32) - /* - * Be careful here startup_64 needs to be at a predictable - * address so I can export it in an ELF header. Bootloaders - * should look at the ELF header to find this address, as - * it may change in the future. - */ .code64 .org 0x200 ENTRY(startup_64) /* + * 64bit entry is 0x200 and it is ABI so immutable! * We come here either from startup_32 or directly from a - * 64bit bootloader. If we come here from a bootloader we depend on - * an identity mapped page table being provied that maps our - * entire text+data+bss and hopefully all of memory. + * 64bit bootloader. + * If we come here from a bootloader, kernel(text+data+bss+brk), + * ramdisk, zero_page, command line could be above 4G. + * We depend on an identity mapped page table being provided + * that maps our entire kernel(text+data+bss+brk), zero page + * and command line. */ #ifdef CONFIG_EFI_STUB /*
[tip:x86/mm2] x86, boot: Update comments about entries for 64bit image
In reply to Yinghai LuCommit-ID: 8ee2f2dfdbdfe1851fcc0191b2d4faa4c26a39fb Gitweb: http://git.kernel.org/tip/8ee2f2dfdbdfe1851fcc0191b2d4faa4c26a39fb Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:07 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:57 -0800
x86, boot: Update comments about entries for 64bit image
Now 64bit entry is fixed on 0x200, can not be changed anymore.
Update the comments to reflect that.
Also put info about it in boot.txt
-v2: fix some grammar error
--- Documentation/x86/boot.txt | 38 ++++++++++++++++++++++++++++++++++++++ arch/x86/boot/compressed/head_64.S | 22 +++++++++++++--------- 2 files changed, 51 insertions(+), 9 deletions(-)
Documentation/x86/boot.txt +38 -0
@@ -1054,6 +1054,44 @@ must have read/write permission; CS must be __BOOT_CS and DS, ES, SS must be __BOOT_DS; interrupt must be disabled; %esi must hold the base address of the struct boot_params; %ebp, %edi and %ebx must be zero. +**** 64-bit BOOT PROTOCOL + +For machine with 64bit cpus and 64bit kernel, we could use 64bit bootloader +and we need a 64-bit boot protocol. + +In 64-bit boot protocol, the first step in loading a Linux kernel +should be to setup the boot parameters (struct boot_params, +traditionally known as "zero page"). The memory for struct boot_params +could be allocated anywhere (even above 4G) and initialized to all zero. +Then, the setup header at offset 0x01f1 of kernel image on should be +loaded into struct boot_params and examined. The end of setup header +can be calculated as follows: + + 0x0202 + byte value at offset 0x0201 + +In addition to read/modify/write the setup header of the struct +boot_params as that of 16-bit boot protocol, the boot loader should +also fill the additional fields of the struct boot_params as described +in zero-page.txt. + +After setting up the struct boot_params, the boot loader can load +64-bit kernel in the same way as that of 16-bit boot protocol, but +kernel could be loaded above 4G. + +In 64-bit boot protocol, the kernel is started by jumping to the +64-bit kernel entry point, which is the start address of loaded +64-bit kernel plus 0x200. + +At entry, the CPU must be in 64-bit mode with paging enabled. +The range with setup_header.init_size from start address of loaded +kernel and zero page and command line buffer get ident mapping; +a GDT must be loaded with the descriptors for selectors +__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat +segment; __BOOT_CS must have execute/read permission, and __BOOT_DS +must have read/write permission; CS must be __BOOT_CS and DS, ES, SS +must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base +address of the struct boot_params. + **** EFI HANDOVER PROTOCOL This protocol allows boot loaders to defer initialisation to the EFI
arch/x86/boot/compressed/head_64.S +13 -9
@@ -37,6 +37,12 @@ __HEAD .code32 ENTRY(startup_32) + /* + * 32bit entry is 0 and it is ABI so immutable! + * If we come here directly from a bootloader, + * kernel(text+data+bss+brk) ramdisk, zero_page, command line + * all need to be under the 4G limit. + */ cld /* * Test KEEP_SEGMENTS flag to see if the bootloader is asking
@@ -182,20 +188,18 @@ ENTRY(startup_32) lret ENDPROC(startup_32) - /* - * Be careful here startup_64 needs to be at a predictable - * address so I can export it in an ELF header. Bootloaders - * should look at the ELF header to find this address, as - * it may change in the future. - */ .code64 .org 0x200 ENTRY(startup_64) /* + * 64bit entry is 0x200 and it is ABI so immutable! * We come here either from startup_32 or directly from a - * 64bit bootloader. If we come here from a bootloader we depend on - * an identity mapped page table being provied that maps our - * entire text+data+bss and hopefully all of memory. + * 64bit bootloader. + * If we come here from a bootloader, kernel(text+data+bss+brk), + * ramdisk, zero_page, command line could be above 4G. + * We depend on an identity mapped page table being provided + * that maps our entire kernel(text+data+bss+brk), zero page + * and command line. */ #ifdef CONFIG_EFI_STUB /*
PATCH 27/35 x86, boot: Not need to check setup_header version for setup_data
In reply to Yinghai LuThat is for bootloaders.
setup_data is in setup_header, and bootloader is copying that from bzImage. So for old bootloader should keep that as 0 already.
old kexec-tools till now for elf image set setup_data to 0, so it is ok.
--- arch/x86/kernel/setup.c | 6 ------ 1 file changed, 6 deletions(-)
arch/x86/kernel/setup.c +0 -6
@@ -439,8 +439,6 @@ static void __init parse_setup_data(void)struct setup_data *data;u64 pa_data; -if (boot_params.hdr.version <0x0209 ) -return ; pa_data = boot_params.hdr.setup_data;while (pa_data) {u32 data_len, map_len;
@@ -476,8 +474,6 @@ static void __init e820_reserve_setup_data(void)u64 pa_data;int found =0 ; -if (boot_params.hdr.version <0x0209 ) -return ; pa_data = boot_params.hdr.setup_data;while (pa_data) { data =early_memremap (pa_data,sizeof (*data));
@@ -501,8 +497,6 @@ static void __init memblock_x86_reserve_range_setup_data(void)struct setup_data *data;u64 pa_data; -if (boot_params.hdr.version <0x0209 ) -return ; pa_data = boot_params.hdr.setup_data;while (pa_data) { data =early_memremap (pa_data,sizeof (*data));
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, boot: Not need to check setup_header version for setup_data
Commit-ID: 38e825c685f1cc82b237f4147c3e35691a610ade Gitweb: http://git.kernel.org/tip/38e825c685f1cc82b237f4147c3e35691a610ade Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:08 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:31:51 -0800
x86, boot: Not need to check setup_header version for setup_data
That is for bootloaders.
setup_data is in setup_header, and bootloader is copying that from bzImage. So for old bootloader should keep that as 0 already.
old kexec-tools till now for elf image set setup_data to 0, so it is ok.
--- arch/x86/kernel/setup.c | 6 ------ 1 file changed, 6 deletions(-)
arch/x86/kernel/setup.c +0 -6
@@ -439,8 +439,6 @@ static void __init parse_setup_data(void)struct setup_data *data;u64 pa_data; -if (boot_params.hdr.version <0x0209 ) -return ; pa_data = boot_params.hdr.setup_data;while (pa_data) {u32 data_len, map_len;
@@ -476,8 +474,6 @@ static void __init e820_reserve_setup_data(void)u64 pa_data;int found =0 ; -if (boot_params.hdr.version <0x0209 ) -return ; pa_data = boot_params.hdr.setup_data;while (pa_data) { data =early_memremap (pa_data,sizeof (*data));
@@ -501,8 +497,6 @@ static void __init memblock_x86_reserve_range_setup_data(void)struct setup_data *data;u64 pa_data; -if (boot_params.hdr.version <0x0209 ) -return ; pa_data = boot_params.hdr.setup_data;while (pa_data) { data =early_memremap (pa_data,sizeof (*data));
[tip:x86/mm2] x86, boot: Not need to check setup_header version for setup_data
In reply to Yinghai LuCommit-ID: d1af6d045fba6b070fa81f54dfe9227214be99ea Gitweb: http://git.kernel.org/tip/d1af6d045fba6b070fa81f54dfe9227214be99ea Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:08 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:57 -0800
x86, boot: Not need to check setup_header version for setup_data
That is for bootloaders.
setup_data is in setup_header, and bootloader is copying that from bzImage. So for old bootloader should keep that as 0 already.
old kexec-tools till now for elf image set setup_data to 0, so it is ok.
--- arch/x86/kernel/setup.c | 6 ------ 1 file changed, 6 deletions(-)
arch/x86/kernel/setup.c +0 -6
@@ -439,8 +439,6 @@ static void __init parse_setup_data(void)struct setup_data *data;u64 pa_data; -if (boot_params.hdr.version <0x0209 ) -return ; pa_data = boot_params.hdr.setup_data;while (pa_data) {u32 data_len, map_len;
@@ -476,8 +474,6 @@ static void __init e820_reserve_setup_data(void)u64 pa_data;int found =0 ; -if (boot_params.hdr.version <0x0209 ) -return ; pa_data = boot_params.hdr.setup_data;while (pa_data) { data =early_memremap (pa_data,sizeof (*data));
@@ -501,8 +497,6 @@ static void __init memblock_x86_reserve_range_setup_data(void)struct setup_data *data;u64 pa_data; -if (boot_params.hdr.version <0x0209 ) -return ; pa_data = boot_params.hdr.setup_data;while (pa_data) { data =early_memremap (pa_data,sizeof (*data));
PATCH 28/35 memblock: Add memblock_mem_size()
In reply to Yinghai LuUse it to get mem size under the limit_pfn.
to replace local version in x86 reserved_initrd.
-v2: remove not needed cast that is pointed out by HPA.
--- arch/x86/kernel/setup.c | 16 +--------------- include/linux/memblock.h | 1 + mm/memblock.c | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 15 deletions(-)
arch/x86/kernel/setup.c +1 -15
@@ -363,20 +363,6 @@ static void __init relocate_initrd(void) ramdisk_here, ramdisk_here + ramdisk_size - 1); } -static u64 __init get_mem_size (unsigned long limit_pfn) -{ -int i; -u64 mapped_pages =0 ; -unsigned long start_pfn, end_pfn; - -for_each_mem_pfn_range (i,MAX_NUMNODES , &start_pfn, &end_pfn,NULL ) { - start_pfn = min_t(unsigned long, start_pfn, limit_pfn); - end_pfn = min_t(unsigned long, end_pfn, limit_pfn); - mapped_pages += end_pfn - start_pfn; - } - -return mapped_pages <<PAGE_SHIFT ; -}static void __init early_reserve_initrd (void ) {/* Assume only end is not page aligned */
@@ -404,7 +390,7 @@ static void __init reserve_initrd(void) initrd_start =0 ; - mapped_size =get_mem_size (max_pfn_mapped); + mapped_size =memblock_mem_size (max_pfn_mapped);if (ramdisk_size >= (mapped_size>>1 )) panic("initrd too large to handle, " "disabling initrd (%lld needed, %lld available)\n",
include/linux/memblock.h +1 -0
@@ -155,6 +155,7 @@ phys_addr_t memblock_alloc_base(phys_addr_t size, phys_addr_t align,phys_addr_t __memblock_alloc_base (phys_addr_t size,phys_addr_t align,phys_addr_t max_addr);phys_addr_t memblock_phys_mem_size (void ); +phys_addr_t memblock_mem_size (unsigned long limit_pfn);phys_addr_t memblock_start_of_DRAM (void );phys_addr_t memblock_end_of_DRAM (void );void memblock_enforce_memory_limit (phys_addr_t memory_limit);
mm/memblock.c +17 -0
@@ -828,6 +828,23 @@ phys_addr_t __init memblock_phys_mem_size(void)return memblock.memory.total_size; } +phys_addr_t __init memblock_mem_size (unsigned long limit_pfn) +{ +unsigned long pages =0 ; +struct memblock_region *r; +unsigned long start_pfn, end_pfn; + +for_each_memblock (memory, r) { + start_pfn =memblock_region_memory_base_pfn (r); + end_pfn =memblock_region_memory_end_pfn (r); + start_pfn = min_t(unsigned long, start_pfn, limit_pfn); + end_pfn = min_t(unsigned long, end_pfn, limit_pfn); + pages += end_pfn - start_pfn; + } + +return (phys_addr_t )pages <<PAGE_SHIFT ; +} +/* lowest address */ phys_addr_t __init_memblock memblock_start_of_DRAM(void) {
Signature · 1 line
1.7.10.4
[tip:x86/mm2] memblock: Add memblock_mem_size()
Commit-ID: f8fff5398fbc6a3b041876114794966652fefe3e Gitweb: http://git.kernel.org/tip/f8fff5398fbc6a3b041876114794966652fefe3e Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:09 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:31:54 -0800
memblock: Add memblock_mem_size()
Use it to get mem size under the limit_pfn. to replace local version in x86 reserved_initrd.
-v2: remove not needed cast that is pointed out by HPA.
--- arch/x86/kernel/setup.c | 16 +--------------- include/linux/memblock.h | 1 + mm/memblock.c | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 15 deletions(-)
arch/x86/kernel/setup.c +1 -15
@@ -363,20 +363,6 @@ static void __init relocate_initrd(void) ramdisk_here, ramdisk_here + ramdisk_size - 1); } -static u64 __init get_mem_size (unsigned long limit_pfn) -{ -int i; -u64 mapped_pages =0 ; -unsigned long start_pfn, end_pfn; - -for_each_mem_pfn_range (i,MAX_NUMNODES , &start_pfn, &end_pfn,NULL ) { - start_pfn = min_t(unsigned long, start_pfn, limit_pfn); - end_pfn = min_t(unsigned long, end_pfn, limit_pfn); - mapped_pages += end_pfn - start_pfn; - } - -return mapped_pages <<PAGE_SHIFT ; -}static void __init early_reserve_initrd (void ) {/* Assume only end is not page aligned */
@@ -404,7 +390,7 @@ static void __init reserve_initrd(void) initrd_start =0 ; - mapped_size =get_mem_size (max_pfn_mapped); + mapped_size =memblock_mem_size (max_pfn_mapped);if (ramdisk_size >= (mapped_size>>1 )) panic("initrd too large to handle, " "disabling initrd (%lld needed, %lld available)\n",
include/linux/memblock.h +1 -0
@@ -155,6 +155,7 @@ phys_addr_t memblock_alloc_base(phys_addr_t size, phys_addr_t align,phys_addr_t __memblock_alloc_base (phys_addr_t size,phys_addr_t align,phys_addr_t max_addr);phys_addr_t memblock_phys_mem_size (void ); +phys_addr_t memblock_mem_size (unsigned long limit_pfn);phys_addr_t memblock_start_of_DRAM (void );phys_addr_t memblock_end_of_DRAM (void );void memblock_enforce_memory_limit (phys_addr_t memory_limit);
mm/memblock.c +17 -0
@@ -828,6 +828,23 @@ phys_addr_t __init memblock_phys_mem_size(void)return memblock.memory.total_size; } +phys_addr_t __init memblock_mem_size (unsigned long limit_pfn) +{ +unsigned long pages =0 ; +struct memblock_region *r; +unsigned long start_pfn, end_pfn; + +for_each_memblock (memory, r) { + start_pfn =memblock_region_memory_base_pfn (r); + end_pfn =memblock_region_memory_end_pfn (r); + start_pfn = min_t(unsigned long, start_pfn, limit_pfn); + end_pfn = min_t(unsigned long, end_pfn, limit_pfn); + pages += end_pfn - start_pfn; + } + +return (phys_addr_t )pages <<PAGE_SHIFT ; +} +/* lowest address */ phys_addr_t __init_memblock memblock_start_of_DRAM(void) {
[tip:x86/mm2] memblock: Add memblock_mem_size()
In reply to Yinghai LuCommit-ID: 595ad9af8584908ea5fb698b836169d05b99f186 Gitweb: http://git.kernel.org/tip/595ad9af8584908ea5fb698b836169d05b99f186 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:09 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:57 -0800
memblock: Add memblock_mem_size()
Use it to get mem size under the limit_pfn. to replace local version in x86 reserved_initrd.
-v2: remove not needed cast that is pointed out by HPA.
--- arch/x86/kernel/setup.c | 16 +--------------- include/linux/memblock.h | 1 + mm/memblock.c | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 15 deletions(-)
arch/x86/kernel/setup.c +1 -15
@@ -363,20 +363,6 @@ static void __init relocate_initrd(void) ramdisk_here, ramdisk_here + ramdisk_size - 1); } -static u64 __init get_mem_size (unsigned long limit_pfn) -{ -int i; -u64 mapped_pages =0 ; -unsigned long start_pfn, end_pfn; - -for_each_mem_pfn_range (i,MAX_NUMNODES , &start_pfn, &end_pfn,NULL ) { - start_pfn = min_t(unsigned long, start_pfn, limit_pfn); - end_pfn = min_t(unsigned long, end_pfn, limit_pfn); - mapped_pages += end_pfn - start_pfn; - } - -return mapped_pages <<PAGE_SHIFT ; -}static void __init early_reserve_initrd (void ) {/* Assume only end is not page aligned */
@@ -404,7 +390,7 @@ static void __init reserve_initrd(void) initrd_start =0 ; - mapped_size =get_mem_size (max_pfn_mapped); + mapped_size =memblock_mem_size (max_pfn_mapped);if (ramdisk_size >= (mapped_size>>1 )) panic("initrd too large to handle, " "disabling initrd (%lld needed, %lld available)\n",
include/linux/memblock.h +1 -0
@@ -155,6 +155,7 @@ phys_addr_t memblock_alloc_base(phys_addr_t size, phys_addr_t align,phys_addr_t __memblock_alloc_base (phys_addr_t size,phys_addr_t align,phys_addr_t max_addr);phys_addr_t memblock_phys_mem_size (void ); +phys_addr_t memblock_mem_size (unsigned long limit_pfn);phys_addr_t memblock_start_of_DRAM (void );phys_addr_t memblock_end_of_DRAM (void );void memblock_enforce_memory_limit (phys_addr_t memory_limit);
mm/memblock.c +17 -0
@@ -828,6 +828,23 @@ phys_addr_t __init memblock_phys_mem_size(void)return memblock.memory.total_size; } +phys_addr_t __init memblock_mem_size (unsigned long limit_pfn) +{ +unsigned long pages =0 ; +struct memblock_region *r; +unsigned long start_pfn, end_pfn; + +for_each_memblock (memory, r) { + start_pfn =memblock_region_memory_base_pfn (r); + end_pfn =memblock_region_memory_end_pfn (r); + start_pfn = min_t(unsigned long, start_pfn, limit_pfn); + end_pfn = min_t(unsigned long, end_pfn, limit_pfn); + pages += end_pfn - start_pfn; + } + +return (phys_addr_t )pages <<PAGE_SHIFT ; +} +/* lowest address */ phys_addr_t __init_memblock memblock_start_of_DRAM(void) {
PATCH 29/35 x86, kdump: Remove crashkernel range find limit for 64bit
In reply to Yinghai LuNow kexeced kernel/ramdisk could be above 4g, so remove 896 limit for 64bit.
--- arch/x86/kernel/setup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/x86/kernel/setup.c +1 -3
@@ -501,13 +501,11 @@ static void __init memblock_x86_reserve_range_setup_data(void)/* * Keep the crash kernel below this limit. On 32 bits earlier kernels * would limit the kernel to the low 512 MiB due to mapping restrictions. -* On 64 bits, kexec-tools currently limits us to 896 MiB; increase this -* limit once kexec-tools are fixed. */ #ifdef CONFIG_X86_32 # define CRASH_KERNEL_ADDR_MAX (512 << 20)#else -# define CRASH_KERNEL_ADDR_MAX (896 << 20) +# define CRASH_KERNEL_ADDR_MAX MAXMEM#endif static void __init reserve_crashkernel (void )
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, kdump: Remove crashkernel range find limit for 64bit
Commit-ID: 574d69ea03612f707e7d8116ffe12a24f088bc1e Gitweb: http://git.kernel.org/tip/574d69ea03612f707e7d8116ffe12a24f088bc1e Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:10 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:31:56 -0800
x86, kdump: Remove crashkernel range find limit for 64bit
Now kexeced kernel/ramdisk could be above 4g, so remove 896 limit for 64bit.
--- arch/x86/kernel/setup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/x86/kernel/setup.c +1 -3
@@ -501,13 +501,11 @@ static void __init memblock_x86_reserve_range_setup_data(void)/* * Keep the crash kernel below this limit. On 32 bits earlier kernels * would limit the kernel to the low 512 MiB due to mapping restrictions. -* On 64 bits, kexec-tools currently limits us to 896 MiB; increase this -* limit once kexec-tools are fixed. */ #ifdef CONFIG_X86_32 # define CRASH_KERNEL_ADDR_MAX (512 << 20)#else -# define CRASH_KERNEL_ADDR_MAX (896 << 20) +# define CRASH_KERNEL_ADDR_MAX MAXMEM#endif static void __init reserve_crashkernel (void )
[tip:x86/mm2] x86, kdump: Remove crashkernel range find limit for 64bit
In reply to Yinghai LuCommit-ID: 7d41a8a4a2b2438621a9159477bff36a11d79a42 Gitweb: http://git.kernel.org/tip/7d41a8a4a2b2438621a9159477bff36a11d79a42 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:10 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:58 -0800
x86, kdump: Remove crashkernel range find limit for 64bit
Now kexeced kernel/ramdisk could be above 4g, so remove 896 limit for 64bit.
--- arch/x86/kernel/setup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/x86/kernel/setup.c +1 -3
@@ -501,13 +501,11 @@ static void __init memblock_x86_reserve_range_setup_data(void)/* * Keep the crash kernel below this limit. On 32 bits earlier kernels * would limit the kernel to the low 512 MiB due to mapping restrictions. -* On 64 bits, kexec-tools currently limits us to 896 MiB; increase this -* limit once kexec-tools are fixed. */ #ifdef CONFIG_X86_32 # define CRASH_KERNEL_ADDR_MAX (512 << 20)#else -# define CRASH_KERNEL_ADDR_MAX (896 << 20) +# define CRASH_KERNEL_ADDR_MAX MAXMEM#endif static void __init reserve_crashkernel (void )
PATCH 30/35 x86: Add Crash kernel low reservation
In reply to Yinghai LuDuring kdump kernel's booting stage, it need to find low ram for swiotlb buffer when system does not support intel iommu/dmar remapping.
kexed-tools is appending memmap=exactmap and range from /proc/iomem with "Crash kernel", and that range is above 4G for 64bit after boot protocol 2.12.
We need to add another range in /proc/iomem like "Crash kernel low", so kexec-tools could find that info and append to kdump kernel command line.
Try to reserve some under 4G if the normal "Crash kernel" is above 4G.
User could specify the size with crashkernel_low=XX[KMG].
-v2: fix warning that is found by Fengguang's test robot. -v3: move out get_mem_size change to another patch, to solve compiling
warning that is found by Borislav Petkov <[email protected]>
-v4: user must specify crashkernel_low if system does not support
intel or amd iommu.
--- Documentation/kernel-parameters.txt | 3 +++ arch/x86/kernel/setup.c | 42 +++++++++++++++++++++++++++++++++-- include/linux/kexec.h | 3 +++ kernel/kexec.c | 34 +++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 7 deletions(-)
Documentation/kernel-parameters.txt +3 -0
@@ -594,6 +594,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. is selected automatically. Check Documentation/kdump/kdump.txt for further details. + crashkernel_low=size[KMG] + [KNL, x86] parts under 4G. + crashkernel=range1:size1[,range2:size2,...][@offset] [KNL] Same as above, but depends on the memory in the running system. The syntax of range is
arch/x86/kernel/setup.c +40 -2
68 lines not on this page · raw message
include/linux/kexec.h +3 -0
@@ -191,6 +191,7 @@ extern struct kimage *kexec_crash_image;/* Location of a reserved region to hold the crash kernel. */ extern struct resource crashk_res; +extern struct resource crashk_low_res;typedef u32 note_buf_t [KEXEC_NOTE_BYTES /4 ];extern note_buf_t __percpu *crash_notes;extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE /4 ];
@@ -199,6 +200,8 @@ extern size_t vmcoreinfo_max_size;int __init parse_crashkernel (char *cmdline,unsigned long long system_ram,unsigned long long *crash_size,unsigned long long *crash_base); +int parse_crashkernel_low (char *cmdline,unsigned long long system_ram, +unsigned long long *crash_size,unsigned long long *crash_base);int crash_shrink_memory (unsigned long new_size);size_t crash_get_memory_size (void );void crash_free_reserved_phys_range (unsigned long begin,unsigned long end);
kernel/kexec.c +29 -5
@@ -54,6 +54,12 @@ struct resource crashk_res = { .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_MEM }; +struct resource crashk_low_res = { + .name ="Crash kernel low" , + .start =0 , + .end =0 , + .flags =IORESOURCE_BUSY |IORESOURCE_MEM +};int kexec_should_crash (struct task_struct *p) {
@@ -1369,10 +1375,11 @@ static int __init parse_crashkernel_simple(char *cmdline,* That function is the entry point for command line parsing and should be * called from the arch-specific code. */ -int __init parse_crashkernel (char *cmdline, +static int __init __parse_crashkernel (char *cmdline,unsigned long long system_ram,unsigned long long *crash_size, -unsigned long long *crash_base) +unsigned long long *crash_base, +const char *name) {char *p = cmdline, *ck_cmdline =NULL ;char *first_colon, *first_space;
@@ -1382,16 +1389,16 @@ int __init parse_crashkernel(char *cmdline, *crash_base =0 ;/* find crashkernel and use the last one if there are more */ - p =strstr (p,"crashkernel=" ); + p =strstr (p, name);while (p) { ck_cmdline = p; - p =strstr (p+1 ,"crashkernel=" ); + p =strstr (p+1 , name); }if (!ck_cmdline)return -EINVAL ; - ck_cmdline +=12 ;/* strlen("crashkernel=") */ + ck_cmdline +=strlen (name);/* * if the commandline contains a ':', then that's the extended
@@ -1409,6 +1416,23 @@ int __init parse_crashkernel(char *cmdline,return 0 ; } +int __init parse_crashkernel (char *cmdline, +unsigned long long system_ram, +unsigned long long *crash_size, +unsigned long long *crash_base) +{ +return __parse_crashkernel (cmdline, system_ram, crash_size, crash_base, +"crashkernel=" ); +} + +int __init parse_crashkernel_low (char *cmdline, +unsigned long long system_ram, +unsigned long long *crash_size, +unsigned long long *crash_base) +{ +return __parse_crashkernel (cmdline, system_ram, crash_size, crash_base, +"crashkernel_low=" ); +}static void update_vmcoreinfo_note (void ) {
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86: Add Crash kernel low reservation
Commit-ID: 2cde8ae169982ad1d1023ac628bb54053d0e9d4d Gitweb: http://git.kernel.org/tip/2cde8ae169982ad1d1023ac628bb54053d0e9d4d Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:11 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:31:59 -0800
x86: Add Crash kernel low reservation
During kdump kernel's booting stage, it need to find low ram for swiotlb buffer when system does not support intel iommu/dmar remapping.
kexed-tools is appending memmap=exactmap and range from /proc/iomem with "Crash kernel", and that range is above 4G for 64bit after boot protocol 2.12.
We need to add another range in /proc/iomem like "Crash kernel low", so kexec-tools could find that info and append to kdump kernel command line.
Try to reserve some under 4G if the normal "Crash kernel" is above 4G.
User could specify the size with crashkernel_low=XX[KMG].
-v2: fix warning that is found by Fengguang's test robot. -v3: move out get_mem_size change to another patch, to solve compiling
warning that is found by Borislav Petkov <[email protected]>
-v4: user must specify crashkernel_low if system does not support
intel or amd iommu.
--- Documentation/kernel-parameters.txt | 3 +++ arch/x86/kernel/setup.c | 42 +++++++++++++++++++++++++++++++++++-- include/linux/kexec.h | 3 +++ kernel/kexec.c | 34 +++++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 7 deletions(-)
Documentation/kernel-parameters.txt +3 -0
@@ -594,6 +594,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. is selected automatically. Check Documentation/kdump/kdump.txt for further details. + crashkernel_low=size[KMG] + [KNL, x86] parts under 4G. + crashkernel=range1:size1[,range2:size2,...][@offset] [KNL] Same as above, but depends on the memory in the running system. The syntax of range is
arch/x86/kernel/setup.c +40 -2
68 lines not on this page · raw message
include/linux/kexec.h +3 -0
@@ -191,6 +191,7 @@ extern struct kimage *kexec_crash_image;/* Location of a reserved region to hold the crash kernel. */ extern struct resource crashk_res; +extern struct resource crashk_low_res;typedef u32 note_buf_t [KEXEC_NOTE_BYTES /4 ];extern note_buf_t __percpu *crash_notes;extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE /4 ];
@@ -199,6 +200,8 @@ extern size_t vmcoreinfo_max_size;int __init parse_crashkernel (char *cmdline,unsigned long long system_ram,unsigned long long *crash_size,unsigned long long *crash_base); +int parse_crashkernel_low (char *cmdline,unsigned long long system_ram, +unsigned long long *crash_size,unsigned long long *crash_base);int crash_shrink_memory (unsigned long new_size);size_t crash_get_memory_size (void );void crash_free_reserved_phys_range (unsigned long begin,unsigned long end);
kernel/kexec.c +29 -5
@@ -54,6 +54,12 @@ struct resource crashk_res = { .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_MEM }; +struct resource crashk_low_res = { + .name ="Crash kernel low" , + .start =0 , + .end =0 , + .flags =IORESOURCE_BUSY |IORESOURCE_MEM +};int kexec_should_crash (struct task_struct *p) {
@@ -1369,10 +1375,11 @@ static int __init parse_crashkernel_simple(char *cmdline,* That function is the entry point for command line parsing and should be * called from the arch-specific code. */ -int __init parse_crashkernel (char *cmdline, +static int __init __parse_crashkernel (char *cmdline,unsigned long long system_ram,unsigned long long *crash_size, -unsigned long long *crash_base) +unsigned long long *crash_base, +const char *name) {char *p = cmdline, *ck_cmdline =NULL ;char *first_colon, *first_space;
@@ -1382,16 +1389,16 @@ int __init parse_crashkernel(char *cmdline, *crash_base =0 ;/* find crashkernel and use the last one if there are more */ - p =strstr (p,"crashkernel=" ); + p =strstr (p, name);while (p) { ck_cmdline = p; - p =strstr (p+1 ,"crashkernel=" ); + p =strstr (p+1 , name); }if (!ck_cmdline)return -EINVAL ; - ck_cmdline +=12 ;/* strlen("crashkernel=") */ + ck_cmdline +=strlen (name);/* * if the commandline contains a ':', then that's the extended
@@ -1409,6 +1416,23 @@ int __init parse_crashkernel(char *cmdline,return 0 ; } +int __init parse_crashkernel (char *cmdline, +unsigned long long system_ram, +unsigned long long *crash_size, +unsigned long long *crash_base) +{ +return __parse_crashkernel (cmdline, system_ram, crash_size, crash_base, +"crashkernel=" ); +} + +int __init parse_crashkernel_low (char *cmdline, +unsigned long long system_ram, +unsigned long long *crash_size, +unsigned long long *crash_base) +{ +return __parse_crashkernel (cmdline, system_ram, crash_size, crash_base, +"crashkernel_low=" ); +}static void update_vmcoreinfo_note (void ) {
Re: [tip:x86/mm2] x86: Add Crash kernel low reservation
Yeah yeah, I'm behind on email...
Quoted 22 lines · tip-bot for Yinghai Lu
Commit-ID: 2cde8ae169982ad1d1023ac628bb54053d0e9d4d Gitweb: http://git.kernel.org/tip/2cde8ae169982ad1d1023ac628bb54053d0e9d4d Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:11 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:31:59 -0800x86: Add Crash kernel low reservation
During kdump kernel's booting stage, it need to find low ram for swiotlb buffer when system does not support intel iommu/dmar remapping.
kexed-tools is appending memmap=exactmap and range from
/proc/iomemwith "Crash kernel", and that range is above 4G for 64bit after boot protocol 2.12.We need to add another range in
/proc/iomemlike "Crash kernel low", so kexec-tools could find that info and append to kdump kernel command line.User could specify the size with crashkernel_low=XX[KMG].
Review
Quoted 5 lines
(quoted diff) +0
-3-v2: fix warning that is found by Fengguang's test robot. -v3: move out get_mem_size change to another patch, to solve compiling warning that is found by Borislav Petkov <[email protected]> -v4: user must specify crashkernel_low if system does not support intel or amd iommu.
I missed: why can we not autodetect the lack of support and DTRT?
Quoted 24 lines
Signed-off-by Yinghai Lu <[email protected]>Cc Eric Biederman <[email protected]>Cc Rob Landley <[email protected]>Signed-off-by H. Peter Anvin <[email protected]>--- Documentation/kernel-parameters.txt | 3 +++ arch/x86/kernel/setup.c | 42 +++++++++++++++++++++++++++++++++++-- include/linux/kexec.h | 3 +++ kernel/kexec.c | 34 +++++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 7 deletions(-)Documentation/kernel-parameters.txt +0
-0@@ -594,6 +594,9 @@ bytes respectively. Such letter suffixes can alsobe entirely omitted.
Documentation/kernel-parameters.txt +0
-0is selected automatically. Check Documentation/kdump/kdump.txt for furtherdetails.
Documentation/kernel-parameters.txt bytes respectively. Such letter suffixes can also be entirely omitted. · line 602
Quoted 6 lines
Documentation/kernel-parameters.txt +3
-0+ crashkernel_low=size[KMG] + [KNL, x86] parts under 4G. + crashkernel=range1:size1[,range2:size2,...][@offset] [KNL] Same as above, but depends on the memory in the running system. The syntax of range is
I don't understand this documentation.
The "parts under 4G." assumes you understand the context of this posting which isn't going into the docs. Above you say:
Quoted 1 line
Try to reserve some under 4G if the normal "Crash kernel" is above 4G.
Which is much clearer. Adding this in the middle also makes the "Same as above" slightly confusing (you have two different aboves...)
The first version (crashkernel=onesize) strongly implies the reservation is physically contiguous. The comma separated version implies that there are discontiguous reservations, manually specified.
So is crashkernel_low=size a separate reservation from crashkernel=size, or a modifier on the existing contiguous allocation? Do you still need a crashkernel= entry if you've got a crashkernel_low= entry? If you can (or are required to) specify both, is one a constraint on part of the other or it an addition (so it reserves crashkernel+crashkernel_low)? I seems unlikely "parts under 4G" means it's trying to make one contiguous reservation straddle the high/low boundary to put parts in each while still being contiguous...
I have no idea from what you've added to kernel-parameters.txt.
Looking at the code, I _think_ this adds an additional independent reservation. I.E. crashkernel=size says "allocate memory from anywhere", crashkernel_low=size says "allocate memory from low memory", and doing both allocates two chunks like the comma separated version.
Oh well. It's not hugely important that I understand a subsystem I don't use, but having to look at the code to figure out what the documentation is saying makes me uncomfortable.
Rob
Re: [tip:x86/mm2] x86: Add Crash kernel low reservation
Quoted 28 lines · Rob Landley
Yeah yeah, I'm behind on email...
Quoted 24 lines · tip-bot for Yinghai Lu
Commit-ID:
2cde8ae169982ad1d1023ac628bb54053d0e9d4dGitweb:
http://git.kernel.org/tip/2cde8ae169982ad1d1023ac628bb54053d0e9d4dAuthor: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:11 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:31:59 -0800x86: Add Crash kernel low reservation
During kdump kernel's booting stage, it need to find low ram for swiotlb buffer when system does not support intel iommu/dmar remapping.
kexed-tools is appending memmap=exactmap and range from
/proc/iomemwith "Crash kernel", and that range is above 4G for 64bit after boot protocol 2.12.We need to add another range in
/proc/iomemlike "Crash kernel low", so kexec-tools could find that info and append to kdump kernel command line.User could specify the size with crashkernel_low=XX[KMG].
Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +0
-3-v2: fix warning that is found by Fengguang's test robot. -v3: move out get_mem_size change to another patch, to solve compiling warning that is found by Borislav Petkov <[email protected]> -v4: user must specify crashkernel_low if system does not support intel or amd iommu.I missed: why can we not autodetect the lack of support and DTRT?
We need to process crashkernel early, and at that time we can not find out if we can get iommu initialized properly.
Quoted 26 lines
Quoted 26 lines
Signed-off-by Yinghai Lu <[email protected]>Link:
http://lkml.kernel.org/r/[email protected]Cc Eric Biederman <[email protected]>Cc Rob Landley <[email protected]>Signed-off-by H. Peter Anvin <[email protected]>--- Documentation/kernel-parameters.txt | 3 +++ arch/x86/kernel/setup.c | 42 +++++++++++++++++++++++++++++++++++-- include/linux/kexec.h | 3 +++ kernel/kexec.c | 34 +++++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 7 deletions(-)Documentation/kernel-parameters.txt +0
-0@@ -594,6 +594,9 @@ bytes respectively. Such letter suffixes can also beentirely omitted.
is selected automatically. CheckDocumentation/kdump/kdump.txtfor further details.
Quoted 9 lines
Documentation/kernel-parameters.txt bytes respectively. Such letter suffixes can also be entirely omitted. · line 602
Quoted 6 lines
Documentation/kernel-parameters.txt +3
-0+ crashkernel_low=size[KMG] + [KNL, x86] parts under 4G. + crashkernel=range1:size1[,range2:size2,...][@offset] [KNL] Same as above, but depends on the memory in the running system. The syntax of range isI don't understand this documentation.
Looks better if crashkernel_low is moved under crashkernel.
Quoted 24 lines
The "parts under 4G." assumes you understand the context of this posting which isn't going into the docs. Above you say:
Quoted 1 line
Try to reserve some under 4G if the normal "Crash kernel" is above 4G.
Which is much clearer. Adding this in the middle also makes the "Same as above" slightly confusing (you have two different aboves...)
The first version (crashkernel=onesize) strongly implies the reservation is physically contiguous. The comma separated version implies that there are discontiguous reservations, manually specified.
So is crashkernel_low=size a separate reservation from crashkernel=size, or a modifier on the existing contiguous allocation? Do you still need a crashkernel= entry if you've got a crashkernel_low= entry? If you can (or are required to) specify both, is one a constraint on part of the other or it an addition (so it reserves crashkernel+crashkernel_low)? I seems unlikely "parts under 4G" means it's trying to make one contiguous reservation straddle the high/low boundary to put parts in each while still being contiguous...
Quoted 6 lines
I have no idea from what you've added to kernel-parameters.txt.
Looking at the code, I _think_ this adds an additional independent reservation. I.E. crashkernel=size says "allocate memory from anywhere", crashkernel_low=size says "allocate memory from low memory", and doing both allocates two chunks like the comma separated version.
comma separated version only allocate one piece, right?
The syntax is:
crashkernel=<range1>:<size1>[,<range2>:<size2>,...][@offset] range=start-[end]
'start' is inclusive and 'end' is exclusive.
For example:
crashkernel=512M-2G:64M,2G-:128M
This would mean:
1) if the RAM is smaller than 512M, then don't reserve anything (this is the "rescue" case)
2) if the RAM size is between 512M and 2G (exclusive), then reserve 64M
3) if the RAM size is larger than 2G, then reserve 128M
Quoted 4 lines
Oh well. It's not hugely important that I understand a subsystem I don't use, but having to look at the code to figure out what the documentation is saying makes me uncomfortable.
logic for crashkernel_low, if crashkernel allocate above 4G, and will continue allocate ram under 4G as user specified with crashkernel_low.
Yinghai
[tip:x86/mm2] x86: Add Crash kernel low reservation
In reply to Yinghai LuCommit-ID: 0212f9159694be61c6bc52e925fa76643e0c1abf Gitweb: http://git.kernel.org/tip/0212f9159694be61c6bc52e925fa76643e0c1abf Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:11 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:58 -0800
x86: Add Crash kernel low reservation
During kdump kernel's booting stage, it need to find low ram for swiotlb buffer when system does not support intel iommu/dmar remapping.
kexed-tools is appending memmap=exactmap and range from /proc/iomem with "Crash kernel", and that range is above 4G for 64bit after boot protocol 2.12.
We need to add another range in /proc/iomem like "Crash kernel low", so kexec-tools could find that info and append to kdump kernel command line.
Try to reserve some under 4G if the normal "Crash kernel" is above 4G.
User could specify the size with crashkernel_low=XX[KMG].
-v2: fix warning that is found by Fengguang's test robot. -v3: move out get_mem_size change to another patch, to solve compiling
warning that is found by Borislav Petkov <[email protected]>
-v4: user must specify crashkernel_low if system does not support
intel or amd iommu.
--- Documentation/kernel-parameters.txt | 3 +++ arch/x86/kernel/setup.c | 42 +++++++++++++++++++++++++++++++++++-- include/linux/kexec.h | 3 +++ kernel/kexec.c | 34 +++++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 7 deletions(-)
Documentation/kernel-parameters.txt +3 -0
@@ -594,6 +594,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. is selected automatically. Check Documentation/kdump/kdump.txt for further details. + crashkernel_low=size[KMG] + [KNL, x86] parts under 4G. + crashkernel=range1:size1[,range2:size2,...][@offset] [KNL] Same as above, but depends on the memory in the running system. The syntax of range is
arch/x86/kernel/setup.c +40 -2
68 lines not on this page · raw message
include/linux/kexec.h +3 -0
@@ -191,6 +191,7 @@ extern struct kimage *kexec_crash_image;/* Location of a reserved region to hold the crash kernel. */ extern struct resource crashk_res; +extern struct resource crashk_low_res;typedef u32 note_buf_t [KEXEC_NOTE_BYTES /4 ];extern note_buf_t __percpu *crash_notes;extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE /4 ];
@@ -199,6 +200,8 @@ extern size_t vmcoreinfo_max_size;int __init parse_crashkernel (char *cmdline,unsigned long long system_ram,unsigned long long *crash_size,unsigned long long *crash_base); +int parse_crashkernel_low (char *cmdline,unsigned long long system_ram, +unsigned long long *crash_size,unsigned long long *crash_base);int crash_shrink_memory (unsigned long new_size);size_t crash_get_memory_size (void );void crash_free_reserved_phys_range (unsigned long begin,unsigned long end);
kernel/kexec.c +29 -5
@@ -54,6 +54,12 @@ struct resource crashk_res = { .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_MEM }; +struct resource crashk_low_res = { + .name ="Crash kernel low" , + .start =0 , + .end =0 , + .flags =IORESOURCE_BUSY |IORESOURCE_MEM +};int kexec_should_crash (struct task_struct *p) {
@@ -1369,10 +1375,11 @@ static int __init parse_crashkernel_simple(char *cmdline,* That function is the entry point for command line parsing and should be * called from the arch-specific code. */ -int __init parse_crashkernel (char *cmdline, +static int __init __parse_crashkernel (char *cmdline,unsigned long long system_ram,unsigned long long *crash_size, -unsigned long long *crash_base) +unsigned long long *crash_base, +const char *name) {char *p = cmdline, *ck_cmdline =NULL ;char *first_colon, *first_space;
@@ -1382,16 +1389,16 @@ int __init parse_crashkernel(char *cmdline, *crash_base =0 ;/* find crashkernel and use the last one if there are more */ - p =strstr (p,"crashkernel=" ); + p =strstr (p, name);while (p) { ck_cmdline = p; - p =strstr (p+1 ,"crashkernel=" ); + p =strstr (p+1 , name); }if (!ck_cmdline)return -EINVAL ; - ck_cmdline +=12 ;/* strlen("crashkernel=") */ + ck_cmdline +=strlen (name);/* * if the commandline contains a ':', then that's the extended
@@ -1409,6 +1416,23 @@ int __init parse_crashkernel(char *cmdline,return 0 ; } +int __init parse_crashkernel (char *cmdline, +unsigned long long system_ram, +unsigned long long *crash_size, +unsigned long long *crash_base) +{ +return __parse_crashkernel (cmdline, system_ram, crash_size, crash_base, +"crashkernel=" ); +} + +int __init parse_crashkernel_low (char *cmdline, +unsigned long long system_ram, +unsigned long long *crash_size, +unsigned long long *crash_base) +{ +return __parse_crashkernel (cmdline, system_ram, crash_size, crash_base, +"crashkernel_low=" ); +}static void update_vmcoreinfo_note (void ) {
PATCH 31/35 x86: Merge early kernel reserve for 32bit and 64bit
In reply to Yinghai LuThey are the same, and we could move them out from head32/64.c to setup.c.
We are using memblock, and it could handle overlapping properly, so we don't need to reserve some at first to hold the location, and just need to make sure we reserve them before we are using memblock to find free mem to use.
--- arch/x86/kernel/head32.c | 9 --------- arch/x86/kernel/head64.c | 9 --------- arch/x86/kernel/setup.c | 9 +++++++++ 3 files changed, 9 insertions(+), 18 deletions(-)
arch/x86/kernel/head32.c +0 -9
@@ -30,9 +30,6 @@ static void __init i386_default_early_setup(void)void __init i386_start_kernel (void ) { -memblock_reserve (__pa_symbol (_text), - (unsigned long )__bss_stop - (unsigned long )_text); -/* Call the subarch specific early setup function */ switch (boot_params.hdr.hardware_subarch) {case X86_SUBARCH_MRST :
@@ -46,11 +43,5 @@ void __init i386_start_kernel(void)break ; } -/* -* At this point everything still needed from the boot loader -* or BIOS or kernel text should be early reserved or marked not -* RAM in e820. All other memory is free game. -*/ -start_kernel (); }
arch/x86/kernel/head64.c +0 -9
@@ -184,16 +184,7 @@ void __init x86_64_start_reservations(char *real_mode_data)if (!boot_params.hdr.version)copy_bootdata (__va (real_mode_data)); -memblock_reserve (__pa_symbol (_text), - (unsigned long )__bss_stop - (unsigned long )_text); -reserve_ebda_region (); -/* -* At this point everything still needed from the boot loader -* or BIOS or kernel text should be early reserved or marked not -* RAM in e820. All other memory is free game. -*/ -start_kernel (); }
arch/x86/kernel/setup.c +9 -0
@@ -805,8 +805,17 @@ early_param("reservelow", parse_reservelow);void __init setup_arch (char **cmdline_p) { +memblock_reserve (__pa_symbol (_text), + (unsigned long )__bss_stop - (unsigned long )_text); +early_reserve_initrd (); +/* +* At this point everything still needed from the boot loader +* or BIOS or kernel text should be early reserved or marked not +* RAM in e820. All other memory is free game. +*/ +#ifdef CONFIG_X86_32 memcpy (&boot_cpu_data, &new_cpu_data,sizeof (new_cpu_data));visws_early_detect ();
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86: Merge early kernel reserve for 32bit and 64bit
Commit-ID: 37e2fc42c2164c785261e83ea2f21fbeb7c46638 Gitweb: http://git.kernel.org/tip/37e2fc42c2164c785261e83ea2f21fbeb7c46638 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:12 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:33:07 -0800
x86: Merge early kernel reserve for 32bit and 64bit
They are the same, and we could move them out from head32/64.c to setup.c.
We are using memblock, and it could handle overlapping properly, so we don't need to reserve some at first to hold the location, and just need to make sure we reserve them before we are using memblock to find free mem to use.
--- arch/x86/kernel/head32.c | 9 --------- arch/x86/kernel/head64.c | 9 --------- arch/x86/kernel/setup.c | 9 +++++++++ 3 files changed, 9 insertions(+), 18 deletions(-)
arch/x86/kernel/head32.c +0 -9
@@ -33,9 +33,6 @@ void __init i386_start_kernel(void) {sanitize_boot_params (&boot_params); -memblock_reserve (__pa_symbol (&_text), -__pa_symbol (&__bss_stop) -__pa_symbol (&_text)); -/* Call the subarch specific early setup function */ switch (boot_params.hdr.hardware_subarch) {case X86_SUBARCH_MRST :
@@ -49,11 +46,5 @@ void __init i386_start_kernel(void)break ; } -/* -* At this point everything still needed from the boot loader -* or BIOS or kernel text should be early reserved or marked not -* RAM in e820. All other memory is free game. -*/ -start_kernel (); }
arch/x86/kernel/head64.c +0 -9
@@ -186,16 +186,7 @@ void __init x86_64_start_reservations(char *real_mode_data)if (!boot_params.hdr.version)copy_bootdata (__va (real_mode_data)); -memblock_reserve (__pa_symbol (&_text), -__pa_symbol (&__bss_stop) -__pa_symbol (&_text)); -reserve_ebda_region (); -/* -* At this point everything still needed from the boot loader -* or BIOS or kernel text should be early reserved or marked not -* RAM in e820. All other memory is free game. -*/ -start_kernel (); }
arch/x86/kernel/setup.c +9 -0
@@ -805,8 +805,17 @@ early_param("reservelow", parse_reservelow);void __init setup_arch (char **cmdline_p) { +memblock_reserve (__pa_symbol (_text), + (unsigned long )__bss_stop - (unsigned long )_text); +early_reserve_initrd (); +/* +* At this point everything still needed from the boot loader +* or BIOS or kernel text should be early reserved or marked not +* RAM in e820. All other memory is free game. +*/ +#ifdef CONFIG_X86_32 memcpy (&boot_cpu_data, &new_cpu_data,sizeof (new_cpu_data));visws_early_detect ();
[tip:x86/mm2] x86: Merge early kernel reserve for 32bit and 64bit
In reply to Yinghai LuCommit-ID: 6c902b656c4a808d9c6f40a387b166455efecd62 Gitweb: http://git.kernel.org/tip/6c902b656c4a808d9c6f40a387b166455efecd62 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:12 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:58 -0800
x86: Merge early kernel reserve for 32bit and 64bit
They are the same, and we could move them out from head32/64.c to setup.c.
We are using memblock, and it could handle overlapping properly, so we don't need to reserve some at first to hold the location, and just need to make sure we reserve them before we are using memblock to find free mem to use.
--- arch/x86/kernel/head32.c | 9 --------- arch/x86/kernel/head64.c | 9 --------- arch/x86/kernel/setup.c | 9 +++++++++ 3 files changed, 9 insertions(+), 18 deletions(-)
arch/x86/kernel/head32.c +0 -9
@@ -33,9 +33,6 @@ void __init i386_start_kernel(void) {sanitize_boot_params (&boot_params); -memblock_reserve (__pa_symbol (&_text), -__pa_symbol (&__bss_stop) -__pa_symbol (&_text)); -/* Call the subarch specific early setup function */ switch (boot_params.hdr.hardware_subarch) {case X86_SUBARCH_MRST :
@@ -49,11 +46,5 @@ void __init i386_start_kernel(void)break ; } -/* -* At this point everything still needed from the boot loader -* or BIOS or kernel text should be early reserved or marked not -* RAM in e820. All other memory is free game. -*/ -start_kernel (); }
arch/x86/kernel/head64.c +0 -9
@@ -186,16 +186,7 @@ void __init x86_64_start_reservations(char *real_mode_data)if (!boot_params.hdr.version)copy_bootdata (__va (real_mode_data)); -memblock_reserve (__pa_symbol (&_text), -__pa_symbol (&__bss_stop) -__pa_symbol (&_text)); -reserve_ebda_region (); -/* -* At this point everything still needed from the boot loader -* or BIOS or kernel text should be early reserved or marked not -* RAM in e820. All other memory is free game. -*/ -start_kernel (); }
arch/x86/kernel/setup.c +9 -0
@@ -805,8 +805,17 @@ early_param("reservelow", parse_reservelow);void __init setup_arch (char **cmdline_p) { +memblock_reserve (__pa_symbol (_text), + (unsigned long )__bss_stop - (unsigned long )_text); +early_reserve_initrd (); +/* +* At this point everything still needed from the boot loader +* or BIOS or kernel text should be early reserved or marked not +* RAM in e820. All other memory is free game. +*/ +#ifdef CONFIG_X86_32 memcpy (&boot_cpu_data, &new_cpu_data,sizeof (new_cpu_data));visws_early_detect ();
PATCH 32/35 x86, 64bit, mm: Mark data/bss/brk to nx
In reply to Yinghai LuHPA said, we should not have RW and +x set at the time.
for kernel layout:
[ 0.000000] Kernel Layout: [ 0.000000] .text: [0x01000000-0x021434f8] [ 0.000000] .rodata: [0x02200000-0x02a13fff] [ 0.000000] .data: [0x02c00000-0x02dc763f] [ 0.000000] .init: [0x02dc9000-0x0312cfff] [ 0.000000] .bss: [0x0313b000-0x03dd6fff] [ 0.000000] .brk: [0x03dd7000-0x03dfffff]
before the patch, we have
---[ High Kernel Mapping ]---
0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff82200000 18M ro PSE GLB x pmd 0xffffffff82200000-0xffffffff82c00000 10M ro PSE GLB NX pmd 0xffffffff82c00000-0xffffffff82dc9000 1828K RW GLB x pte 0xffffffff82dc9000-0xffffffff82e00000 220K RW GLB NX pte 0xffffffff82e00000-0xffffffff83000000 2M RW PSE GLB NX pmd 0xffffffff83000000-0xffffffff8313a000 1256K RW GLB NX pte 0xffffffff8313a000-0xffffffff83200000 792K RW GLB x pte 0xffffffff83200000-0xffffffff83e00000 12M RW PSE GLB x pmd
0xffffffff83e00000-0xffffffffa0000000 450M pmd
after patch,, we get
---[ High Kernel Mapping ]---
0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff82200000 18M ro PSE GLB x pmd 0xffffffff82200000-0xffffffff82c00000 10M ro PSE GLB NX pmd 0xffffffff82c00000-0xffffffff82e00000 2M RW GLB NX pte 0xffffffff82e00000-0xffffffff83000000 2M RW PSE GLB NX pmd 0xffffffff83000000-0xffffffff83200000 2M RW GLB NX pte 0xffffffff83200000-0xffffffff83e00000 12M RW PSE GLB NX pmd
0xffffffff83e00000-0xffffffffa0000000 450M pmd
so data, bss, brk get NX ...
--- arch/x86/mm/init_64.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
arch/x86/mm/init_64.c +4 -3
@@ -808,6 +808,7 @@ void mark_rodata_ro(void)unsigned long end = (unsigned long ) &__end_rodata_hpage_align;unsigned long text_end =PFN_ALIGN (&__stop___ex_table);unsigned long rodata_end =PFN_ALIGN (&__end_rodata); +unsigned long all_end =PFN_ALIGN (&_end);printk (KERN_INFO "Write protecting the kernel read-only data: %luk\n" , (end - start) >>10 );
@@ -816,10 +817,10 @@ void mark_rodata_ro(void) kernel_set_to_readonly =1 ;/* -* The rodata section (but not the kernel text!) should also be -* not-executable. +* The rodata/data/bss/brk section (but not the kernel text!) +* should also be not-executable. */ -set_memory_nx (rodata_start, (end - rodata_start) >>PAGE_SHIFT ); +set_memory_nx (rodata_start, (all_end - rodata_start) >>PAGE_SHIFT );rodata_test ();
Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86, 64bit, mm: Mark data/bss/brk to nx
Commit-ID: d27807b9bfd6315a93a051e4e6d9961d6e4467d3 Gitweb: http://git.kernel.org/tip/d27807b9bfd6315a93a051e4e6d9961d6e4467d3 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:13 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:34:36 -0800
x86, 64bit, mm: Mark data/bss/brk to nx
HPA said, we should not have RW and +x set at the time.
for kernel layout:
[ 0.000000] Kernel Layout: [ 0.000000] .text: [0x01000000-0x021434f8] [ 0.000000] .rodata: [0x02200000-0x02a13fff] [ 0.000000] .data: [0x02c00000-0x02dc763f] [ 0.000000] .init: [0x02dc9000-0x0312cfff] [ 0.000000] .bss: [0x0313b000-0x03dd6fff] [ 0.000000] .brk: [0x03dd7000-0x03dfffff]
before the patch, we have
---[ High Kernel Mapping ]---
0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff82200000 18M ro PSE GLB x pmd 0xffffffff82200000-0xffffffff82c00000 10M ro PSE GLB NX pmd 0xffffffff82c00000-0xffffffff82dc9000 1828K RW GLB x pte 0xffffffff82dc9000-0xffffffff82e00000 220K RW GLB NX pte 0xffffffff82e00000-0xffffffff83000000 2M RW PSE GLB NX pmd 0xffffffff83000000-0xffffffff8313a000 1256K RW GLB NX pte 0xffffffff8313a000-0xffffffff83200000 792K RW GLB x pte 0xffffffff83200000-0xffffffff83e00000 12M RW PSE GLB x pmd
0xffffffff83e00000-0xffffffffa0000000 450M pmd
after patch,, we get
---[ High Kernel Mapping ]---
0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff82200000 18M ro PSE GLB x pmd 0xffffffff82200000-0xffffffff82c00000 10M ro PSE GLB NX pmd 0xffffffff82c00000-0xffffffff82e00000 2M RW GLB NX pte 0xffffffff82e00000-0xffffffff83000000 2M RW PSE GLB NX pmd 0xffffffff83000000-0xffffffff83200000 2M RW GLB NX pte 0xffffffff83200000-0xffffffff83e00000 12M RW PSE GLB NX pmd
0xffffffff83e00000-0xffffffffa0000000 450M pmd
so data, bss, brk get NX ...
--- arch/x86/mm/init_64.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
arch/x86/mm/init_64.c +4 -3
@@ -810,6 +810,7 @@ void mark_rodata_ro(void)unsigned long text_end =PAGE_ALIGN ((unsigned long ) &__stop___ex_table);unsigned long rodata_end =PAGE_ALIGN ((unsigned long ) &__end_rodata);unsigned long data_start = (unsigned long ) &_sdata; +unsigned long all_end =PFN_ALIGN (&_end);printk (KERN_INFO "Write protecting the kernel read-only data: %luk\n" , (end - start) >>10 );
@@ -818,10 +819,10 @@ void mark_rodata_ro(void) kernel_set_to_readonly =1 ;/* -* The rodata section (but not the kernel text!) should also be -* not-executable. +* The rodata/data/bss/brk section (but not the kernel text!) +* should also be not-executable. */ -set_memory_nx (rodata_start, (end - rodata_start) >>PAGE_SHIFT ); +set_memory_nx (rodata_start, (all_end - rodata_start) >>PAGE_SHIFT );rodata_test ();
[tip:x86/mm2] x86, 64bit, mm: Mark data/bss/brk to nx
In reply to Yinghai LuCommit-ID: 72212675d1c96f5db8ec6fb35701879911193158 Gitweb: http://git.kernel.org/tip/72212675d1c96f5db8ec6fb35701879911193158 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:13 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:58 -0800
x86, 64bit, mm: Mark data/bss/brk to nx
HPA said, we should not have RW and +x set at the time.
for kernel layout:
[ 0.000000] Kernel Layout: [ 0.000000] .text: [0x01000000-0x021434f8] [ 0.000000] .rodata: [0x02200000-0x02a13fff] [ 0.000000] .data: [0x02c00000-0x02dc763f] [ 0.000000] .init: [0x02dc9000-0x0312cfff] [ 0.000000] .bss: [0x0313b000-0x03dd6fff] [ 0.000000] .brk: [0x03dd7000-0x03dfffff]
before the patch, we have
---[ High Kernel Mapping ]---
0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff82200000 18M ro PSE GLB x pmd 0xffffffff82200000-0xffffffff82c00000 10M ro PSE GLB NX pmd 0xffffffff82c00000-0xffffffff82dc9000 1828K RW GLB x pte 0xffffffff82dc9000-0xffffffff82e00000 220K RW GLB NX pte 0xffffffff82e00000-0xffffffff83000000 2M RW PSE GLB NX pmd 0xffffffff83000000-0xffffffff8313a000 1256K RW GLB NX pte 0xffffffff8313a000-0xffffffff83200000 792K RW GLB x pte 0xffffffff83200000-0xffffffff83e00000 12M RW PSE GLB x pmd
0xffffffff83e00000-0xffffffffa0000000 450M pmd
after patch,, we get
---[ High Kernel Mapping ]---
0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff82200000 18M ro PSE GLB x pmd 0xffffffff82200000-0xffffffff82c00000 10M ro PSE GLB NX pmd 0xffffffff82c00000-0xffffffff82e00000 2M RW GLB NX pte 0xffffffff82e00000-0xffffffff83000000 2M RW PSE GLB NX pmd 0xffffffff83000000-0xffffffff83200000 2M RW GLB NX pte 0xffffffff83200000-0xffffffff83e00000 12M RW PSE GLB NX pmd
0xffffffff83e00000-0xffffffffa0000000 450M pmd
so data, bss, brk get NX ...
--- arch/x86/mm/init_64.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
arch/x86/mm/init_64.c +4 -3
@@ -810,6 +810,7 @@ void mark_rodata_ro(void)unsigned long text_end =PAGE_ALIGN ((unsigned long ) &__stop___ex_table);unsigned long rodata_end =PAGE_ALIGN ((unsigned long ) &__end_rodata);unsigned long data_start = (unsigned long ) &_sdata; +unsigned long all_end =PFN_ALIGN (&_end);printk (KERN_INFO "Write protecting the kernel read-only data: %luk\n" , (end - start) >>10 );
@@ -818,10 +819,10 @@ void mark_rodata_ro(void) kernel_set_to_readonly =1 ;/* -* The rodata section (but not the kernel text!) should also be -* not-executable. +* The rodata/data/bss/brk section (but not the kernel text!) +* should also be not-executable. */ -set_memory_nx (rodata_start, (end - rodata_start) >>PAGE_SHIFT ); +set_memory_nx (rodata_start, (all_end - rodata_start) >>PAGE_SHIFT );rodata_test ();
PATCH 33/35 x86, 64bit, mm: hibernate use generic mapping_init
In reply to Yinghai LuWe should set mappings only for usable memory ranges under max_pfn Otherwise causes same problem that is fixed by
x86, mm: Only direct map addresses that are marked as E820_RAM
Make it only map range in pfn_mapped array.
--- arch/x86/power/hibernate_64.c | 66 ++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 44 deletions(-)
arch/x86/power/hibernate_64.c +22 -44
@@ -11,6 +11,8 @@#include <linux/gfp.h> #include <linux/smp.h> #include <linux/suspend.h> + +#include <asm/init.h> #include <asm/proto.h> #include <asm/page.h> #include <asm/pgtable.h>
@@ -39,41 +41,21 @@ pgd_t *temp_level4_pgt;void *relocated_restore_code; -static int res_phys_pud_init (pud_t *pud,unsigned long address,unsigned long end) +static void *alloc_pgt_page (void *context) { -long i, j; - - i =pud_index (address); - pud = pud + i; -for (; i <PTRS_PER_PUD ; pud++, i++) { -unsigned long paddr; -pmd_t *pmd; - - paddr = address + i*PUD_SIZE ; -if (paddr >= end) -break ; - - pmd = (pmd_t *)get_safe_page (GFP_ATOMIC ); -if (!pmd) -return -ENOMEM ; -set_pud (pud,__pud (__pa (pmd) | _KERNPG_TABLE)); -for (j =0 ; j <PTRS_PER_PMD ; pmd++, j++, paddr +=PMD_SIZE ) { -unsigned long pe; - -if (paddr >= end) -break ; - pe = __PAGE_KERNEL_LARGE_EXEC | paddr; - pe &= __supported_pte_mask; -set_pmd (pmd,__pmd (pe)); - } - } -return 0 ; +return (void *)get_safe_page (GFP_ATOMIC ); }static int set_up_temporary_mappings (void ) { -unsigned long start, end, next; -int error; +struct x86_mapping_info info = { + .alloc_pgt_page = alloc_pgt_page, + .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, + .kernel_mapping = true, + }; +unsigned long mstart, mend; +int result; +int i; temp_level4_pgt = (pgd_t *)get_safe_page (GFP_ATOMIC );if (!temp_level4_pgt)
@@ -84,21 +66,17 @@ static int set_up_temporary_mappings(void) init_level4_pgt[pgd_index(__START_KERNEL_map)]);/* Set up the direct mapping from scratch */ - start = (unsigned long )pfn_to_kaddr (0 ); - end = (unsigned long )pfn_to_kaddr (max_pfn); - -for (; start < end; start = next) { -pud_t *pud = (pud_t *)get_safe_page (GFP_ATOMIC ); -if (!pud) -return -ENOMEM ; - next = start +PGDIR_SIZE ; -if (next > end) - next = end; -if ((error =res_phys_pud_init (pud,__pa (start),__pa (next)))) -return error; -set_pgd (temp_level4_pgt +pgd_index (start), -mk_kernel_pgd (__pa (pud))); +for (i =0 ; i < nr_pfn_mapped; i++) { + mstart = pfn_mapped[i].start <<PAGE_SHIFT ; + mend = pfn_mapped[i].end <<PAGE_SHIFT ; + + result =kernel_ident_mapping_init (&info, temp_level4_pgt, + mstart, mend); + +if (result) +return result; } +return 0 ; }
Signature · 1 line
1.7.10.4
Re: [PATCH 33/35] x86, 64bit, mm: hibernate use generic mapping_init
Quoted 6 lines · Yinghai Lu
We should set mappings only for usable memory ranges under
max_pfnOtherwise causes same problem that is fixed byx86, mm: Only direct map addresses that are marked as
E820_RAMMake it only map range in
pfn_mappedarray.
Well.
While I don't have fundamental objections, I can't really ACK the patch, because I haven't been following arch/x86 development for several months and I can't really say how this is supposed to work after the change.
Thanks,
Rafael
Quoted 106 lines
Signed-off-by Yinghai Lu <[email protected]>Cc Pavel Machek <[email protected]>Cc Rafael J. Wysocki <[email protected]>--- arch/x86/power/hibernate_64.c | 66 ++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 44 deletions(-)arch/x86/power/hibernate_64.c +22
-44@@ -11,6 +11,8 @@#include <linux/gfp.h> #include <linux/smp.h> #include <linux/suspend.h> + +#include <asm/init.h> #include <asm/proto.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -39,41 +41,21 @@ pgd_t *temp_level4_pgt;void *relocated_restore_code; -static int res_phys_pud_init (pud_t *pud,unsigned long address,unsigned long end) +static void *alloc_pgt_page (void *context) { -long i, j; - - i =pud_index (address); - pud = pud + i; -for (; i <PTRS_PER_PUD ; pud++, i++) { -unsigned long paddr; -pmd_t *pmd; - - paddr = address + i*PUD_SIZE ; -if (paddr >= end) -break ; - - pmd = (pmd_t *)get_safe_page (GFP_ATOMIC ); -if (!pmd) -return -ENOMEM ; -set_pud (pud,__pud (__pa (pmd) | _KERNPG_TABLE)); -for (j =0 ; j <PTRS_PER_PMD ; pmd++, j++, paddr +=PMD_SIZE ) { -unsigned long pe; - -if (paddr >= end) -break ; - pe = __PAGE_KERNEL_LARGE_EXEC | paddr; - pe &= __supported_pte_mask; -set_pmd (pmd,__pmd (pe)); - } - } -return 0 ; +return (void *)get_safe_page (GFP_ATOMIC ); }static int set_up_temporary_mappings (void ) { -unsigned long start, end, next; -int error; +struct x86_mapping_info info = { + .alloc_pgt_page = alloc_pgt_page, + .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, + .kernel_mapping = true, + }; +unsigned long mstart, mend; +int result; +int i; temp_level4_pgt = (pgd_t *)get_safe_page (GFP_ATOMIC );if (!temp_level4_pgt)@@ -84,21 +66,17 @@ static int set_up_temporary_mappings(void) init_level4_pgt[pgd_index(__START_KERNEL_map)]);/* Set up the direct mapping from scratch */ - start = (unsigned long )pfn_to_kaddr (0 ); - end = (unsigned long )pfn_to_kaddr (max_pfn); - -for (; start < end; start = next) { -pud_t *pud = (pud_t *)get_safe_page (GFP_ATOMIC ); -if (!pud) -return -ENOMEM ; - next = start +PGDIR_SIZE ; -if (next > end) - next = end; -if ((error =res_phys_pud_init (pud,__pa (start),__pa (next)))) -return error; -set_pgd (temp_level4_pgt +pgd_index (start), -mk_kernel_pgd (__pa (pud))); +for (i =0 ; i < nr_pfn_mapped; i++) { + mstart = pfn_mapped[i].start <<PAGE_SHIFT ; + mend = pfn_mapped[i].end <<PAGE_SHIFT ; + + result =kernel_ident_mapping_init (&info, temp_level4_pgt, + mstart, mend); + +if (result) +return result; } +return 0 ; }
Signature · 2 lines
I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center.
[tip:x86/mm2] x86, 64bit, mm: hibernate use generic mapping_init
In reply to Yinghai LuCommit-ID: 5dcb7eaf2b39787d185221c2e80a9068d63490bb Gitweb: http://git.kernel.org/tip/5dcb7eaf2b39787d185221c2e80a9068d63490bb Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:14 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:34:40 -0800
x86, 64bit, mm: hibernate use generic mapping_init
We should set mappings only for usable memory ranges under max_pfn Otherwise causes same problem that is fixed by
x86, mm: Only direct map addresses that are marked as E820_RAM
Make it only map range in pfn_mapped array.
--- arch/x86/power/hibernate_64.c | 66 +++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 44 deletions(-)
arch/x86/power/hibernate_64.c +22 -44
@@ -11,6 +11,8 @@#include <linux/gfp.h> #include <linux/smp.h> #include <linux/suspend.h> + +#include <asm/init.h> #include <asm/proto.h> #include <asm/page.h> #include <asm/pgtable.h>
@@ -39,41 +41,21 @@ pgd_t *temp_level4_pgt;void *relocated_restore_code; -static int res_phys_pud_init (pud_t *pud,unsigned long address,unsigned long end) +static void *alloc_pgt_page (void *context) { -long i, j; - - i =pud_index (address); - pud = pud + i; -for (; i <PTRS_PER_PUD ; pud++, i++) { -unsigned long paddr; -pmd_t *pmd; - - paddr = address + i*PUD_SIZE ; -if (paddr >= end) -break ; - - pmd = (pmd_t *)get_safe_page (GFP_ATOMIC ); -if (!pmd) -return -ENOMEM ; -set_pud (pud,__pud (__pa (pmd) | _KERNPG_TABLE)); -for (j =0 ; j <PTRS_PER_PMD ; pmd++, j++, paddr +=PMD_SIZE ) { -unsigned long pe; - -if (paddr >= end) -break ; - pe = __PAGE_KERNEL_LARGE_EXEC | paddr; - pe &= __supported_pte_mask; -set_pmd (pmd,__pmd (pe)); - } - } -return 0 ; +return (void *)get_safe_page (GFP_ATOMIC ); }static int set_up_temporary_mappings (void ) { -unsigned long start, end, next; -int error; +struct x86_mapping_info info = { + .alloc_pgt_page = alloc_pgt_page, + .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, + .kernel_mapping = true, + }; +unsigned long mstart, mend; +int result; +int i; temp_level4_pgt = (pgd_t *)get_safe_page (GFP_ATOMIC );if (!temp_level4_pgt)
@@ -84,21 +66,17 @@ static int set_up_temporary_mappings(void) init_level4_pgt[pgd_index(__START_KERNEL_map)]);/* Set up the direct mapping from scratch */ - start = (unsigned long )pfn_to_kaddr (0 ); - end = (unsigned long )pfn_to_kaddr (max_pfn); - -for (; start < end; start = next) { -pud_t *pud = (pud_t *)get_safe_page (GFP_ATOMIC ); -if (!pud) -return -ENOMEM ; - next = start +PGDIR_SIZE ; -if (next > end) - next = end; -if ((error =res_phys_pud_init (pud,__pa (start),__pa (next)))) -return error; -set_pgd (temp_level4_pgt +pgd_index (start), -mk_kernel_pgd (__pa (pud))); +for (i =0 ; i < nr_pfn_mapped; i++) { + mstart = pfn_mapped[i].start <<PAGE_SHIFT ; + mend = pfn_mapped[i].end <<PAGE_SHIFT ; + + result =kernel_ident_mapping_init (&info, temp_level4_pgt, + mstart, mend); + +if (result) +return result; } +return 0 ; }
[tip:x86/mm2] x86, 64bit, mm: hibernate use generic mapping_init
In reply to Yinghai LuCommit-ID: 8b78c21d72d9dbcb7230e97423a2cd8d8402c20c Gitweb: http://git.kernel.org/tip/8b78c21d72d9dbcb7230e97423a2cd8d8402c20c Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:14 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:59 -0800
x86, 64bit, mm: hibernate use generic mapping_init
We should set mappings only for usable memory ranges under max_pfn Otherwise causes same problem that is fixed by
x86, mm: Only direct map addresses that are marked as E820_RAM
Make it only map range in pfn_mapped array.
--- arch/x86/power/hibernate_64.c | 66 +++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 44 deletions(-)
arch/x86/power/hibernate_64.c +22 -44
@@ -11,6 +11,8 @@#include <linux/gfp.h> #include <linux/smp.h> #include <linux/suspend.h> + +#include <asm/init.h> #include <asm/proto.h> #include <asm/page.h> #include <asm/pgtable.h>
@@ -39,41 +41,21 @@ pgd_t *temp_level4_pgt;void *relocated_restore_code; -static int res_phys_pud_init (pud_t *pud,unsigned long address,unsigned long end) +static void *alloc_pgt_page (void *context) { -long i, j; - - i =pud_index (address); - pud = pud + i; -for (; i <PTRS_PER_PUD ; pud++, i++) { -unsigned long paddr; -pmd_t *pmd; - - paddr = address + i*PUD_SIZE ; -if (paddr >= end) -break ; - - pmd = (pmd_t *)get_safe_page (GFP_ATOMIC ); -if (!pmd) -return -ENOMEM ; -set_pud (pud,__pud (__pa (pmd) | _KERNPG_TABLE)); -for (j =0 ; j <PTRS_PER_PMD ; pmd++, j++, paddr +=PMD_SIZE ) { -unsigned long pe; - -if (paddr >= end) -break ; - pe = __PAGE_KERNEL_LARGE_EXEC | paddr; - pe &= __supported_pte_mask; -set_pmd (pmd,__pmd (pe)); - } - } -return 0 ; +return (void *)get_safe_page (GFP_ATOMIC ); }static int set_up_temporary_mappings (void ) { -unsigned long start, end, next; -int error; +struct x86_mapping_info info = { + .alloc_pgt_page = alloc_pgt_page, + .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, + .kernel_mapping = true, + }; +unsigned long mstart, mend; +int result; +int i; temp_level4_pgt = (pgd_t *)get_safe_page (GFP_ATOMIC );if (!temp_level4_pgt)
@@ -84,21 +66,17 @@ static int set_up_temporary_mappings(void) init_level4_pgt[pgd_index(__START_KERNEL_map)]);/* Set up the direct mapping from scratch */ - start = (unsigned long )pfn_to_kaddr (0 ); - end = (unsigned long )pfn_to_kaddr (max_pfn); - -for (; start < end; start = next) { -pud_t *pud = (pud_t *)get_safe_page (GFP_ATOMIC ); -if (!pud) -return -ENOMEM ; - next = start +PGDIR_SIZE ; -if (next > end) - next = end; -if ((error =res_phys_pud_init (pud,__pa (start),__pa (next)))) -return error; -set_pgd (temp_level4_pgt +pgd_index (start), -mk_kernel_pgd (__pa (pud))); +for (i =0 ; i < nr_pfn_mapped; i++) { + mstart = pfn_mapped[i].start <<PAGE_SHIFT ; + mend = pfn_mapped[i].end <<PAGE_SHIFT ; + + result =kernel_ident_mapping_init (&info, temp_level4_pgt, + mstart, mend); + +if (result) +return result; } +return 0 ; }
PATCH 34/35 mm: Add alloc_bootmem_low_pages_nopanic()
In reply to Yinghai LuWe don't need to panic in some case, like for swiotlb preallocating.
--- include/linux/bootmem.h | 5 +++++ mm/bootmem.c | 8 ++++++++ mm/nobootmem.c | 8 ++++++++ 3 files changed, 21 insertions(+)
include/linux/bootmem.h +5 -0
@@ -99,6 +99,9 @@ void *___alloc_bootmem_node_nopanic(pg_data_t *pgdat,extern void *__alloc_bootmem_low (unsigned long size,unsigned long align,unsigned long goal); +void *__alloc_bootmem_low_nopanic (unsigned long size, +unsigned long align, +unsigned long goal); extern void *__alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size, unsigned long align,
@@ -132,6 +135,8 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,#define alloc_bootmem_low (x) \ __alloc_bootmem_low(x, SMP_CACHE_BYTES, 0) +#define alloc_bootmem_low_pages_nopanic (x) \ + __alloc_bootmem_low_nopanic(x, PAGE_SIZE, 0)#define alloc_bootmem_low_pages (x) \ __alloc_bootmem_low(x, PAGE_SIZE, 0)#define alloc_bootmem_low_pages_node (pgdat, x) \
mm/bootmem.c +8 -0
@@ -833,6 +833,14 @@ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,return ___alloc_bootmem (size, align, goal,ARCH_LOW_ADDRESS_LIMIT ); } +void *__init __alloc_bootmem_low_nopanic (unsigned long size, +unsigned long align, +unsigned long goal) +{ +return ___alloc_bootmem_nopanic (size, align, goal, +ARCH_LOW_ADDRESS_LIMIT ); +} +/** * __alloc_bootmem_low_node - allocate low boot memory from a specific node * @pgdat: node to allocate from
mm/nobootmem.c +8 -0
@@ -391,6 +391,14 @@ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,return ___alloc_bootmem (size, align, goal,ARCH_LOW_ADDRESS_LIMIT ); } +void *__init __alloc_bootmem_low_nopanic (unsigned long size, +unsigned long align, +unsigned long goal) +{ +return ___alloc_bootmem_nopanic (size, align, goal, +ARCH_LOW_ADDRESS_LIMIT ); +} +/** * __alloc_bootmem_low_node - allocate low boot memory from a specific node * @pgdat: node to allocate from
Signature · 1 line
1.7.10.4
[tip:x86/mm2] mm: Add alloc_bootmem_low_pages_nopanic()
Commit-ID: 7f5de22abaeb993a3f27132449588ed76c5a7938 Gitweb: http://git.kernel.org/tip/7f5de22abaeb993a3f27132449588ed76c5a7938 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:15 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:34:42 -0800
mm: Add alloc_bootmem_low_pages_nopanic()
We don't need to panic in some case, like for swiotlb preallocating.
--- include/linux/bootmem.h | 5 +++++ mm/bootmem.c | 8 ++++++++ mm/nobootmem.c | 8 ++++++++ 3 files changed, 21 insertions(+)
include/linux/bootmem.h +5 -0
@@ -99,6 +99,9 @@ void *___alloc_bootmem_node_nopanic(pg_data_t *pgdat,extern void *__alloc_bootmem_low (unsigned long size,unsigned long align,unsigned long goal); +void *__alloc_bootmem_low_nopanic (unsigned long size, +unsigned long align, +unsigned long goal); extern void *__alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size, unsigned long align,
@@ -132,6 +135,8 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,#define alloc_bootmem_low (x) \ __alloc_bootmem_low(x, SMP_CACHE_BYTES, 0) +#define alloc_bootmem_low_pages_nopanic (x) \ + __alloc_bootmem_low_nopanic(x, PAGE_SIZE, 0)#define alloc_bootmem_low_pages (x) \ __alloc_bootmem_low(x, PAGE_SIZE, 0)#define alloc_bootmem_low_pages_node (pgdat, x) \
mm/bootmem.c +8 -0
@@ -833,6 +833,14 @@ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,return ___alloc_bootmem (size, align, goal,ARCH_LOW_ADDRESS_LIMIT ); } +void *__init __alloc_bootmem_low_nopanic (unsigned long size, +unsigned long align, +unsigned long goal) +{ +return ___alloc_bootmem_nopanic (size, align, goal, +ARCH_LOW_ADDRESS_LIMIT ); +} +/** * __alloc_bootmem_low_node - allocate low boot memory from a specific node * @pgdat: node to allocate from
mm/nobootmem.c +8 -0
@@ -391,6 +391,14 @@ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,return ___alloc_bootmem (size, align, goal,ARCH_LOW_ADDRESS_LIMIT ); } +void *__init __alloc_bootmem_low_nopanic (unsigned long size, +unsigned long align, +unsigned long goal) +{ +return ___alloc_bootmem_nopanic (size, align, goal, +ARCH_LOW_ADDRESS_LIMIT ); +} +/** * __alloc_bootmem_low_node - allocate low boot memory from a specific node * @pgdat: node to allocate from
[tip:x86/mm2] mm: Add alloc_bootmem_low_pages_nopanic()
In reply to Yinghai LuCommit-ID: 38fa4175e60d98fb1c9815fb14f8057576dade73 Gitweb: http://git.kernel.org/tip/38fa4175e60d98fb1c9815fb14f8057576dade73 Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:15 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:32:59 -0800
mm: Add alloc_bootmem_low_pages_nopanic()
We don't need to panic in some case, like for swiotlb preallocating.
--- include/linux/bootmem.h | 5 +++++ mm/bootmem.c | 8 ++++++++ mm/nobootmem.c | 8 ++++++++ 3 files changed, 21 insertions(+)
include/linux/bootmem.h +5 -0
@@ -99,6 +99,9 @@ void *___alloc_bootmem_node_nopanic(pg_data_t *pgdat,extern void *__alloc_bootmem_low (unsigned long size,unsigned long align,unsigned long goal); +void *__alloc_bootmem_low_nopanic (unsigned long size, +unsigned long align, +unsigned long goal); extern void *__alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size, unsigned long align,
@@ -132,6 +135,8 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,#define alloc_bootmem_low (x) \ __alloc_bootmem_low(x, SMP_CACHE_BYTES, 0) +#define alloc_bootmem_low_pages_nopanic (x) \ + __alloc_bootmem_low_nopanic(x, PAGE_SIZE, 0)#define alloc_bootmem_low_pages (x) \ __alloc_bootmem_low(x, PAGE_SIZE, 0)#define alloc_bootmem_low_pages_node (pgdat, x) \
mm/bootmem.c +8 -0
@@ -833,6 +833,14 @@ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,return ___alloc_bootmem (size, align, goal,ARCH_LOW_ADDRESS_LIMIT ); } +void *__init __alloc_bootmem_low_nopanic (unsigned long size, +unsigned long align, +unsigned long goal) +{ +return ___alloc_bootmem_nopanic (size, align, goal, +ARCH_LOW_ADDRESS_LIMIT ); +} +/** * __alloc_bootmem_low_node - allocate low boot memory from a specific node * @pgdat: node to allocate from
mm/nobootmem.c +8 -0
@@ -391,6 +391,14 @@ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,return ___alloc_bootmem (size, align, goal,ARCH_LOW_ADDRESS_LIMIT ); } +void *__init __alloc_bootmem_low_nopanic (unsigned long size, +unsigned long align, +unsigned long goal) +{ +return ___alloc_bootmem_nopanic (size, align, goal, +ARCH_LOW_ADDRESS_LIMIT ); +} +/** * __alloc_bootmem_low_node - allocate low boot memory from a specific node * @pgdat: node to allocate from
PATCH 35/35 x86: Don't panic if can not alloc buffer for swiotlb
In reply to Yinghai LuNormal boot path on system with iommu support:
swiotlb buffer will be allocated early at first and then try to initialize iommu, if iommu for intel or AMD could setup properly, swiotlb buffer will be freed.
The early allocating is with bootmem, and could panic when we try to use kdump with buffer above 4G only, or with memmap to limit mem under 4G. for example: memmap=4095M$1M to remove memory under 4G.
According to Eric, add _nopanic version and no_iotlb_memory to fail map single later if swiotlb is still needed.
-v2: don't pass nopanic, and use -ENOMEM return value according to Eric.
panic early instead of using swiotlb_full to panic...according to Eric/Konrad.
-v3: make swiotlb_init to be notpanic, but will affect:
arm64, ia64, powerpc, tile, unicore32, x86.
-v4: cleanup swiotlb_init by removing swiotlb_init_with_default_size.
--- arch/mips/cavium-octeon/dma-octeon.c | 3 ++- drivers/xen/swiotlb-xen.c | 4 ++- include/linux/swiotlb.h | 2 +- lib/swiotlb.c | 47 +++++++++++++++++++++------------- 4 files changed, 35 insertions(+), 21 deletions(-)
arch/mips/cavium-octeon/dma-octeon.c +2 -1
@@ -317,7 +317,8 @@ void __init plat_swiotlb_setup(void) octeon_swiotlb =alloc_bootmem_low_pages (swiotlbsize); -swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ); +if (swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ) == -ENOMEM ) +panic ("Cannot allocate SWIOTLB buffer" ); mips_dma_map_ops = &octeon_linear_dma_map_ops.dma_map_ops; }
drivers/xen/swiotlb-xen.c +3 -1
@@ -231,7 +231,9 @@ retry: } start_dma_addr =xen_virt_to_bus (xen_io_tlb_start);if (early) { -swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, verbose); +if (swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, + verbose)) +panic ("Cannot allocate SWIOTLB buffer" ); rc =0 ; }else rc =swiotlb_late_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs);
include/linux/swiotlb.h +1 -1
@@ -23,7 +23,7 @@ extern int swiotlb_force;#define IO_TLB_SHIFT 11extern void swiotlb_init (int verbose); -extern void swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose); +int swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose);extern unsigned long swiotlb_nr_tbl (void );extern int swiotlb_late_init_with_tbl (char *tlb,unsigned long nslabs);
lib/swiotlb.c +29 -18
97 lines not on this page · raw message
Signature · 1 line
1.7.10.4
Re: [PATCH 35/35] x86: Don't panic if can not alloc buffer for swiotlb
Quoted 18 lines · Yinghai Lu
Normal boot path on system with iommu support:
swiotlb buffer will be allocated early at first and then try to initialize iommu, if iommu for intel or AMD could setup properly, swiotlb buffer will be freed.The early allocating is with bootmem, and could panic when we try to use kdump with buffer above 4G only, or with memmap to limit mem under 4G. for example: memmap=4095M$1M to remove memory under 4G.
According to Eric, add
_nopanicversion andno_iotlb_memoryto fail map single later if swiotlb is still needed.(quoted diff) +0
-3-v2: don't pass nopanic, and use -ENOMEM return value according to Eric. panic early instead of using swiotlb_full to panic...according to Eric/Konrad. -v3: make swiotlb_init to be notpanic, but will affect: arm64, ia64, powerpc, tile, unicore32, x86. -v4: cleanup swiotlb_init by removing swiotlb_init_with_default_size.
Quoted 3 lines
Suggested-by Eric W. Biederman <[email protected]>Signed-off-by Yinghai Lu <[email protected]>Cc Konrad Rzeszutek Wilk <[email protected]>
:-)
Quoted 170 lines
Cc Joerg Roedel <[email protected]>Cc Ralf Baechle <[email protected]>Cc Jeremy Fitzhardinge <[email protected]>Cc Kyungmin Park <[email protected]>Cc Marek Szyprowski <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Andrzej Pietrasiewicz <[email protected]>Cc Shuah Khan <[email protected]>--- arch/mips/cavium-octeon/dma-octeon.c | 3 ++- drivers/xen/swiotlb-xen.c | 4 ++- include/linux/swiotlb.h | 2 +- lib/swiotlb.c | 47 +++++++++++++++++++++------------- 4 files changed, 35 insertions(+), 21 deletions(-)arch/mips/cavium-octeon/dma-octeon.c +2
-1@@ -317,7 +317,8 @@ void __init plat_swiotlb_setup(void) octeon_swiotlb =alloc_bootmem_low_pages (swiotlbsize); -swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ); +if (swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ) == -ENOMEM ) +panic ("Cannot allocate SWIOTLB buffer" ); mips_dma_map_ops = &octeon_linear_dma_map_ops.dma_map_ops; }drivers/xen/swiotlb-xen.c +3
-1@@ -231,7 +231,9 @@ retry: } start_dma_addr =xen_virt_to_bus (xen_io_tlb_start);if (early) { -swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, verbose); +if (swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, + verbose)) +panic ("Cannot allocate SWIOTLB buffer" ); rc =0 ; }else rc =swiotlb_late_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs);include/linux/swiotlb.h +1
-1@@ -23,7 +23,7 @@ extern int swiotlb_force;#define IO_TLB_SHIFT 11extern void swiotlb_init (int verbose); -extern void swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose); +int swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose);extern unsigned long swiotlb_nr_tbl (void );extern int swiotlb_late_init_with_tbl (char *tlb,unsigned long nslabs);lib/swiotlb.c +29
-18@@ -122,11 +122,18 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,return phys_to_dma (hwdev,virt_to_phys (address)); } +static bool no_iotlb_memory; +void swiotlb_print_info (void ) {unsigned long bytes = io_tlb_nslabs <<IO_TLB_SHIFT ;unsigned char *vstart, *vend; +if (no_iotlb_memory) { +pr_warn ("software IO TLB: No low mem\n" ); +return ; + } + vstart =phys_to_virt (io_tlb_start); vend =phys_to_virt (io_tlb_end);@@ -136,7 +143,7 @@ void swiotlb_print_info(void) bytes >> 20, vstart, vend - 1); } -void __init swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose) +int __init swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose) {void *v_overflow_buffer;unsigned long i, bytes;@@ -150,9 +157,10 @@ void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)/* * Get the overflow emergency buffer */ - v_overflow_buffer =alloc_bootmem_low_pages (PAGE_ALIGN (io_tlb_overflow)); + v_overflow_buffer =alloc_bootmem_low_pages_nopanic ( +PAGE_ALIGN (io_tlb_overflow));if (!v_overflow_buffer) -panic ("Cannot allocate SWIOTLB overflow buffer!\n" ); +return -ENOMEM ; io_tlb_overflow_buffer =__pa (v_overflow_buffer);@@ -169,15 +177,19 @@ void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)if (verbose)swiotlb_print_info (); + +return 0 ; }/* * Statically reserve bounce buffer space and initialize bounce buffer data * structures for the software IO TLB used to implement the DMA API. */ -static void __init -swiotlb_init_with_default_size (size_t default_size,int verbose) +void __init +swiotlb_init (int verbose) { +/* default to 64MB */ +size_t default_size =64UL <<20 ;unsigned char *vstart;unsigned long bytes;@@ -188,20 +200,16 @@ swiotlb_init_with_default_size(size_t default_size, int verbose) bytes = io_tlb_nslabs <<IO_TLB_SHIFT ; -/* -* Get IO TLB memory from the low pages -*/ - vstart =alloc_bootmem_low_pages (PAGE_ALIGN (bytes)); -if (!vstart) -panic ("Cannot allocate SWIOTLB buffer" ); - -swiotlb_init_with_tbl (vstart, io_tlb_nslabs, verbose); -} +/* Get IO TLB memory from the low pages */ + vstart =alloc_bootmem_low_pages_nopanic (PAGE_ALIGN (bytes)); +if (vstart && !swiotlb_init_with_tbl (vstart, io_tlb_nslabs, verbose)) +return ; -void __init -swiotlb_init (int verbose) -{ -swiotlb_init_with_default_size (64 * (1 <<20 ), verbose);/* default to 64MB */ +if (io_tlb_start) +free_bootmem (io_tlb_start, +PAGE_ALIGN (io_tlb_nslabs <<IO_TLB_SHIFT )); +pr_warn ("Cannot allocate SWIOTLB buffer" ); + no_iotlb_memory = true; }/* @@ -405,6 +413,9 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,unsigned long offset_slots;unsigned long max_slots; +if (no_iotlb_memory) +panic ("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer" ); + mask =dma_get_seg_boundary (hwdev); tbl_dma_addr &= mask;Signature · 1 line
1.7.10.4
[tip:x86/mm2] x86: Don' t panic if can not alloc buffer for swiotlb
In reply to Yinghai LuCommit-ID: c0abd12aba653b4f8da8182ebd13a53c7cd9650b Gitweb: http://git.kernel.org/tip/c0abd12aba653b4f8da8182ebd13a53c7cd9650b Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:16 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 15:34:45 -0800
x86: Don't panic if can not alloc buffer for swiotlb
Normal boot path on system with iommu support:
swiotlb buffer will be allocated early at first and then try to initialize iommu, if iommu for intel or AMD could setup properly, swiotlb buffer will be freed.
The early allocating is with bootmem, and could panic when we try to use kdump with buffer above 4G only, or with memmap to limit mem under 4G. for example: memmap=4095M$1M to remove memory under 4G.
According to Eric, add _nopanic version and no_iotlb_memory to fail map single later if swiotlb is still needed.
-v2: don't pass nopanic, and use -ENOMEM return value according to Eric.
panic early instead of using swiotlb_full to panic...according to Eric/Konrad.
-v3: make swiotlb_init to be notpanic, but will affect:
arm64, ia64, powerpc, tile, unicore32, x86.
-v4: cleanup swiotlb_init by removing swiotlb_init_with_default_size.
--- arch/mips/cavium-octeon/dma-octeon.c | 3 ++- drivers/xen/swiotlb-xen.c | 4 ++- include/linux/swiotlb.h | 2 +- lib/swiotlb.c | 47 ++++++++++++++++++++++-------------- 4 files changed, 35 insertions(+), 21 deletions(-)
arch/mips/cavium-octeon/dma-octeon.c +2 -1
@@ -317,7 +317,8 @@ void __init plat_swiotlb_setup(void) octeon_swiotlb =alloc_bootmem_low_pages (swiotlbsize); -swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ); +if (swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ) == -ENOMEM ) +panic ("Cannot allocate SWIOTLB buffer" ); mips_dma_map_ops = &octeon_linear_dma_map_ops.dma_map_ops; }
drivers/xen/swiotlb-xen.c +3 -1
@@ -231,7 +231,9 @@ retry: } start_dma_addr =xen_virt_to_bus (xen_io_tlb_start);if (early) { -swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, verbose); +if (swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, + verbose)) +panic ("Cannot allocate SWIOTLB buffer" ); rc =0 ; }else rc =swiotlb_late_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs);
include/linux/swiotlb.h +1 -1
@@ -23,7 +23,7 @@ extern int swiotlb_force;#define IO_TLB_SHIFT 11extern void swiotlb_init (int verbose); -extern void swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose); +int swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose);extern unsigned long swiotlb_nr_tbl (void );extern int swiotlb_late_init_with_tbl (char *tlb,unsigned long nslabs);
lib/swiotlb.c +29 -18
97 lines not on this page · raw message
[tip:x86/mm2] x86: Don' t panic if can not alloc buffer for swiotlb
In reply to Yinghai LuCommit-ID: ac2cbab21f318e19bc176a7f38a120cec835220f Gitweb: http://git.kernel.org/tip/ac2cbab21f318e19bc176a7f38a120cec835220f Author: Yinghai Lu <[email protected]> AuthorDate: Thu, 24 Jan 2013 12:20:16 -0800 Committer: H. Peter Anvin <[email protected]> CommitDate: Tue, 29 Jan 2013 19:36:53 -0800
x86: Don't panic if can not alloc buffer for swiotlb
Normal boot path on system with iommu support:
swiotlb buffer will be allocated early at first and then try to initialize iommu, if iommu for intel or AMD could setup properly, swiotlb buffer will be freed.
The early allocating is with bootmem, and could panic when we try to use kdump with buffer above 4G only, or with memmap to limit mem under 4G. for example: memmap=4095M$1M to remove memory under 4G.
According to Eric, add _nopanic version and no_iotlb_memory to fail map single later if swiotlb is still needed.
-v2: don't pass nopanic, and use -ENOMEM return value according to Eric.
panic early instead of using swiotlb_full to panic...according to Eric/Konrad.
-v3: make swiotlb_init to be notpanic, but will affect:
arm64, ia64, powerpc, tile, unicore32, x86.
-v4: cleanup swiotlb_init by removing swiotlb_init_with_default_size.
--- arch/mips/cavium-octeon/dma-octeon.c | 3 ++- drivers/xen/swiotlb-xen.c | 4 ++- include/linux/swiotlb.h | 2 +- lib/swiotlb.c | 47 ++++++++++++++++++++++-------------- 4 files changed, 35 insertions(+), 21 deletions(-)
arch/mips/cavium-octeon/dma-octeon.c +2 -1
@@ -317,7 +317,8 @@ void __init plat_swiotlb_setup(void) octeon_swiotlb =alloc_bootmem_low_pages (swiotlbsize); -swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ); +if (swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ) == -ENOMEM ) +panic ("Cannot allocate SWIOTLB buffer" ); mips_dma_map_ops = &octeon_linear_dma_map_ops.dma_map_ops; }
drivers/xen/swiotlb-xen.c +3 -1
@@ -231,7 +231,9 @@ retry: } start_dma_addr =xen_virt_to_bus (xen_io_tlb_start);if (early) { -swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, verbose); +if (swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, + verbose)) +panic ("Cannot allocate SWIOTLB buffer" ); rc =0 ; }else rc =swiotlb_late_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs);
include/linux/swiotlb.h +1 -1
@@ -23,7 +23,7 @@ extern int swiotlb_force;#define IO_TLB_SHIFT 11extern void swiotlb_init (int verbose); -extern void swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose); +int swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose);extern unsigned long swiotlb_nr_tbl (void );extern int swiotlb_late_init_with_tbl (char *tlb,unsigned long nslabs);
lib/swiotlb.c +29 -18
97 lines not on this page · raw message
PATCH 35/35 x86: Don't panic if can not alloc buffer for swiotlb
In reply to Yinghai LuNormal boot path on system with iommu support:
swiotlb buffer will be allocated early at first and then try to initialize iommu, if iommu for intel or AMD could setup properly, swiotlb buffer will be freed.
The early allocating is with bootmem, and could panic when we try to use kdump with buffer above 4G only, or with memmap to limit mem under 4G. for example: memmap=4095M$1M to remove memory under 4G.
According to Eric, add _nopanic version and no_iotlb_memory to fail map single later if swiotlb is still needed.
-v2: don't pass nopanic, and use -ENOMEM return value according to Eric.
panic early instead of using swiotlb_full to panic...according to Eric/Konrad.
-v3: make swiotlb_init to be notpanic, but will affect:
arm64, ia64, powerpc, tile, unicore32, x86.
-v4: cleanup swiotlb_init by removing swiotlb_init_with_default_size.
--- arch/mips/cavium-octeon/dma-octeon.c | 3 ++- drivers/xen/swiotlb-xen.c | 4 ++- include/linux/swiotlb.h | 2 +- lib/swiotlb.c | 47 +++++++++++++++++++++------------- 4 files changed, 35 insertions(+), 21 deletions(-)
arch/mips/cavium-octeon/dma-octeon.c +2 -1
@@ -317,7 +317,8 @@ void __init plat_swiotlb_setup(void) octeon_swiotlb =alloc_bootmem_low_pages (swiotlbsize); -swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ); +if (swiotlb_init_with_tbl (octeon_swiotlb, swiotlb_nslabs,1 ) == -ENOMEM ) +panic ("Cannot allocate SWIOTLB buffer" ); mips_dma_map_ops = &octeon_linear_dma_map_ops.dma_map_ops; }
drivers/xen/swiotlb-xen.c +3 -1
@@ -231,7 +231,9 @@ retry: } start_dma_addr =xen_virt_to_bus (xen_io_tlb_start);if (early) { -swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, verbose); +if (swiotlb_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs, + verbose)) +panic ("Cannot allocate SWIOTLB buffer" ); rc =0 ; }else rc =swiotlb_late_init_with_tbl (xen_io_tlb_start, xen_io_tlb_nslabs);
include/linux/swiotlb.h +1 -1
@@ -23,7 +23,7 @@ extern int swiotlb_force;#define IO_TLB_SHIFT 11extern void swiotlb_init (int verbose); -extern void swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose); +int swiotlb_init_with_tbl (char *tlb,unsigned long nslabs,int verbose);extern unsigned long swiotlb_nr_tbl (void );extern int swiotlb_late_init_with_tbl (char *tlb,unsigned long nslabs);
lib/swiotlb.c +29 -18
97 lines not on this page · raw message
Signature · 1 line
1.7.10.4