x86, mm: init_memory_mapping cleanup
Subsystems (5)
cover x86, mm: init_memory_mapping cleanup
Current kernel init memory mapping between [0, TOML) and [4G, TOMH) Some AMD systems have mem hole between 4G and TOMH, around 1T.
According to HPA, we should only mapping ram range.
This patcheset:
1. Seperate calculate_table_space_size and find_early_page_table out with init_memory_mapping.
2. For all ranges, will allocate page table one time
3. init mapping for ram range one by one.
Could be found at:git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-x86-mm
Jacob Shin (4):
x86: if kernel .text .data .bss are not marked as E820_RAM, complain and fix
x86: Fixup code testing if a pfn is direct mapped
x86: Only direct map addresses that are marked as E820_RAM
x86/mm: calculate_table_space_size based on memory ranges that are being mapped
Yinghai Lu (9):
x86, mm: Add global page_size_mask and probe one time only x86, mm: Split out split_mem_range from init_memory_mapping x86, mm: Move init_memory_mapping calling out of setup.c x86, mm: Revert back good_end setting for 64bit
x86, mm: Find early page table buffer altogether
x86, mm: Separate out calculate_table_space_size() x86, mm: Move down two calculate_table_space_size down. x86, mm: Set memblock initial limit to 1M
x86, mm: Use func pointer to table size calculation and mapping
arch/x86/include/asm/init.h | 1 - arch/x86/include/asm/page_types.h | 2 + arch/x86/include/asm/pgtable.h | 1 + arch/x86/kernel/cpu/amd.c | 8 +- arch/x86/kernel/setup.c | 36 +++-- arch/x86/mm/init.c | 350 +++++++++++++++++++++++++------------ arch/x86/mm/init_64.c | 6 +- arch/x86/platform/efi/efi.c | 8 +- 8 files changed, 273 insertions(+), 139 deletions(-)
Signature · 1 line
1.7.7
PATCH 1/13 x86, mm: Add global page_size_mask and probe one time only
Now we pass around use_gbpages and use_pse for calculating page table size, Later we will need to calculate page table size for every ram range, that mean those calculation will be done several times.
Those info are the same for all ram range and could be stored in page_size_mask and only probe them one time.
Move htat probing code from in init_memory_mapping into separated function probe_page_size_mask, and call it before all init_memory_mapping.
--- arch/x86/include/asm/pgtable.h | 1 + arch/x86/kernel/setup.c | 1 + arch/x86/mm/init.c | 66 +++++++++++++++++++--------------------- 3 files changed, 33 insertions(+), 35 deletions(-)
arch/x86/include/asm/pgtable.h +1 -0
@@ -598,6 +598,7 @@ static inline int pgd_none(pgd_t pgd)#ifndef __ASSEMBLY__extern int direct_gbpages; +void probe_page_size_mask (void );/* local pte updates need not use xchg for locking */ static inline pte_t native_local_ptep_get_and_clear (pte_t *ptep)
arch/x86/kernel/setup.c +1 -0
@@ -912,6 +912,7 @@ void __init setup_arch(char **cmdline_p)setup_real_mode ();init_gbpages (); +probe_page_size_mask ();/* max_pfn_mapped is updated here */ max_low_pfn_mapped =init_memory_mapping (0 , max_low_pfn<<PAGE_SHIFT );
arch/x86/mm/init.c +31 -35
111 lines not on this page · raw message
Signature · 1 line
1.7.7
PATCH 2/13 x86, mm: Split out split_mem_range from init_memory_mapping
In reply to Yinghai LuSo make init_memory_mapping smaller and readable.
--- arch/x86/mm/init.c | 42 ++++++++++++++++++++++++++---------------- 1 files changed, 26 insertions(+), 16 deletions(-)
arch/x86/mm/init.c +26 -16
@@ -143,25 +143,13 @@ static int __meminit save_mr(struct map_range *mr, int nr_range,return nr_range; } -/* -* Setup the direct mapping of the physical memory at PAGE_OFFSET. -* This runs before bootmem is initialized and gets pages directly from -* the physical memory. To access them they are temporarily mapped. -*/ -unsigned long __init_refok init_memory_mapping (unsigned long start, -unsigned long end) +static int __meminit split_mem_range (struct map_range *mr,int nr_range, +unsigned long start, +unsigned long end) {unsigned long start_pfn, end_pfn; -unsigned long ret =0 ;unsigned long pos; -struct map_range mr[NR_RANGE_MR ]; -int nr_range, i; - -printk (KERN_INFO "init_memory_mapping: [mem %#010lx-%#010lx]\n" , - start, end -1 ); - -memset (mr,0 ,sizeof (mr)); - nr_range =0 ; +int i;/* head if not big page alignment ? */ start_pfn = start >>PAGE_SHIFT ;
@@ -255,6 +243,28 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, (mr[i].page_size_mask & (1 <<PG_LEVEL_1G ))?"1G" :( (mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k")); +return nr_range; +} + +/* +* Setup the direct mapping of the physical memory at PAGE_OFFSET. +* This runs before bootmem is initialized and gets pages directly from +* the physical memory. To access them they are temporarily mapped. +*/ +unsigned long __init_refok init_memory_mapping (unsigned long start, +unsigned long end) +{ +struct map_range mr[NR_RANGE_MR ]; +unsigned long ret =0 ; +int nr_range, i; + +pr_info ("init_memory_mapping: [mem %#010lx-%#010lx]\n" , + start, end -1 ); + +memset (mr,0 ,sizeof (mr)); + nr_range =0 ; + nr_range =split_mem_range (mr, nr_range, start, end); +/* * Find space for the kernel direct mapping tables. *
Signature · 1 line
1.7.7
PATCH 3/13 x86, mm: Move init_memory_mapping calling out of setup.c
In reply to Yinghai LuNow init_memory_mapping is called two times, later will call more time for more ram ranges.
Could put all related init_mem calling together.
--- arch/x86/include/asm/init.h | 1 - arch/x86/include/asm/pgtable.h | 2 +- arch/x86/kernel/setup.c | 13 +------------ arch/x86/mm/init.c | 19 ++++++++++++++++++- 4 files changed, 20 insertions(+), 15 deletions(-)
arch/x86/include/asm/init.h +0 -1
@@ -12,7 +12,6 @@ kernel_physical_mapping_init(unsigned long start,unsigned long end, unsigned long page_size_mask); -extern unsigned long __initdata pgt_buf_start;extern unsigned long __meminitdata pgt_buf_end;extern unsigned long __meminitdata pgt_buf_top;
arch/x86/include/asm/pgtable.h +1 -1
@@ -598,7 +598,7 @@ static inline int pgd_none(pgd_t pgd)#ifndef __ASSEMBLY__extern int direct_gbpages; -void probe_page_size_mask (void ); +void init_mem_mapping (void );/* local pte updates need not use xchg for locking */ static inline pte_t native_local_ptep_get_and_clear (pte_t *ptep)
arch/x86/kernel/setup.c +1 -12
@@ -912,20 +912,9 @@ void __init setup_arch(char **cmdline_p)setup_real_mode ();init_gbpages (); -probe_page_size_mask (); -/* max_pfn_mapped is updated here */ - max_low_pfn_mapped =init_memory_mapping (0 , max_low_pfn<<PAGE_SHIFT ); - max_pfn_mapped = max_low_pfn_mapped; +init_mem_mapping (); -#ifdef CONFIG_X86_64 -if (max_pfn > max_low_pfn) { - max_pfn_mapped =init_memory_mapping (1UL <<32 , - max_pfn<<PAGE_SHIFT ); -/* can we preseve max_low_pfn ?*/ - max_low_pfn = max_pfn; - } -#endif memblock.current_limit =get_max_mapped ();dma_contiguous_reserve (0 );
arch/x86/mm/init.c +18 -1
@@ -92,7 +92,7 @@ static void __init find_early_table_space(struct map_range *mr, (pgt_buf_top << PAGE_SHIFT) - 1); } -void probe_page_size_mask (void ) +static void __init probe_page_size_mask (void ) {#if !defined(CONFIG_DEBUG_PAGEALLOC ) && !defined(CONFIG_KMEMCHECK )/*
@@ -312,6 +312,23 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,return ret >>PAGE_SHIFT ; } +void __init init_mem_mapping (void ) +{ +probe_page_size_mask (); + +/* max_pfn_mapped is updated here */ + max_low_pfn_mapped =init_memory_mapping (0 , max_low_pfn<<PAGE_SHIFT ); + max_pfn_mapped = max_low_pfn_mapped; + +#ifdef CONFIG_X86_64 +if (max_pfn > max_low_pfn) { + max_pfn_mapped =init_memory_mapping (1UL <<32 , + max_pfn<<PAGE_SHIFT ); +/* can we preseve max_low_pfn ?*/ + max_low_pfn = max_pfn; + } +#endif +}/* * devmem_is_allowed() checks to see if /dev/mem access to a certain address
Signature · 1 line
1.7.7
PATCH 4/13 x86, mm: Revert back good_end setting for 64bit
In reply to Yinghai LuAfter
| commit 8548c84da2f47e71bbbe300f55edb768492575f7 | Author: Takashi Iwai <[email protected]> | Date: Sun Oct 23 23:19:12 2011 +0200 | | x86: Fix S4 regression | | Commit 4b239f458 ("x86-64, mm: Put early page table high") causes a S4 | regression since 2.6.39, namely the machine reboots occasionally at S4 | resume. It doesn't happen always, overall rate is about 1/20. But, | like other bugs, once when this happens, it continues to happen. | | This patch fixes the problem by essentially reverting the memory | assignment in the older way.
Have some page table around 512M again, that will prevent kdump to find 512M under 768M.
We need revert that reverting, so we could put page table high again for 64bit.
Takashi agreed that S4 regression could be something else.
https://lkml.org/lkml/2012/6/15/182
--- arch/x86/mm/init.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/mm/init.c +1 -1
@@ -76,8 +76,8 @@ static void __init find_early_table_space(struct map_range *mr,#ifdef CONFIG_X86_32 /* for fixmap */ tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); -#endif good_end = max_pfn_mapped <<PAGE_SHIFT ; +#endif base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE );if (!base)
Signature · 1 line
1.7.7
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 35 lines · Yinghai Lu
After
| commit 8548c84da2f47e71bbbe300f55edb768492575f7 | Author: Takashi Iwai <[email protected]> | Date: Sun Oct 23 23:19:12 2011 +0200 | | x86: Fix S4 regression | | Commit 4b239f458 ("x86-64, mm: Put early page table high") causes a S4 | regression since 2.6.39, namely the machine reboots occasionally at S4 | resume. It doesn't happen always, overall rate is about 1/20. But, | like other bugs, once when this happens, it continues to happen. | | This patch fixes the problem by essentially reverting the memory | assignment in the older way.Have some page table around 512M again, that will prevent kdump to find 512M under 768M.
We need revert that reverting, so we could put page table high again for 64bit.
Takashi agreed that S4 regression could be something else.
https://lkml.org/lkml/2012/6/15/182Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/mm/init.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)arch/x86/mm/init.c +0
-0
arch/x86/mm/init.c static void __init find_early_table_space(struct map_range *mr, · line 83
Quoted 9 lines
arch/x86/mm/init.c +1
-1@@ -76,8 +76,8 @@ static void __init find_early_table_space(struct map_range *mr,#ifdef CONFIG_X86_32 /* for fixmap */ tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); -#endif good_end = max_pfn_mapped <<PAGE_SHIFT ; +#endif base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE );if (!base)
Isn't this going to cause init_memory_mapping to allocate pagetable pages from memory not yet mapped?
Last time I spoke with HPA and Thomas about this, they seem to agree that it isn't a very good idea.
Also, it is proven to cause a certain amount of headaches on Xen, see commit d8aa5ec3382e6a545b8f25178d1e0992d4927f19.
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 43 lines · Stefano Stabellini
Quoted 42 lines · Yinghai Lu
After
| commit 8548c84da2f47e71bbbe300f55edb768492575f7 | Author: Takashi Iwai <[email protected]> | Date: Sun Oct 23 23:19:12 2011 +0200 | | x86: Fix S4 regression | | Commit 4b239f458 ("x86-64, mm: Put early page table high") causes a S4 | regression since 2.6.39, namely the machine reboots occasionally at S4 | resume. It doesn't happen always, overall rate is about 1/20. But, | like other bugs, once when this happens, it continues to happen. | | This patch fixes the problem by essentially reverting the memory | assignment in the older way.Have some page table around 512M again, that will prevent kdump to find 512M under 768M.
We need revert that reverting, so we could put page table high again for 64bit.
Takashi agreed that S4 regression could be something else.
https://lkml.org/lkml/2012/6/15/182Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/mm/init.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)arch/x86/mm/init.c +1
-1@@ -76,8 +76,8 @@ static void __init find_early_table_space(struct map_range *mr,#ifdef CONFIG_X86_32 /* for fixmap */ tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); -#endif good_end = max_pfn_mapped <<PAGE_SHIFT ; +#endif
Quoted 10 lines
arch/x86/mm/init.c static void __init find_early_table_space(struct map_range *mr, · line 83
Quoted 2 lines
arch/x86/mm/init.c +0
-0base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE );if (!base)Isn't this going to cause
init_memory_mappingto allocate pagetable pages from memory not yet mapped?
Last time I spoke with HPA and Thomas about this, they seem to agree that it isn't a very good idea.
Also, it is proven to cause a certain amount of headaches on Xen, see commitd8aa5ec3382e6a545b8f25178d1e0992d4927f19.
Any comments, thoughts? hpa? Yinghai?
So it seems that during init_memory_mapping Xen needs to modify page table bits and the memory where the page tables live needs to be direct mapped at that time.
Since we now call init_memory_mapping for every E820_RAM range sequencially, the only way to satisfy Xen is to find_early_page_table_space (good_end needs to be within memory already mapped at the time) for every init_memory_mapping call.
What do you think Yinghai?
H. Peter Anvin
reviewerRe: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 7 lines · Jacob Shin
Any comments, thoughts? hpa? Yinghai?
So it seems that during
init_memory_mappingXen needs to modify page table bits and the memory where the page tables live needs to be direct mapped at that time.
Quoted 7 lines
Since we now call
init_memory_mappingfor everyE820_RAMrange sequencially, the only way to satisfy Xen is tofind_early_page_table_space(good_endneeds to be within memory already mapped at the time) for everyinit_memory_mappingcall.What do you think Yinghai?
I outlined the sane way to do this at Kernel Summit for Yinghai and several other people. I need to write it up for people who weren't there, but I don't have time right at the moment.
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
In reply to Jacob ShinQuoted 55 lines · Jacob Shin
Quoted 43 lines · Stefano Stabellini
Quoted 42 lines · Yinghai Lu
After
| commit 8548c84da2f47e71bbbe300f55edb768492575f7 | Author: Takashi Iwai <[email protected]> | Date: Sun Oct 23 23:19:12 2011 +0200 | | x86: Fix S4 regression | | Commit 4b239f458 ("x86-64, mm: Put early page table high") causes a S4 | regression since 2.6.39, namely the machine reboots occasionally at S4 | resume. It doesn't happen always, overall rate is about 1/20. But, | like other bugs, once when this happens, it continues to happen. | | This patch fixes the problem by essentially reverting the memory | assignment in the older way.Have some page table around 512M again, that will prevent kdump to find 512M under 768M.
We need revert that reverting, so we could put page table high again for 64bit.
Takashi agreed that S4 regression could be something else.
https://lkml.org/lkml/2012/6/15/182Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/mm/init.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)arch/x86/mm/init.c +1
-1@@ -76,8 +76,8 @@ static void __init find_early_table_space(struct map_range *mr,#ifdef CONFIG_X86_32 /* for fixmap */ tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); -#endif good_end = max_pfn_mapped <<PAGE_SHIFT ; +#endif Quoted 10 lines
arch/x86/mm/init.c static void __init find_early_table_space(struct map_range *mr, · line 83
Quoted 2 lines
arch/x86/mm/init.c +0
-0base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE );if (!base)Isn't this going to cause
init_memory_mappingto allocate pagetable pages from memory not yet mapped?
Last time I spoke with HPA and Thomas about this, they seem to agree that it isn't a very good idea.
Also, it is proven to cause a certain amount of headaches on Xen, see commitd8aa5ec3382e6a545b8f25178d1e0992d4927f19.
Quoted 5 lines
Any comments, thoughts? hpa? Yinghai?
So it seems that during
init_memory_mappingXen needs to modify page table bits and the memory where the page tables live needs to be direct mapped at that time.
That is not exactly true. I am not sure if we are just using the wrong words for it - so let me try to write up what the impediment is.
There is also this talk between Stefano and tglrx that can help in getting ones' head around it: https://lkml.org/lkml/2012/8/24/335
The restriction that Xen places on Linux page-tables is that they MUST be read-only when in usage. Meaning if you creating a PTE table (or PMD, PUD, etc), you can write to it as long as you want - but the moment you hook it up to a live page-table - it must be marked RO (so the PMD entry cannot have _PAGE_RW on it). Easy enough.
This means that if we are re-using a pagetable during the init_memory_mapping (so we iomap it), we need to iomap it with !_PAGE_RW) - and that is where xen_set_pte_init has a check for is_early_ioremap_ptep. To add to the fun, the pagetables are expanding - so as one is ioremapping/iounmaping, you have to check the pgt_buf_end to check whether the page table we are mapping is within the:
pgt_buf_start -> pgt_buf_end <- pgt_buf_top
(and pgt_buf_end can increment up to pgt_buf_top).
Now the next part of this that is hard to wrap around is when you want to create a PTE entries for the pgt_buf_start -> pgt_buf_end. Its double fun, b/c your pgt_buf_end can increment as you are trying to create those PTE entries - and you _MUST_ mark those PTE entries as RO. This is b/c those pagetables (pgt_buf_start -> pgt_buf_end) are live and only Xen can touch them.
This feels like operating on a live patient, while said patient is running the marathon. Only duct-tape expert can apply for this position.
What Peter had in mind is a nice system where we get rid of this linear allocation of page-tables (so pgt_buf_start -> pgt_buf _end are linearly allocated). His thinking (and Peter if I mess up please correct me), is that we can stick the various pagetables in different spots in memory. Mainly that as we look at mapping a region (say 0GB->1GB), we look at in chunks (2MB?) and allocate a page-table at the _end_ of the newly mapped chunk if we have filled all entries in said pagetable.
For simplicity, lets say we are just dealing with PTE tables and we are mapping the region 0GB->1GB with 4KB pages.
First we stick a page-table (or if there is a found one reuse it) at the start of the region (so 0-2MB).
0MB.......................2MB
/-----\
|PTE_A|
\-----/
The PTE entries in it will cover 0->2MB (PTE table #A) and once it is finished, it will stick a new pagetable at the end of the 2MB region:
0MB.......................2MB...........................4MB
/-----\ /-----\ |PTE_A| |PTE_B| \-----/ \-----/
The PTE_B page table will be used to map 2MB->4MB.
Once that is finished .. we repeat the cycle.
That should remove the utter duct-tape madness and make this a lot easier.
H. Peter Anvin
reviewerRe: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 30 lines · Konrad Rzeszutek Wilk
What Peter had in mind is a nice system where we get rid of this linear allocation of page-tables (so
pgt_buf_start->pgt_buf_endare linearly allocated). His thinking (and Peter if I mess up please correct me), is that we can stick the various pagetables in different spots in memory. Mainly that as we look at mapping a region (say 0GB->1GB), we look at in chunks (2MB?) and allocate a page-table at the _end_ of the newly mapped chunk if we have filled all entries in said pagetable.For simplicity, lets say we are just dealing with PTE tables and we are mapping the region 0GB->1GB with 4KB pages.
First we stick a page-table (or if there is a found one reuse it) at the start of the region (so 0-2MB).
0MB.......................2MB
/-----\
|PTE_A|
\-----/The PTE entries in it will cover 0->2MB (PTE table #A) and once it is finished, it will stick a new pagetable at the end of the 2MB region:
0MB.......................2MB...........................4MB
/-----\ /-----\ |PTE_A| |PTE_B| \-----/ \-----/
Quoted 7 lines
The
PTE_Bpage table will be used to map 2MB->4MB.Once that is finished .. we repeat the cycle.
That should remove the utter duct-tape madness and make this a lot easier.
You got the basic idea right but the details slightly wrong. Let me try to explain.
When we start up, we know we have a set of page tables which maps the kernel text, data, bss and brk. This is set up by the startup code on native and by the domain builder on Xen.
We can reserve an arbitrary chunk of brk that is (a) big enough to map the kernel text+data+bss+brk itself plus (b) some arbitrary additional chunk of memory (perhaps we reserve another 256K of brk or so, enough to map 128 MB in the worst case of 4K PAE pages.)
Step 1:
- Create page table mappings for kernel text+data+bss+brk out of the brk region.
Step 2:
- Start creating mappings for the topmost memory region downward, until the brk reserved area is exhaused.
Step 3:
- Call a paravirt hook on the page tables created so far. On native this does nothing, on Xen it can map it readonly and tell the hypervisor it is a page table.
Step 4:
- Switch to the newly created page table. The bootup page table is now obsolete.
Step 5:
- Moving downward from the last address mapped, create new page tables for any additional unmapped memory region until either we run out of unmapped memory regions, or we run out of mapped memory for the memory regions to map.
Step 6:
- Call the paravirt hook for the new page tables, then add them to the page table tree.
Step 7:
- Repeat from step 5 until there are no more unmapped memory regions.
This:
a) removes any need to guesstimate how much page tables are going to consume. We simply construct them; they may not be contiguous but that's okay.
b) very cleanly solves the Xen problem of not wanting to status-flip pages any more than necessary.
The only reason for moving downward rather than upward is that we want the page tables as high as possible in memory, since memory at low addresses is precious (for stupid DMA devices, for things like kexec/kdump, and so on.)
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
In reply to Jacob ShinQuoted 6 lines · Jacob Shin
Any comments, thoughts? hpa? Yinghai?
So it seems that during
init_memory_mappingXen needs to modify page table bits and the memory where the page tables live needs to be direct mapped at that time.
Quoted 6 lines
Since we now call
init_memory_mappingfor everyE820_RAMrange sequencially, the only way to satisfy Xen is tofind_early_page_table_space(good_endneeds to be within memory already mapped at the time) for everyinit_memory_mappingcall.What do you think Yinghai?
that may put the page table on near end of every ram range for next memory range.
then kdump may have problem get big range again.
Yinghai
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 12 lines · Yinghai Lu
Quoted 11 lines · Jacob Shin
Any comments, thoughts? hpa? Yinghai?
So it seems that during
init_memory_mappingXen needs to modify page table bits and the memory where the page tables live needs to be direct mapped at that time.Since we now call
init_memory_mappingfor everyE820_RAMrange sequencially, the only way to satisfy Xen is tofind_early_page_table_space(good_endneeds to be within memory already mapped at the time) for everyinit_memory_mappingcall.
Quoted 6 lines
Quoted 1 line
What do you think Yinghai?
that may put the page table on near end of every ram range for next memory range.
then kdump may have problem get big range again.
Is there a git commit that explains what the 'big range' problem is?
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 3 lines · Konrad Rzeszutek Wilk
Quoted 1 line
then kdump may have problem get big range again.
Is there a git commit that explains what the 'big range' problem is?
commit 7f8595bfacef279f06c82ec98d420ef54f2537e0
Author: H. Peter Anvin <[email protected]> Date: Thu Dec 16 19:20:41 2010 -0800
x86, kexec: Limit the crashkernel address appropriately
Keep the crash kernel address below 512 MiB for 32 bits and 896 MiB for 64 bits. For 32 bits, this retains compatibility with earlier kernel releases, and makes it work even if the vmalloc= setting is adjusted.
For 64 bits, we should be able to increase this substantially once a hard-coded limit in kexec-tools is fixed.
LKML-Reference: <[email protected]>
arch/x86/kernel/setup.c +14 -3
@@ -501,7 +501,18 @@ static inline unsigned long long get_total_mem(void)return total <<PAGE_SHIFT ; } -#define DEFAULT_BZIMAGE_ADDR_MAX 0x37FFFFFF +/* +* 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) +#endif +static void __init reserve_crashkernel (void ) {unsigned long long total_mem;
@@ -520,10 +531,10 @@ static void __init reserve_crashkernel(void)const unsigned long long alignment =16 <<20 ;/* 16M */ /* -* kexec want bzImage is below DEFAULT_BZIMAGE_ADDR_MAX +* kexec want bzImage is below CRASH_KERNEL_ADDR_MAX */ crash_base =memblock_find_in_range (alignment, -DEFAULT_BZIMAGE_ADDR_MAX , crash_size, alignment); +CRASH_KERNEL_ADDR_MAX , crash_size, alignment);if (crash_base ==MEMBLOCK_ERROR ) { pr_info("crashkernel reservation failed - No
suitable area found.\n");
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 5 lines · Yinghai Lu
Quoted 3 lines · Konrad Rzeszutek Wilk
Quoted 1 line
then kdump may have problem get big range again.
Is there a git commit that explains what the 'big range' problem is?
At least on x86_64 this was recently tested and anywhere below 4G is good, and there is a patch floating around somewhere to remove this issue.
I don't know about x86_32.
Eric
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 5 lines · Eric W. Biederman
Quoted 1 line
Quoted 1 line
Is there a git commit that explains what the 'big range' problem is?
At least on
x86_64this was recently tested and anywhere below 4G is good, and there is a patch floating around somewhere to remove this issue.
patch for kernel or kexec-tools?
Yinghai
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 8 lines · Yinghai Lu
Quoted 5 lines · Eric W. Biederman
Quoted 1 line
Quoted 1 line
Is there a git commit that explains what the 'big range' problem is?
At least on
x86_64this was recently tested and anywhere below 4G is good, and there is a patch floating around somewhere to remove this issue.patch for kernel or kexec-tools?
kernel.
The sgi guys needed a kdump kernel with 1G of ram to dump their all of the memory on one of their crazy large machines and so investigated this.
Basically they found that a kdump kernel loaded anywhere < 4G worked, the only change that was needed was to relaxy the 896M hard code.
In one test they had a kdump kernel loaded above 2G.
Eric
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 13 lines · Eric W. Biederman
Quoted 8 lines · Yinghai Lu
Quoted 5 lines · Eric W. Biederman
Quoted 1 line
Quoted 1 line
Is there a git commit that explains what the 'big range' problem is?
At least on
x86_64this was recently tested and anywhere below 4G is good, and there is a patch floating around somewhere to remove this issue.patch for kernel or kexec-tools?
kernel.
Quoted 8 lines
The sgi guys needed a kdump kernel with 1G of ram to dump their all of the memory on one of their crazy large machines and so investigated this.
Basically they found that a kdump kernel loaded anywhere < 4G worked, the only change that was needed was to relaxy the 896M hard code.
In one test they had a kdump kernel loaded above 2G.
with bzImage or vmlinux?
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 1 line · Yinghai Lu
with bzImage or vmlinux?
bzImage I presume. Certainly the bzImage has lost it's 896M limit, which is where ultimiately the 896M limite came from.
Eric
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 6 lines · Eric W. Biederman
Quoted 1 line · Yinghai Lu
with bzImage or vmlinux?
bzImage I presume. Certainly the bzImage has lost it's 896M limit, which is where ultimiately the 896M limite came from.
they are using updated kexec-tools ?
last time when i checked the code for kexec-tools found the 896M problem was from kexec-tools bzimage support.
896MB address limit (was: Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit)
I am going to see about merging these two threads.
Quoted 5 lines · Yinghai Lu
Quoted 4 lines · Eric W. Biederman
Quoted 1 line · Yinghai Lu
with bzImage or vmlinux?
Quoted 7 lines
Quoted 2 lines
bzImage I presume. Certainly the bzImage has lost it's 896M limit, which is where ultimiately the 896M limite came from.
they are using updated kexec-tools ?
last time when i checked the code for kexec-tools found the 896M problem was from kexec-tools bzimage support.
Cliff Wickman was the guy at sgi running the tests.
To the best of my knowledge he was runing an up to date kexec-tools and was loading a bzImage. Of course his initial reaction was where did the 896M limit come from, as he had just updated to a kernel with the limit a few weeks ago.
YH please talk to Cliff directly.
Eric
H. Peter Anvin
reviewerRe: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
In reply to Eric W. BiedermanQuoted 7 lines · Eric W. Biederman
Quoted 1 line · Yinghai Lu
with bzImage or vmlinux?
bzImage I presume. Certainly the bzImage has lost it's 896M limit, which is where ultimiately the 896M limite came from.
~896M (actually comes from i386, not from bzImage...
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 10 lines · H. Peter Anvin
Quoted 7 lines · Eric W. Biederman
Quoted 1 line · Yinghai Lu
with bzImage or vmlinux?
bzImage I presume. Certainly the bzImage has lost it's 896M limit, which is where ultimiately the 896M limite came from.
~896M (actually comes from i386, not from bzImage...
Right it was 1G - VMALLLOC_SIZE.
At some point that affected the boot protocol as the maximum address we could load ramdisks.
Eric
H. Peter Anvin
reviewerRe: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
That disappeared 10 years ago...
Quoted 19 lines · [email protected] wrote:
Quoted 10 lines · H. Peter Anvin
Quoted 7 lines · Eric W. Biederman
Quoted 1 line · Yinghai Lu
with bzImage or vmlinux?
bzImage I presume. Certainly the bzImage has lost it's 896M limit, which is where ultimiately the 896M limite came from.
~896M (actually comes from i386, not from bzImage...
Right it was 1G -
VMALLLOC_SIZE.At some point that affected the boot protocol as the maximum address we could load ramdisks.
Eric
Signature · 1 line
Sent from my mobile phone. Please excuse brevity and lack of formatting.
H. Peter Anvin
reviewerRe: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
In reply to Eric W. BiedermanQuoted 13 lines · Eric W. Biederman
Quoted 8 lines · Yinghai Lu
Quoted 5 lines · Eric W. Biederman
Quoted 1 line
Quoted 1 line
Is there a git commit that explains what the 'big range' problem is?
At least on
x86_64this was recently tested and anywhere below 4G is good, and there is a patch floating around somewhere to remove this issue.patch for kernel or kexec-tools?
kernel.
Quoted 9 lines
The sgi guys needed a kdump kernel with 1G of ram to dump their all of the memory on one of their crazy large machines and so investigated this.
Basically they found that a kdump kernel loaded anywhere < 4G worked, the only change that was needed was to relaxy the 896M hard code.
In one test they had a kdump kernel loaded above 2G.
Seriously, any case where we can't load anywhere in physical ram on x86-64 is a bug. i386 is another matter.
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 18 lines · H. Peter Anvin
Quoted 17 lines · Eric W. Biederman
Quoted 8 lines · Yinghai Lu
Quoted 5 lines · Eric W. Biederman
Quoted 1 line
Quoted 1 line
Is there a git commit that explains what the 'big range' problem is?
At least on
x86_64this was recently tested and anywhere below 4G is good, and there is a patch floating around somewhere to remove this issue.patch for kernel or kexec-tools?
kernel.
The sgi guys needed a kdump kernel with 1G of ram to dump their all of the memory on one of their crazy large machines and so investigated this.
Quoted 8 lines
Quoted 5 lines
Basically they found that a kdump kernel loaded anywhere < 4G worked, the only change that was needed was to relaxy the 896M hard code.
In one test they had a kdump kernel loaded above 2G.
Seriously, any case where we can't load anywhere in physical ram on x86-64 is a bug. i386 is another matter.
As I recall there are data structures like the IDT that only have a 32bit base address.
According to the bzImage header we don't support ramdisks above 4G. I think we also have a 32bit address for the kernel command line in the bzImage header.
In the case of kdump in particular there is a need for DMAable memory and in general that means memory below 4G. So as long as we only support one memory extent for kdump it makes sense for that segment to be below 4G.
For a normal x86_64 kernel which gets to use most of the memory it definitely should be loadable anywhere in memory.
Eric
H. Peter Anvin
reviewerRe: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 7 lines · Eric W. Biederman
Quoted 3 lines
Seriously, any case where we can't load anywhere in physical ram on x86-64 is a bug. i386 is another matter.
As I recall there are data structures like the IDT that only have a 32bit base address.
Not true. The only one I know of is memory for the trampoline which has to be below 1M. The < 1M space is already handled specially for good reason.
Quoted 3 lines
According to the bzImage header we don't support ramdisks above 4G. I think we also have a 32bit address for the kernel command line in the bzImage header.
There are pointers in the bzImage header, that is true. We can fix that problem, though, at least for entry via the 64-bit entry point.
Quoted 4 lines
In the case of kdump in particular there is a need for DMAable memory and in general that means memory below 4G. So as long as we only support one memory extent for kdump it makes sense for that segment to be below 4G.
"In general" meaning "no iotlb"? In that case you have some unknown address space restriction which may or may not be 4G...
Quoted 2 lines
For a normal
x86_64kernel which gets to use most of the memory it definitely should be loadable anywhere in memory.
Yes. We should fix problems, like the limitations in the boot_params structure.
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
In reply to Stefano StabelliniQuoted 43 lines · Stefano Stabellini
Quoted 42 lines · Yinghai Lu
After
| commit 8548c84da2f47e71bbbe300f55edb768492575f7 | Author: Takashi Iwai <[email protected]> | Date: Sun Oct 23 23:19:12 2011 +0200 | | x86: Fix S4 regression | | Commit 4b239f458 ("x86-64, mm: Put early page table high") causes a S4 | regression since 2.6.39, namely the machine reboots occasionally at S4 | resume. It doesn't happen always, overall rate is about 1/20. But, | like other bugs, once when this happens, it continues to happen. | | This patch fixes the problem by essentially reverting the memory | assignment in the older way.Have some page table around 512M again, that will prevent kdump to find 512M under 768M.
We need revert that reverting, so we could put page table high again for 64bit.
Takashi agreed that S4 regression could be something else.
https://lkml.org/lkml/2012/6/15/182Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/mm/init.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)arch/x86/mm/init.c +1
-1@@ -76,8 +76,8 @@ static void __init find_early_table_space(struct map_range *mr,#ifdef CONFIG_X86_32 /* for fixmap */ tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); -#endif good_end = max_pfn_mapped <<PAGE_SHIFT ; +#endif
Quoted 5 lines
arch/x86/mm/init.c static void __init find_early_table_space(struct map_range *mr, · line 83
Quoted 2 lines
arch/x86/mm/init.c +0
-0base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE );if (!base)Isn't this going to cause
init_memory_mappingto allocate pagetable pages from memory not yet mapped?
but 64bit is using ioremap to access those page table buf.
Quoted 4 lines
Last time I spoke with HPA and Thomas about this, they seem to agree that it isn't a very good idea.
Also, it is proven to cause a certain amount of headaches on Xen, see commitd8aa5ec3382e6a545b8f25178d1e0992d4927f19.
this patchset will allocate page table buf one time only. So could use ram under 1M to map that page table at first.
so that will make it xen happy ?
Thanks
Yinghai
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 51 lines · Yinghai Lu
Quoted 43 lines · Stefano Stabellini
Quoted 42 lines · Yinghai Lu
After
| commit 8548c84da2f47e71bbbe300f55edb768492575f7 | Author: Takashi Iwai <[email protected]> | Date: Sun Oct 23 23:19:12 2011 +0200 | | x86: Fix S4 regression | | Commit 4b239f458 ("x86-64, mm: Put early page table high") causes a S4 | regression since 2.6.39, namely the machine reboots occasionally at S4 | resume. It doesn't happen always, overall rate is about 1/20. But, | like other bugs, once when this happens, it continues to happen. | | This patch fixes the problem by essentially reverting the memory | assignment in the older way.Have some page table around 512M again, that will prevent kdump to find 512M under 768M.
We need revert that reverting, so we could put page table high again for 64bit.
Takashi agreed that S4 regression could be something else.
https://lkml.org/lkml/2012/6/15/182Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/mm/init.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)arch/x86/mm/init.c +1
-1@@ -76,8 +76,8 @@ static void __init find_early_table_space(struct map_range *mr,#ifdef CONFIG_X86_32 /* for fixmap */ tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); -#endif good_end = max_pfn_mapped <<PAGE_SHIFT ; +#endif Quoted 5 lines
arch/x86/mm/init.c static void __init find_early_table_space(struct map_range *mr, · line 83
Quoted 2 lines
arch/x86/mm/init.c +0
-0base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE );if (!base)Isn't this going to cause
init_memory_mappingto allocate pagetable pages from memory not yet mapped?
Quoted 8 lines
but 64bit is using ioremap to access those page table buf.
Quoted 4 lines
Last time I spoke with HPA and Thomas about this, they seem to agree that it isn't a very good idea.
Also, it is proven to cause a certain amount of headaches on Xen, see commitd8aa5ec3382e6a545b8f25178d1e0992d4927f19.this patchset will allocate page table buf one time only.
As in, if your machine has 8GB, it will allocate pagetables that span 0->8GB at once?
Quoted 1 line
So could use ram under 1M to map that page table at first.
Could or does this patch do it? And why 1MB?
Quoted 2 lines
so that will make it xen happy ?
The issues that Xen faces are purely due to the fact that they must be RO when they are in use. I believe (and without actually checking it just to make sure) that it does not matter where the page-tables are located. But with the current generic code the location is quite linear: it starts with pgt_buf_start and goes up to pgt_buf_top. So how would this patch move the location of the page-table to be under 1MB?
Perhaps we are talking about seperate topics?
My recollection of memblock_find_in_range is that it will try the end of the range to find a suitable "chunk" that satisfies the 'size' and 'aligment' parameters?
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 3 lines · Konrad Rzeszutek Wilk
Quoted 1 line
So could use ram under 1M to map that page table at first.
Could or does this patch do it? And why 1MB?
can you or stefano could test attached patch on xen ?
that will map the page table buffer that will be used.
under 1M, still 4k there, so there will be no page table around 512M.
Quoted 10 lines
Quoted 2 lines
so that will make it xen happy ?
The issues that Xen faces are purely due to the fact that they must be RO when they are in use. I believe (and without actually checking it just to make sure) that it does not matter where the page-tables are located. But with the current generic code the location is quite linear: it starts with
pgt_buf_startand goes up topgt_buf_top. So how would this patch move the location of the page-table to be under 1MB?
just page table buf's page table.
Thanks
Yinghai
--- arch/x86/mm/init.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
arch/x86/mm/init.c +47 -0
@@ -359,6 +359,39 @@ unsigned long __init_refok init_memory_mreturn ret >>PAGE_SHIFT ; } +static long __init early_init_memory_mapping (unsigned long start, +unsigned long end) +{ +unsigned long ret; +unsigned long tables, good_end; + +pr_info ("init_memory_mapping: [mem %#010lx-%#010lx]\n" , + start, end -1 ); + + tables =calculate_table_space_size (start, end); + good_end =ISA_END_ADDRESS ; + +find_early_table_space (0 , good_end, tables); + +printk (KERN_DEBUG "kernel direct mapping tables from %#lx to %#lx @ [mem %#010lx-%#010lx] prealloc\n" , + start, end -1 , pgt_buf_start <<PAGE_SHIFT , + (pgt_buf_top <<PAGE_SHIFT ) -1 ); + + ret =init_memory_mapping (start, end); + +if (pgt_buf_end > pgt_buf_start) { +printk (KERN_DEBUG "kernel direct mapping tables from %#lx to %#lx @ [mem %#010lx-%#010lx] final\n" , + start, end -1 , pgt_buf_start <<PAGE_SHIFT , + (pgt_buf_end <<PAGE_SHIFT ) -1 ); + x86_init.mapping.pagetable_reserve (PFN_PHYS (pgt_buf_start), +PFN_PHYS (pgt_buf_end)); + } + +early_memtest (start, end); + +return ret; +} +/* * Iterate through E820 memory map and create direct mappings for only E820_RAM * regions. We cannot simply create direct mappings for all pfns from
@@ -395,6 +428,20 @@ void __init init_mem_mapping(void)#endif walk_ram_ranges (size_work_fn, &tables);find_early_table_space (0 , good_end, tables); + +if (pgt_buf_top >= max_pfn_mapped) { +unsigned long old_pgt_buf_start = pgt_buf_start; +unsigned long old_pgt_buf_end = pgt_buf_end; +unsigned long old_pgt_buf_top = pgt_buf_top; + +early_init_memory_mapping (old_pgt_buf_start <<PAGE_SHIFT , + old_pgt_buf_top <<PAGE_SHIFT ); + + pgt_buf_start = old_pgt_buf_start; + pgt_buf_end = old_pgt_buf_end; + pgt_buf_top = old_pgt_buf_top; + } +printk (KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx] prealloc\n" , end -1 , pgt_buf_start <<PAGE_SHIFT , (pgt_buf_top <<PAGE_SHIFT ) -1 );
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 8 lines · Yinghai Lu
Quoted 3 lines · Konrad Rzeszutek Wilk
Quoted 1 line
So could use ram under 1M to map that page table at first.
Could or does this patch do it? And why 1MB?
can you or stefano could test attached patch on xen ?
on top of
http://git.kernel.org/?p=linux/kernel/git/tip/tip.git;a=shortlog;h=refs/heads/x86/mm2
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/mm2
H. Peter Anvin
reviewerRe: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 7 lines · Yinghai Lu
Quoted 6 lines · Yinghai Lu
Quoted 3 lines · Konrad Rzeszutek Wilk
Quoted 1 line
So could use ram under 1M to map that page table at first.
Could or does this patch do it? And why 1MB?
Quoted 8 lines
Quoted 2 lines
can you or stefano could test attached patch on xen ?
on top of
http://git.kernel.org/?p=linux/kernel/git/tip/tip.git;a=shortlog;h=refs/heads/x86/mm2
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.gitx86/mm2
No, no, not yet another ad hoc hack... please.
-hpa
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 10 lines · H. Peter Anvin
Quoted 9 lines · Yinghai Lu
Quoted 8 lines · Yinghai Lu
Quoted 3 lines · Konrad Rzeszutek Wilk
Quoted 1 line
So could use ram under 1M to map that page table at first.
Could or does this patch do it? And why 1MB?
can you or stefano could test attached patch on xen ?
Quoted 9 lines
Quoted 6 lines
on top of
http://git.kernel.org/?p=linux/kernel/git/tip/tip.git;a=shortlog;h=refs/heads/x86/mm2
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.gitx86/mm2No, no, not yet another ad hoc hack... please.
or let xen map that page table by itself at first?
H. Peter Anvin
reviewerRe: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 3 lines · Yinghai Lu
or let xen map that page table by itself at first?
See my other post. This is bringing up the Kernel Summit algorithm again.
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 3 lines · H. Peter Anvin
See my other post. This is bringing up the Kernel Summit algorithm again.
sure. please check if you are ok with attached one on top of x86/mm2
Thanks
Yinghai
Subject: [PATCH] x86: get early page table from BRK
set pgt_buf early from BRK, and use it to map page table at first.
also use the left at first, then use new extend one.
--- arch/x86/include/asm/init.h | 4 ++++ arch/x86/include/asm/pgtable.h | 1 + arch/x86/kernel/setup.c | 2 ++ arch/x86/mm/init.c | 23 +++++++++++++++++++++++ arch/x86/mm/init_32.c | 8 ++++++-- arch/x86/mm/init_64.c | 8 ++++++-- 6 files changed, 42 insertions(+), 4 deletions(-)
arch/x86/include/asm/pgtable.h +1 -0
@@ -599,6 +599,7 @@ static inline int pgd_none(pgd_t pgd)extern int direct_gbpages;void init_mem_mapping (void ); +void early_alloc_pgt_buf (void );/* local pte updates need not use xchg for locking */ static inline pte_t native_local_ptep_get_and_clear (pte_t *ptep)
arch/x86/kernel/setup.c +2 -0
@@ -950,6 +950,8 @@ void __init setup_arch(char **cmdline_p)reserve_ibft_region (); +early_alloc_pgt_buf (); +/* * Need to conclude brk, before memblock_x86_fill() * it could use memblock_find_in_range, could overlap with
arch/x86/mm/init.c +23 -0
@@ -21,6 +21,10 @@ unsigned long __initdata pgt_buf_start;unsigned long __meminitdata pgt_buf_end;unsigned long __meminitdata pgt_buf_top; +unsigned long __initdata early_pgt_buf_start; +unsigned long __meminitdata early_pgt_buf_end; +unsigned long __meminitdata early_pgt_buf_top; +int after_bootmem;int direct_gbpages
@@ -291,6 +295,11 @@ static void __init find_early_table_spacif (!base)panic ("Cannot find space for the kernel page tables" ); +init_memory_mapping (base, base + tables); +printk (KERN_DEBUG "kernel direct mapping tables from %#llx to %#llx @ [mem %#010lx-%#010lx]\n" , + base, base + tables -1 , early_pgt_buf_start <<PAGE_SHIFT , + (early_pgt_buf_end <<PAGE_SHIFT ) -1 ); + pgt_buf_start = base >>PAGE_SHIFT ; pgt_buf_end = pgt_buf_start; pgt_buf_top = pgt_buf_start + (tables >>PAGE_SHIFT );
@@ -437,6 +446,20 @@ void __init init_mem_mapping(void)early_memtest (0 , max_pfn_mapped <<PAGE_SHIFT ); } +RESERVE_BRK (early_pgt_alloc,16384 ); + +void __init early_alloc_pgt_buf (void ) +{ +unsigned long tables =13864 ; +phys_addr_t base; + + base =__pa (extend_brk (tables,PAGE_SIZE )); + + early_pgt_buf_start = base >>PAGE_SHIFT ; + early_pgt_buf_end = early_pgt_buf_start; + early_pgt_buf_top = early_pgt_buf_start + (tables >>PAGE_SHIFT ); +} +/* * devmem_is_allowed() checks to see if /dev/mem access to a certain address * is valid. The argument is a physical page number.
arch/x86/mm/init_32.c +6 -2
@@ -61,10 +61,14 @@ bool __read_mostly __vmalloc_start_set =static __init void *alloc_low_page (void ) { -unsigned long pfn = pgt_buf_end++; +unsigned long pfn;void *adr; -if (pfn >= pgt_buf_top) +if (early_pgt_buf_end < early_pgt_buf_top) + pfn = early_pgt_buf_end++; +else if (pgt_buf_end < pgt_buf_top) + pfn = pgt_buf_end++; +else panic ("alloc_low_page: ran out of memory" ); adr =__va (pfn *PAGE_SIZE );
arch/x86/mm/init_64.c +6 -2
@@ -318,7 +318,7 @@ void __init cleanup_highmap(void)static __ref void *alloc_low_page (unsigned long *phys) { -unsigned long pfn = pgt_buf_end++; +unsigned long pfn;void *adr;if (after_bootmem) {
@@ -328,7 +328,11 @@ static __ref void *alloc_low_page(unsignreturn adr; } -if (pfn >= pgt_buf_top) +if (early_pgt_buf_end < early_pgt_buf_top) + pfn = early_pgt_buf_end++; +else if (pgt_buf_end < pgt_buf_top) + pfn = pgt_buf_end++; +else panic ("alloc_low_page: ran out of memory" ); adr =early_memremap (pfn *PAGE_SIZE ,PAGE_SIZE );
arch/x86/include/asm/init.h +4 -0
@@ -16,4 +16,8 @@ extern unsigned long __initdata pgt_buf_extern unsigned long __meminitdata pgt_buf_end;extern unsigned long __meminitdata pgt_buf_top; +extern unsigned long __initdata early_pgt_buf_start; +extern unsigned long __meminitdata early_pgt_buf_end; +extern unsigned long __meminitdata early_pgt_buf_top; +#endif /* _ASM_X86_INIT_32_H */
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 7 lines · Yinghai Lu
Quoted 3 lines · H. Peter Anvin
See my other post. This is bringing up the Kernel Summit algorithm again.
sure. please check if you are ok with attached one on top of x86/mm2
Quoted 7 lines
Subject: [PATCH] x86: get early page table from BRK
set
pgt_bufearly from BRK, and use it to map page table at first.also use the left at first, then use new extend one.
Signed-off-by Yinghai Lu <[email protected]>
If I read the patch correctly, it wouldn't actually change the pagetable allocation flow or implement Peter's suggestion.
However it would pre-map (pgt_buf_start-pgt_buf_top) using brk memory.
So, if that's correct, we could remove the early_memremap call from alloc_low_page and map_low_page, right?
Also the patch introduces an additional range of pagetable pages (early_pgt_buf_start-early_pgt_buf_top) and that would need to be communicated somehow to Xen (that at the moment assumes that the range is pgt_buf_start-pgt_buf_top. Pretty bad).
Overall I still prefer Peter's suggestion :)
Quoted 129 lines
--- arch/x86/include/asm/init.h | 4 ++++ arch/x86/include/asm/pgtable.h | 1 + arch/x86/kernel/setup.c | 2 ++ arch/x86/mm/init.c | 23 +++++++++++++++++++++++ arch/x86/mm/init_32.c | 8 ++++++-- arch/x86/mm/init_64.c | 8 ++++++-- 6 files changed, 42 insertions(+), 4 deletions(-)Index:
linux-2.6/arch/x86/include/asm/pgtable.h
===================================================================arch/x86/include/asm/pgtable.h +1
-0@@ -599,6 +599,7 @@ static inline int pgd_none(pgd_t pgd)extern int direct_gbpages;void init_mem_mapping (void ); +void early_alloc_pgt_buf (void );/* local pte updates need not use xchg for locking */ static inline pte_t native_local_ptep_get_and_clear (pte_t *ptep)Index:
linux-2.6/arch/x86/kernel/setup.c
===================================================================arch/x86/kernel/setup.c +2
-0@@ -950,6 +950,8 @@ void __init setup_arch(char **cmdline_p)reserve_ibft_region (); +early_alloc_pgt_buf (); +/* * Need to conclude brk, before memblock_x86_fill() * it could use memblock_find_in_range, could overlap with Index:
linux-2.6/arch/x86/mm/init.c
===================================================================arch/x86/mm/init.c +23
-0@@ -21,6 +21,10 @@ unsigned long __initdata pgt_buf_start;unsigned long __meminitdata pgt_buf_end;unsigned long __meminitdata pgt_buf_top; +unsigned long __initdata early_pgt_buf_start; +unsigned long __meminitdata early_pgt_buf_end; +unsigned long __meminitdata early_pgt_buf_top; +int after_bootmem;int direct_gbpages@@ -291,6 +295,11 @@ static void __init find_early_table_spacif (!base)panic ("Cannot find space for the kernel page tables" ); +init_memory_mapping (base, base + tables); +printk (KERN_DEBUG "kernel direct mapping tables from %#llx to %#llx @ [mem %#010lx-%#010lx]\n" , + base, base + tables -1 , early_pgt_buf_start <<PAGE_SHIFT , + (early_pgt_buf_end <<PAGE_SHIFT ) -1 ); + pgt_buf_start = base >>PAGE_SHIFT ; pgt_buf_end = pgt_buf_start; pgt_buf_top = pgt_buf_start + (tables >>PAGE_SHIFT );@@ -437,6 +446,20 @@ void __init init_mem_mapping(void)early_memtest (0 , max_pfn_mapped <<PAGE_SHIFT ); } +RESERVE_BRK (early_pgt_alloc,16384 ); + +void __init early_alloc_pgt_buf (void ) +{ +unsigned long tables =13864 ; +phys_addr_t base; + + base =__pa (extend_brk (tables,PAGE_SIZE )); + + early_pgt_buf_start = base >>PAGE_SHIFT ; + early_pgt_buf_end = early_pgt_buf_start; + early_pgt_buf_top = early_pgt_buf_start + (tables >>PAGE_SHIFT ); +} +/* * devmem_is_allowed() checks to see if /dev/mem access to a certain address * is valid. The argument is a physical page number. Index:
linux-2.6/arch/x86/mm/init_32.c
===================================================================arch/x86/mm/init_32.c +6
-2@@ -61,10 +61,14 @@ bool __read_mostly __vmalloc_start_set =static __init void *alloc_low_page (void ) { -unsigned long pfn = pgt_buf_end++; +unsigned long pfn;void *adr; -if (pfn >= pgt_buf_top) +if (early_pgt_buf_end < early_pgt_buf_top) + pfn = early_pgt_buf_end++; +else if (pgt_buf_end < pgt_buf_top) + pfn = pgt_buf_end++; +else panic ("alloc_low_page: ran out of memory" ); adr =__va (pfn *PAGE_SIZE );Index:
linux-2.6/arch/x86/mm/init_64.c
===================================================================arch/x86/mm/init_64.c +6
-2@@ -318,7 +318,7 @@ void __init cleanup_highmap(void)static __ref void *alloc_low_page (unsigned long *phys) { -unsigned long pfn = pgt_buf_end++; +unsigned long pfn;void *adr;if (after_bootmem) {@@ -328,7 +328,11 @@ static __ref void *alloc_low_page(unsignreturn adr; } -if (pfn >= pgt_buf_top) +if (early_pgt_buf_end < early_pgt_buf_top) + pfn = early_pgt_buf_end++; +else if (pgt_buf_end < pgt_buf_top) + pfn = pgt_buf_end++; +else panic ("alloc_low_page: ran out of memory" ); adr =early_memremap (pfn *PAGE_SIZE ,PAGE_SIZE );
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
Quoted 20 lines · Stefano Stabellini
Quoted 7 lines · Yinghai Lu
Quoted 3 lines · H. Peter Anvin
See my other post. This is bringing up the Kernel Summit algorithm again.
sure. please check if you are ok with attached one on top of x86/mm2
Quoted 7 lines
Subject: [PATCH] x86: get early page table from BRK
set
pgt_bufearly from BRK, and use it to map page table at first.also use the left at first, then use new extend one.
Signed-off-by Yinghai Lu <[email protected]>If I read the patch correctly, it wouldn't actually change the pagetable allocation flow or implement Peter's suggestion.
However it would pre-map (pgt_buf_start-pgt_buf_top) using brk memory.
Quoted 7 lines
So, if that's correct, we could remove the
early_memremapcall fromalloc_low_pageandmap_low_page, right?Also the patch introduces an additional range of pagetable pages (early_pgt_buf_start-early_pgt_buf_top) and that would need to be communicated somehow to Xen (that at the moment assumes that the range is pgt_buf_start-pgt_buf_top. Pretty bad).
that will need extra two lines for xen:
@@ -430,6 +439,8 @@ void __init init_mem_mapping(void)
x86_init.mapping.pagetable_reserve(PFN_PHYS(pgt_buf_start),
PFN_PHYS(pgt_buf_end));
}
+ x86_init.mapping.pagetable_reserve(PFN_PHYS(early_pgt_buf_start),
+ PFN_PHYS(early_pgt_buf_end));
/* stop the wrong using */
pgt_buf_top = 0;
Quoted 133 lines
Overall I still prefer Peter's suggestion :)
Quoted 129 lines
--- arch/x86/include/asm/init.h | 4 ++++ arch/x86/include/asm/pgtable.h | 1 + arch/x86/kernel/setup.c | 2 ++ arch/x86/mm/init.c | 23 +++++++++++++++++++++++ arch/x86/mm/init_32.c | 8 ++++++-- arch/x86/mm/init_64.c | 8 ++++++-- 6 files changed, 42 insertions(+), 4 deletions(-)Index:
linux-2.6/arch/x86/include/asm/pgtable.h
===================================================================arch/x86/include/asm/pgtable.h +1
-0@@ -599,6 +599,7 @@ static inline int pgd_none(pgd_t pgd)extern int direct_gbpages;void init_mem_mapping (void ); +void early_alloc_pgt_buf (void );/* local pte updates need not use xchg for locking */ static inline pte_t native_local_ptep_get_and_clear (pte_t *ptep)Index:
linux-2.6/arch/x86/kernel/setup.c
===================================================================arch/x86/kernel/setup.c +2
-0@@ -950,6 +950,8 @@ void __init setup_arch(char **cmdline_p)reserve_ibft_region (); +early_alloc_pgt_buf (); +/* * Need to conclude brk, before memblock_x86_fill() * it could use memblock_find_in_range, could overlap with Index:
linux-2.6/arch/x86/mm/init.c
===================================================================arch/x86/mm/init.c +23
-0@@ -21,6 +21,10 @@ unsigned long __initdata pgt_buf_start;unsigned long __meminitdata pgt_buf_end;unsigned long __meminitdata pgt_buf_top; +unsigned long __initdata early_pgt_buf_start; +unsigned long __meminitdata early_pgt_buf_end; +unsigned long __meminitdata early_pgt_buf_top; +int after_bootmem;int direct_gbpages@@ -291,6 +295,11 @@ static void __init find_early_table_spacif (!base)panic ("Cannot find space for the kernel page tables" ); +init_memory_mapping (base, base + tables); +printk (KERN_DEBUG "kernel direct mapping tables from %#llx to %#llx @ [mem %#010lx-%#010lx]\n" , + base, base + tables -1 , early_pgt_buf_start <<PAGE_SHIFT , + (early_pgt_buf_end <<PAGE_SHIFT ) -1 ); + pgt_buf_start = base >>PAGE_SHIFT ; pgt_buf_end = pgt_buf_start; pgt_buf_top = pgt_buf_start + (tables >>PAGE_SHIFT );@@ -437,6 +446,20 @@ void __init init_mem_mapping(void)early_memtest (0 , max_pfn_mapped <<PAGE_SHIFT ); } +RESERVE_BRK (early_pgt_alloc,16384 ); + +void __init early_alloc_pgt_buf (void ) +{ +unsigned long tables =13864 ; +phys_addr_t base; + + base =__pa (extend_brk (tables,PAGE_SIZE )); + + early_pgt_buf_start = base >>PAGE_SHIFT ; + early_pgt_buf_end = early_pgt_buf_start; + early_pgt_buf_top = early_pgt_buf_start + (tables >>PAGE_SHIFT ); +} +/* * devmem_is_allowed() checks to see if /dev/mem access to a certain address * is valid. The argument is a physical page number. Index:
linux-2.6/arch/x86/mm/init_32.c
===================================================================arch/x86/mm/init_32.c +6
-2@@ -61,10 +61,14 @@ bool __read_mostly __vmalloc_start_set =static __init void *alloc_low_page (void ) { -unsigned long pfn = pgt_buf_end++; +unsigned long pfn;void *adr; -if (pfn >= pgt_buf_top) +if (early_pgt_buf_end < early_pgt_buf_top) + pfn = early_pgt_buf_end++; +else if (pgt_buf_end < pgt_buf_top) + pfn = pgt_buf_end++; +else panic ("alloc_low_page: ran out of memory" ); adr =__va (pfn *PAGE_SIZE );Index:
linux-2.6/arch/x86/mm/init_64.c
===================================================================arch/x86/mm/init_64.c +6
-2@@ -318,7 +318,7 @@ void __init cleanup_highmap(void)static __ref void *alloc_low_page (unsigned long *phys) { -unsigned long pfn = pgt_buf_end++; +unsigned long pfn;void *adr;if (after_bootmem) {@@ -328,7 +328,11 @@ static __ref void *alloc_low_page(unsignreturn adr; } -if (pfn >= pgt_buf_top) +if (early_pgt_buf_end < early_pgt_buf_top) + pfn = early_pgt_buf_end++; +else if (pgt_buf_end < pgt_buf_top) + pfn = pgt_buf_end++; +else panic ("alloc_low_page: ran out of memory" ); adr =early_memremap (pfn *PAGE_SIZE ,PAGE_SIZE );
cover x86: pre mapping page table to make xen happy.
on top of tip/x86/mm2
also remove early_ioremap in page table accessing.
Yinghai Lu (3):
x86: get early page table from BRK
x86, mm: Don't clear page table if next range is ram x86, mm: Remove early_memremap workaround for page table accessing
arch/x86/include/asm/init.h | 4 ++ arch/x86/include/asm/pgtable.h | 1 + arch/x86/kernel/setup.c | 2 + arch/x86/mm/init.c | 25 ++++++++++++ arch/x86/mm/init_32.c | 8 +++- arch/x86/mm/init_64.c | 85 ++++++++++++++-------------------------- 6 files changed, 67 insertions(+), 58 deletions(-)
Signature · 1 line
1.7.7
PATCH 1/3 x86: get early page table from BRK
set pgt_buf early from BRK, and use it to map page table at first.
also use the left at first, then use new extend one.
-v2: extra xen call back for that new range.
--- arch/x86/include/asm/init.h | 4 ++++ arch/x86/include/asm/pgtable.h | 1 + arch/x86/kernel/setup.c | 2 ++ arch/x86/mm/init.c | 25 +++++++++++++++++++++++++ arch/x86/mm/init_32.c | 8 ++++++-- arch/x86/mm/init_64.c | 8 ++++++-- 6 files changed, 44 insertions(+), 4 deletions(-)
arch/x86/include/asm/init.h +4 -0
@@ -16,4 +16,8 @@ extern unsigned long __initdata pgt_buf_start;extern unsigned long __meminitdata pgt_buf_end;extern unsigned long __meminitdata pgt_buf_top; +extern unsigned long __initdata early_pgt_buf_start; +extern unsigned long __meminitdata early_pgt_buf_end; +extern unsigned long __meminitdata early_pgt_buf_top; +#endif /* _ASM_X86_INIT_32_H */
arch/x86/include/asm/pgtable.h +1 -0
@@ -599,6 +599,7 @@ static inline int pgd_none(pgd_t pgd)extern int direct_gbpages;void init_mem_mapping (void ); +void early_alloc_pgt_buf (void );/* local pte updates need not use xchg for locking */ static inline pte_t native_local_ptep_get_and_clear (pte_t *ptep)
arch/x86/kernel/setup.c +2 -0
@@ -896,6 +896,8 @@ void __init setup_arch(char **cmdline_p)reserve_ibft_region (); +early_alloc_pgt_buf (); +/* * Need to conclude brk, before memblock_x86_fill() * it could use memblock_find_in_range, could overlap with
arch/x86/mm/init.c +25 -0
@@ -21,6 +21,10 @@ unsigned long __initdata pgt_buf_start;unsigned long __meminitdata pgt_buf_end;unsigned long __meminitdata pgt_buf_top; +unsigned long __initdata early_pgt_buf_start; +unsigned long __meminitdata early_pgt_buf_end; +unsigned long __meminitdata early_pgt_buf_top; +int after_bootmem;int direct_gbpages
@@ -291,6 +295,11 @@ static void __init find_early_table_space(unsigned long start,if (!base)panic ("Cannot find space for the kernel page tables" ); +init_memory_mapping (base, base + tables); +printk (KERN_DEBUG "kernel direct mapping tables from %#llx to %#llx @ [mem %#010lx-%#010lx]\n" , + base, base + tables -1 , early_pgt_buf_start <<PAGE_SHIFT , + (early_pgt_buf_end <<PAGE_SHIFT ) -1 ); + pgt_buf_start = base >>PAGE_SHIFT ; pgt_buf_end = pgt_buf_start; pgt_buf_top = pgt_buf_start + (tables >>PAGE_SHIFT );
@@ -430,6 +439,8 @@ void __init init_mem_mapping(void) x86_init.mapping.pagetable_reserve (PFN_PHYS (pgt_buf_start),PFN_PHYS (pgt_buf_end)); } + x86_init.mapping.pagetable_reserve (PFN_PHYS (early_pgt_buf_start), +PFN_PHYS (early_pgt_buf_end));/* stop the wrong using */ pgt_buf_top =0 ;
@@ -437,6 +448,20 @@ void __init init_mem_mapping(void)early_memtest (0 , max_pfn_mapped <<PAGE_SHIFT ); } +RESERVE_BRK (early_pgt_alloc,16384 ); + +void __init early_alloc_pgt_buf (void ) +{ +unsigned long tables =16384 ; +phys_addr_t base; + + base =__pa (extend_brk (tables,PAGE_SIZE )); + + early_pgt_buf_start = base >>PAGE_SHIFT ; + early_pgt_buf_end = early_pgt_buf_start; + early_pgt_buf_top = early_pgt_buf_start + (tables >>PAGE_SHIFT ); +} +/* * devmem_is_allowed() checks to see if /dev/mem access to a certain address * is valid. The argument is a physical page number.
arch/x86/mm/init_32.c +6 -2
@@ -61,10 +61,14 @@ bool __read_mostly __vmalloc_start_set = false;static __init void *alloc_low_page (void ) { -unsigned long pfn = pgt_buf_end++; +unsigned long pfn;void *adr; -if (pfn >= pgt_buf_top) +if (early_pgt_buf_end < early_pgt_buf_top) + pfn = early_pgt_buf_end++; +else if (pgt_buf_end < pgt_buf_top) + pfn = pgt_buf_end++; +else panic ("alloc_low_page: ran out of memory" ); adr =__va (pfn *PAGE_SIZE );
arch/x86/mm/init_64.c +6 -2
@@ -316,7 +316,7 @@ void __init cleanup_highmap(void)static __ref void *alloc_low_page (unsigned long *phys) { -unsigned long pfn = pgt_buf_end++; +unsigned long pfn;void *adr;if (after_bootmem) {
@@ -326,7 +326,11 @@ static __ref void *alloc_low_page(unsigned long *phys)return adr; } -if (pfn >= pgt_buf_top) +if (early_pgt_buf_end < early_pgt_buf_top) + pfn = early_pgt_buf_end++; +else if (pgt_buf_end < pgt_buf_top) + pfn = pgt_buf_end++; +else panic ("alloc_low_page: ran out of memory" ); adr =early_memremap (pfn *PAGE_SIZE ,PAGE_SIZE );
Signature · 1 line
1.7.7
Re: [PATCH 1/3] x86: get early page table from BRK
Quoted 82 lines · Yinghai Lu
set
pgt_bufearly from BRK, and use it to map page table at first.also use the left at first, then use new extend one.
-v2: extra xen call back for that new range.
Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/include/asm/init.h | 4 ++++ arch/x86/include/asm/pgtable.h | 1 + arch/x86/kernel/setup.c | 2 ++ arch/x86/mm/init.c | 25 +++++++++++++++++++++++++ arch/x86/mm/init_32.c | 8 ++++++-- arch/x86/mm/init_64.c | 8 ++++++-- 6 files changed, 44 insertions(+), 4 deletions(-)arch/x86/include/asm/init.h +4
-0@@ -16,4 +16,8 @@ extern unsigned long __initdata pgt_buf_start;extern unsigned long __meminitdata pgt_buf_end;extern unsigned long __meminitdata pgt_buf_top; +extern unsigned long __initdata early_pgt_buf_start; +extern unsigned long __meminitdata early_pgt_buf_end; +extern unsigned long __meminitdata early_pgt_buf_top; +#endif /* _ASM_X86_INIT_32_H */ arch/x86/include/asm/pgtable.h +1
-0@@ -599,6 +599,7 @@ static inline int pgd_none(pgd_t pgd)extern int direct_gbpages;void init_mem_mapping (void ); +void early_alloc_pgt_buf (void );/* local pte updates need not use xchg for locking */ static inline pte_t native_local_ptep_get_and_clear (pte_t *ptep)arch/x86/kernel/setup.c +2
-0@@ -896,6 +896,8 @@ void __init setup_arch(char **cmdline_p)reserve_ibft_region (); +early_alloc_pgt_buf (); +/* * Need to conclude brk, before memblock_x86_fill() * it could use memblock_find_in_range, could overlap with arch/x86/mm/init.c +9
-0@@ -21,6 +21,10 @@ unsigned long __initdata pgt_buf_start;unsigned long __meminitdata pgt_buf_end;unsigned long __meminitdata pgt_buf_top; +unsigned long __initdata early_pgt_buf_start; +unsigned long __meminitdata early_pgt_buf_end; +unsigned long __meminitdata early_pgt_buf_top; +int after_bootmem;int direct_gbpages@@ -291,6 +295,11 @@ static void __init find_early_table_space(unsigned long start,if (!base)panic ("Cannot find space for the kernel page tables" ); +init_memory_mapping (base, base + tables); +printk (KERN_DEBUG "kernel direct mapping tables from %#llx to %#llx @ [mem %#010lx-%#010lx]\n" , + base, base + tables -1 , early_pgt_buf_start <<PAGE_SHIFT , + (early_pgt_buf_end <<PAGE_SHIFT ) -1 ); + pgt_buf_start = base >>PAGE_SHIFT ; pgt_buf_end = pgt_buf_start; pgt_buf_top = pgt_buf_start + (tables >>PAGE_SHIFT );
arch/x86/mm/init.c void __init init_mem_mapping(void) · line 443
Quoted 5 lines
arch/x86/mm/init.c +2
-0@@ -430,6 +439,8 @@ void __init init_mem_mapping(void) x86_init.mapping.pagetable_reserve (PFN_PHYS (pgt_buf_start),PFN_PHYS (pgt_buf_end)); } + x86_init.mapping.pagetable_reserve (PFN_PHYS (early_pgt_buf_start), +PFN_PHYS (early_pgt_buf_end));
pagetable_reserve is not the right hook: pagetable_reserve tells the subsystem that the memory range you are passing is going to be used for pagetable pages. It is used to reserve that range using memblock_reserve. On Xen is also used to mark RW any pages _outside_ that range that have been marked RO: implicitely we assume that the full range is pgt_buf_start-pgt_buf_top and we mark it RO (see Xen memory contraints on pagetable pages, as decribed by Konrad).
Calling pagetable_reserve(real_start, real_end) reserves real_start-real_end as pagetable pages and frees pgt_buf_start-real_start and real_end-pgt_buf_top.
So the problem is that at the moment we don't have a hook to say: "the range of pagetable pages is pgt_buf_start-pgt_buf_top". In fact if you give a look at arch/x86/xen/mmu.c you'll find few references to pgt_buf_start, pgt_buf_end, pgt_buf_top, that shouldn't really be there.
PATCH 2/3 x86, mm: Don't clear page table if next range is ram
In reply to Yinghai LuDuring adding code from BRK to map buffer for final page table,
It should be safe to remove early_memmap for page table accessing.
But get panic after that.
It turns out we clear the initial page table wrongly for next range that is separated by holes.
And it only happens when we are trying to map range one by one range.
After checking before clearing the related page table to fix the problem.
--- arch/x86/mm/init_64.c | 39 +++++++++++++++++++-------------------- 1 files changed, 19 insertions(+), 20 deletions(-)
arch/x86/mm/init_64.c +19 -20
@@ -367,20 +367,21 @@ static unsigned long __meminit phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end, pgprot_t prot) { -unsigned pages =0 ; +unsigned long pages =0 , next;unsigned long last_map_addr = end;int i;pte_t *pte = pte_page +pte_index (addr); -for (i =pte_index (addr); i <PTRS_PER_PTE ; i++, addr +=PAGE_SIZE , pte++) { +for (i =pte_index (addr); i <PTRS_PER_PTE ; i++, addr = next, pte++) { + next = (addr &PAGE_MASK ) +PAGE_SIZE ;if (addr >= end) { -if (!after_bootmem) { -for (; i <PTRS_PER_PTE ; i++, pte++) -set_pte (pte,__pte (0 )); - } -break ; +if (!after_bootmem && + addr < (2UL <<30 ) && + !e820_any_mapped (addr &PAGE_MASK , next,0 )) +set_pte (pte,__pte (0 )); +continue ; }/*
@@ -422,16 +423,15 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,pte_t *pte;pgprot_t new_prot = prot; + next = (address &PMD_MASK ) +PMD_SIZE ;if (address >= end) { -if (!after_bootmem) { -for (; i <PTRS_PER_PMD ; i++, pmd++) -set_pmd (pmd,__pmd (0 )); - } -break ; +if (!after_bootmem && + address < (2UL <<30 ) && + !e820_any_mapped (address &PMD_MASK , next,0 )) +set_pmd (pmd,__pmd (0 )); +continue ; } - next = (address &PMD_MASK ) +PMD_SIZE ; -if (pmd_val (*pmd)) {if (!pmd_large (*pmd)) {spin_lock (&init_mm.page_table_lock);
@@ -498,13 +498,12 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,pmd_t *pmd;pgprot_t prot =PAGE_KERNEL ; -if (addr >= end) -break ; - next = (addr &PUD_MASK ) +PUD_SIZE ; - -if (!after_bootmem && !e820_any_mapped (addr, next,0 )) { -set_pud (pud,__pud (0 )); +if (addr >= end) { +if (!after_bootmem && + addr < (2UL <<30 ) && + !e820_any_mapped (addr &PUD_MASK , next,0 )) +set_pud (pud,__pud (0 ));continue ; }
Signature · 1 line
1.7.7
Re: [PATCH 2/3] x86, mm: Don't clear page table if next range is ram
Quoted 8 lines · Yinghai Lu
During adding code from BRK to map buffer for final page table,
It should be safe to remove
early_memmapfor page table accessing.But get panic after that.
It turns out we clear the initial page table wrongly for next range that is separated by holes.
Were are the holes? Are these E820 holes?
Quoted 3 lines
And it only happens when we are trying to map range one by one range.
After checking before clearing the related page table to fix the problem.
Huh?
Quoted 23 lines
Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/mm/init_64.c | 39 +++++++++++++++++++-------------------- 1 files changed, 19 insertions(+), 20 deletions(-)arch/x86/mm/init_64.c +2
-2@@ -367,20 +367,21 @@ static unsigned long __meminit phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end, pgprot_t prot) { -unsigned pages =0 ; +unsigned long pages =0 , next;unsigned long last_map_addr = end;int i;pte_t *pte = pte_page +pte_index (addr); -for (i =pte_index (addr); i <PTRS_PER_PTE ; i++, addr +=PAGE_SIZE , pte++) { +for (i =pte_index (addr); i <PTRS_PER_PTE ; i++, addr = next, pte++) {
arch/x86/mm/init_64.c static unsigned long __meminit · line 381
Quoted 10 lines
arch/x86/mm/init_64.c +3
-5+ next = (addr &PAGE_MASK ) +PAGE_SIZE ;if (addr >= end) { -if (!after_bootmem) { -for (; i <PTRS_PER_PTE ; i++, pte++) -set_pte (pte,__pte (0 )); - } -break ; + if (!after_bootmem && + addr < (2UL<<30) &&
Why 2G?
arch/x86/mm/init_64.c static unsigned long __meminit · line 382
Quoted 1 line
arch/x86/mm/init_64.c +1
-0+ !e820_any_mapped(addr & PAGE_MASK, next, 0))
What is the 0 parameter for?
Quoted 29 lines
arch/x86/mm/init_64.c +8
-7+set_pte (pte,__pte (0 )); +continue ; }/* @@ -422,16 +423,15 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,pte_t *pte;pgprot_t new_prot = prot; + next = (address &PMD_MASK ) +PMD_SIZE ;if (address >= end) { -if (!after_bootmem) { -for (; i <PTRS_PER_PMD ; i++, pmd++) -set_pmd (pmd,__pmd (0 )); - } -break ; +if (!after_bootmem && + address < (2UL <<30 ) && + !e820_any_mapped (address &PMD_MASK , next,0 )) +set_pmd (pmd,__pmd (0 )); +continue ; } - next = (address &PMD_MASK ) +PMD_SIZE ; -if (pmd_val (*pmd)) {if (!pmd_large (*pmd)) {spin_lock (&init_mm.page_table_lock);
arch/x86/mm/init_64.c phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, · line 502
Quoted 5 lines
arch/x86/mm/init_64.c +0
-2@@ -498,13 +498,12 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,pmd_t *pmd;pgprot_t prot =PAGE_KERNEL ; -if (addr >= end) -break ;
Why do you get rid of that?
Quoted 22 lines
arch/x86/mm/init_64.c +5
-4- next = (addr &PUD_MASK ) +PUD_SIZE ; - -if (!after_bootmem && !e820_any_mapped (addr, next,0 )) { -set_pud (pud,__pud (0 )); +if (addr >= end) { +if (!after_bootmem && + addr < (2UL <<30 ) && + !e820_any_mapped (addr &PUD_MASK , next,0 )) +set_pud (pud,__pud (0 ));continue ; }Signature · 7 lines
1.7.7 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 2/3] x86, mm: Don't clear page table if next range is ram
Quoted 3 lines · Konrad Rzeszutek Wilk
Quoted 1 line
+ !e820_any_mapped(addr &
PAGE_MASK, next, 0))What is the 0 parameter for?
any type
if type != 0, the will only check entries with same type.
inte820_any_mapped(u64 start, u64 end, unsigned type)
{
int i;
for (i = 0; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
if (type && ei->type != type)
continue;
if (ei->addr >= end || ei->addr + ei->size <= start)
continue;
return 1;
}
return 0;
}Re: [PATCH 2/3] x86, mm: Don't clear page table if next range is ram
Quoted 6 lines · Yinghai Lu
Quoted 3 lines · Konrad Rzeszutek Wilk
Quoted 1 line
+ !e820_any_mapped(addr &
PAGE_MASK, next, 0))What is the 0 parameter for?
any type
OK, which means that it either should have a #define for it, or at least a comment, like:
0 /* any type */
as this would make it clear at first glance what it is - without having to dive in e820_any_mapped function to determine that.
Quoted 20 lines
if type != 0, the will only check entries with same type.
int
e820_any_mapped(u64 start, u64 end, unsigned type){ int i; for (i = 0; i < e820.nr_map; i++) { struct e820entry *ei = &e820.map[i]; if (type && ei->type != type) continue; if (ei->addr >= end || ei->addr + ei->size <= start) continue; return 1; } return 0; }
Re: [PATCH 2/3] x86, mm: Don't clear page table if next range is ram
Quoted 8 lines · Konrad Rzeszutek Wilk
Quoted 6 lines · Yinghai Lu
Quoted 3 lines · Konrad Rzeszutek Wilk
Quoted 1 line
+ !e820_any_mapped(addr &
PAGE_MASK, next, 0))What is the 0 parameter for?
any type
Quoted 7 lines
OK, which means that it either should have a #define for it, or at least a comment, like:
0 /* any type */
as this would make it clear at first glance what it is - without having to dive in
e820_any_mappedfunction to determine that.
yes, we should add E820_ANY_TYPE. and update e820_any_mapped to use it.
will address that later in another patch.
PATCH 3/3 x86, mm: Remove early_memremap workaround for page table accessing
In reply to Yinghai LuNot needed anymore after premaping page table buf and not clear initial page table wrongly.
--- arch/x86/mm/init_64.c | 38 ++++---------------------------------- 1 files changed, 4 insertions(+), 34 deletions(-)
arch/x86/mm/init_64.c +4 -34
@@ -333,36 +333,12 @@ static __ref void *alloc_low_page(unsigned long *phys)else panic ("alloc_low_page: ran out of memory" ); - adr =early_memremap (pfn *PAGE_SIZE ,PAGE_SIZE ); + adr =__va (pfn *PAGE_SIZE );clear_page (adr); *phys = pfn *PAGE_SIZE ;return adr; } -static __ref void *map_low_page (void *virt) -{ -void *adr; -unsigned long phys, left; - -if (after_bootmem) -return virt; - - phys =__pa (virt); - left = phys & (PAGE_SIZE -1 ); - adr =early_memremap (phys &PAGE_MASK ,PAGE_SIZE ); - adr = (void *)(((unsigned long )adr) | left); - -return adr; -} - -static __ref void unmap_low_page (void *adr) -{ -if (after_bootmem) -return ; - -early_iounmap ((void *)((unsigned long )adr &PAGE_MASK ),PAGE_SIZE ); -} -static unsigned long __meminit phys_pte_init (pte_t *pte_page,unsigned long addr,unsigned long end,pgprot_t prot)
@@ -435,10 +411,9 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,if (pmd_val (*pmd)) {if (!pmd_large (*pmd)) {spin_lock (&init_mm.page_table_lock); - pte =map_low_page ((pte_t *)pmd_page_vaddr (*pmd)); + pte = (pte_t *)pmd_page_vaddr (*pmd); last_map_addr =phys_pte_init (pte, address, end, prot); -unmap_low_page (pte);spin_unlock (&init_mm.page_table_lock);continue ; }
@@ -474,7 +449,6 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, pte =alloc_low_page (&pte_phys); last_map_addr =phys_pte_init (pte, address, end, new_prot); -unmap_low_page (pte);spin_lock (&init_mm.page_table_lock);pmd_populate_kernel (&init_mm, pmd,__va (pte_phys));
@@ -509,10 +483,9 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,if (pud_val (*pud)) {if (!pud_large (*pud)) { - pmd =map_low_page (pmd_offset (pud,0 )); + pmd =pmd_offset (pud,0 ); last_map_addr =phys_pmd_init (pmd, addr, end, page_size_mask, prot); -unmap_low_page (pmd);__flush_tlb_all ();continue ; }
@@ -548,7 +521,6 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, pmd =alloc_low_page (&pmd_phys); last_map_addr =phys_pmd_init (pmd, addr, end, page_size_mask, prot); -unmap_low_page (pmd);spin_lock (&init_mm.page_table_lock);pud_populate (&init_mm, pud,__va (pmd_phys));
@@ -584,17 +556,15 @@ kernel_physical_mapping_init(unsigned long start, next = end;if (pgd_val (*pgd)) { - pud =map_low_page ((pud_t *)pgd_page_vaddr (*pgd)); + pud = (pud_t *)pgd_page_vaddr (*pgd); last_map_addr =phys_pud_init (pud,__pa (start),__pa (end), page_size_mask); -unmap_low_page (pud);continue ; } pud =alloc_low_page (&pud_phys); last_map_addr =phys_pud_init (pud,__pa (start),__pa (next), page_size_mask); -unmap_low_page (pud);spin_lock (&init_mm.page_table_lock);pgd_populate (&init_mm, pgd,__va (pud_phys));
Signature · 1 line
1.7.7
Re: [PATCH 3/3] x86, mm: Remove early_memremap workaround for page table accessing
Quoted 2 lines · Yinghai Lu
Not needed anymore after premaping page table buf and not clear initial page table wrongly.
Your comment should include what patch made the iomap/iounmap part unnecessary.
.. and also explain how this work-around is not required anymore.
Quoted 116 lines
Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/mm/init_64.c | 38 ++++---------------------------------- 1 files changed, 4 insertions(+), 34 deletions(-)arch/x86/mm/init_64.c +4
-34@@ -333,36 +333,12 @@ static __ref void *alloc_low_page(unsigned long *phys)else panic ("alloc_low_page: ran out of memory" ); - adr =early_memremap (pfn *PAGE_SIZE ,PAGE_SIZE ); + adr =__va (pfn *PAGE_SIZE );clear_page (adr); *phys = pfn *PAGE_SIZE ;return adr; } -static __ref void *map_low_page (void *virt) -{ -void *adr; -unsigned long phys, left; - -if (after_bootmem) -return virt; - - phys =__pa (virt); - left = phys & (PAGE_SIZE -1 ); - adr =early_memremap (phys &PAGE_MASK ,PAGE_SIZE ); - adr = (void *)(((unsigned long )adr) | left); - -return adr; -} - -static __ref void unmap_low_page (void *adr) -{ -if (after_bootmem) -return ; - -early_iounmap ((void *)((unsigned long )adr &PAGE_MASK ),PAGE_SIZE ); -} -static unsigned long __meminit phys_pte_init (pte_t *pte_page,unsigned long addr,unsigned long end,pgprot_t prot)@@ -435,10 +411,9 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,if (pmd_val (*pmd)) {if (!pmd_large (*pmd)) {spin_lock (&init_mm.page_table_lock); - pte =map_low_page ((pte_t *)pmd_page_vaddr (*pmd)); + pte = (pte_t *)pmd_page_vaddr (*pmd); last_map_addr =phys_pte_init (pte, address, end, prot); -unmap_low_page (pte);spin_unlock (&init_mm.page_table_lock);continue ; }@@ -474,7 +449,6 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, pte =alloc_low_page (&pte_phys); last_map_addr =phys_pte_init (pte, address, end, new_prot); -unmap_low_page (pte);spin_lock (&init_mm.page_table_lock);pmd_populate_kernel (&init_mm, pmd,__va (pte_phys));@@ -509,10 +483,9 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,if (pud_val (*pud)) {if (!pud_large (*pud)) { - pmd =map_low_page (pmd_offset (pud,0 )); + pmd =pmd_offset (pud,0 ); last_map_addr =phys_pmd_init (pmd, addr, end, page_size_mask, prot); -unmap_low_page (pmd);__flush_tlb_all ();continue ; }@@ -548,7 +521,6 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, pmd =alloc_low_page (&pmd_phys); last_map_addr =phys_pmd_init (pmd, addr, end, page_size_mask, prot); -unmap_low_page (pmd);spin_lock (&init_mm.page_table_lock);pud_populate (&init_mm, pud,__va (pmd_phys));@@ -584,17 +556,15 @@ kernel_physical_mapping_init(unsigned long start, next = end;if (pgd_val (*pgd)) { - pud =map_low_page ((pud_t *)pgd_page_vaddr (*pgd)); + pud = (pud_t *)pgd_page_vaddr (*pgd); last_map_addr =phys_pud_init (pud,__pa (start),__pa (end), page_size_mask); -unmap_low_page (pud);continue ; } pud =alloc_low_page (&pud_phys); last_map_addr =phys_pud_init (pud,__pa (start),__pa (next), page_size_mask); -unmap_low_page (pud);spin_lock (&init_mm.page_table_lock);pgd_populate (&init_mm, pgd,__va (pud_phys));Signature · 7 lines
1.7.7 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
In reply to Yinghai LuQuoted 9 lines · Yinghai Lu
Quoted 7 lines · Stefano Stabellini
Quoted 6 lines · Yinghai Lu
Quoted 3 lines · H. Peter Anvin
See my other post. This is bringing up the Kernel Summit algorithm again.
sure. please check if you are ok with attached one on top of x86/mm2
I updated my for-x86-mm branch, It should be ok now with xen.
Can you please check it ?
git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git
for-x86-mm
in addition patches in tip x86/mm2, there are 5 new patches added.
688d437: x86, mm: Use big page for small memory range
41e562f: x86, mm: only keep initial mapping for ram
24ac352: x86, mm: Remove early_memremap workaround for page table accessing
d9dd599: x86, mm: Don't clear page table if next range is ram 080acbe: x86, mm: get early page table from BRK
Thanks
Yinghai
Re: [PATCH 04/13] x86, mm: Revert back good_end setting for 64bit
In reply to Yinghai LuQuoted 45 lines · Yinghai Lu
Quoted 43 lines · Stefano Stabellini
Quoted 42 lines · Yinghai Lu
After
| commit 8548c84da2f47e71bbbe300f55edb768492575f7 | Author: Takashi Iwai <[email protected]> | Date: Sun Oct 23 23:19:12 2011 +0200 | | x86: Fix S4 regression | | Commit 4b239f458 ("x86-64, mm: Put early page table high") causes a S4 | regression since 2.6.39, namely the machine reboots occasionally at S4 | resume. It doesn't happen always, overall rate is about 1/20. But, | like other bugs, once when this happens, it continues to happen. | | This patch fixes the problem by essentially reverting the memory | assignment in the older way.Have some page table around 512M again, that will prevent kdump to find 512M under 768M.
We need revert that reverting, so we could put page table high again for 64bit.
Takashi agreed that S4 regression could be something else.
https://lkml.org/lkml/2012/6/15/182Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/mm/init.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)arch/x86/mm/init.c +1
-1@@ -76,8 +76,8 @@ static void __init find_early_table_space(struct map_range *mr,#ifdef CONFIG_X86_32 /* for fixmap */ tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); -#endif good_end = max_pfn_mapped <<PAGE_SHIFT ; +#endif
Quoted 7 lines
Quoted 5 lines
arch/x86/mm/init.c static void __init find_early_table_space(struct map_range *mr, · line 83
Quoted 2 lines
arch/x86/mm/init.c +0
-0base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE );if (!base)Isn't this going to cause
init_memory_mappingto allocate pagetable pages from memory not yet mapped?but 64bit is using ioremap to access those page table buf.
Yes, but as Konrad explained, the mapping should be RO or RW on Xen depending on whether the pagetable pages are already hooked into the pagetable or not. ioremap could be called on not-yet-hooked pagetable pages (or non-pagetable-pages) and already-hooked pagetable pages and they need to be marked differently. Finally when you are going to map the region in memory that contains the pagetable pages, the entire range needs to be marked RO.
These issues could be avoided if the pagetable pages were allocated from a memory region that is already mapped and we had a proper pvop to warn the Xen subsystem that the pagetable pages are about to be hooked into the live pagetable.
Quoted 7 lines
Quoted 4 lines
Last time I spoke with HPA and Thomas about this, they seem to agree that it isn't a very good idea.
Also, it is proven to cause a certain amount of headaches on Xen, see commitd8aa5ec3382e6a545b8f25178d1e0992d4927f19.this patchset will allocate page table buf one time only. So could use ram under 1M to map that page table at first.
I don't have anything agaist the goal of this series, the problem is just where these pagetable pages come from.
Quoted 1 line
so that will make it xen happy ?
It would greatly simplify our life if the pagetable pages were allocated from memory already mapped.
PATCH 5/13 x86, mm: Find early page table buffer altogether
In reply to Yinghai LuWe should not do that in every calling of init_memory_mapping.
At the same time need to move down early_memtest, and could move after_bootmem checking away.
-v2: fix one early_memtest with 32bit by passing max_pfn_mapped instead.
--- arch/x86/mm/init.c | 72 ++++++++++++++++++++++++++------------------------- 1 files changed, 37 insertions(+), 35 deletions(-)
arch/x86/mm/init.c +37 -35
@@ -37,7 +37,7 @@ struct map_range {static int page_size_mask; -static void __init find_early_table_space (struct map_range *mr, +static void __init find_early_table_space (unsigned long begin,unsigned long end) {unsigned long puds, pmds, ptes, tables, start =0 , good_end = end;
@@ -64,8 +64,8 @@ static void __init find_early_table_space(struct map_range *mr, extra +=PMD_SIZE ;#endif /* The first 2/4M doesn't use large pages. */ -if (mr->start <PMD_SIZE ) - extra += mr->end - mr->start; +if (begin <PMD_SIZE ) + extra += (PMD_SIZE - begin) >>PAGE_SHIFT ; ptes = (extra +PAGE_SIZE -1 ) >>PAGE_SHIFT ; }else
@@ -265,16 +265,6 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, nr_range =0 ; nr_range =split_mem_range (mr, nr_range, start, end); -/* -* Find space for the kernel direct mapping tables. -* -* Later we should allocate these tables in the local node of the -* memory mapped. Unfortunately this is done currently before the -* nodes are discovered. -*/ -if (!after_bootmem) -find_early_table_space (&mr[0 ], end); -for (i =0 ; i < nr_range; i++) ret =kernel_physical_mapping_init (mr[i].start, mr[i].end, mr[i].page_size_mask);
@@ -287,6 +277,36 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,__flush_tlb_all (); +return ret >>PAGE_SHIFT ; +} + +void __init init_mem_mapping (void ) +{ +probe_page_size_mask (); + +/* +* Find space for the kernel direct mapping tables. +* +* Later we should allocate these tables in the local node of the +* memory mapped. Unfortunately this is done currently before the +* nodes are discovered. +*/ +#ifdef CONFIG_X86_64 +find_early_table_space (0 , max_pfn<<PAGE_SHIFT ); +#else +find_early_table_space (0 , max_low_pfn<<PAGE_SHIFT ); +#endif + max_low_pfn_mapped =init_memory_mapping (0 , max_low_pfn<<PAGE_SHIFT ); + max_pfn_mapped = max_low_pfn_mapped; + +#ifdef CONFIG_X86_64 +if (max_pfn > max_low_pfn) { + max_pfn_mapped =init_memory_mapping (1UL <<32 , + max_pfn<<PAGE_SHIFT ); +/* can we preseve max_low_pfn ?*/ + max_low_pfn = max_pfn; + } +#endif /* * Reserve the kernel pagetable pages we used (pgt_buf_start - * pgt_buf_end) and free the other ones (pgt_buf_end - pgt_buf_top)
@@ -302,32 +322,14 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,* RO all the pagetable pages, including the ones that are beyond * pgt_buf_end at that time. */ -if (!after_bootmem && pgt_buf_end > pgt_buf_start) +if (pgt_buf_end > pgt_buf_start) x86_init.mapping.pagetable_reserve (PFN_PHYS (pgt_buf_start),PFN_PHYS (pgt_buf_end)); -if (!after_bootmem) -early_memtest (start, end); +/* stop the wrong using */ + pgt_buf_top =0 ; -return ret >>PAGE_SHIFT ; -} - -void __init init_mem_mapping (void ) -{ -probe_page_size_mask (); - -/* max_pfn_mapped is updated here */ - max_low_pfn_mapped =init_memory_mapping (0 , max_low_pfn<<PAGE_SHIFT ); - max_pfn_mapped = max_low_pfn_mapped; - -#ifdef CONFIG_X86_64 -if (max_pfn > max_low_pfn) { - max_pfn_mapped =init_memory_mapping (1UL <<32 , - max_pfn<<PAGE_SHIFT ); -/* can we preseve max_low_pfn ?*/ - max_low_pfn = max_pfn; - } -#endif +early_memtest (0 , max_pfn_mapped <<PAGE_SHIFT ); }/*
Signature · 1 line
1.7.7
PATCH 6/13 x86, mm: Separate out calculate_table_space_size()
In reply to Yinghai LuIt should take physical address range that will need to be mapped. find_early_table_space should take range that pgt buff should be in.
Separating page table size calculating and finding early page table will reduce confusing.
--- arch/x86/mm/init.c | 39 ++++++++++++++++++++++++++++----------- 1 files changed, 28 insertions(+), 11 deletions(-)
arch/x86/mm/init.c +28 -11
@@ -37,11 +37,10 @@ struct map_range {static int page_size_mask; -static void __init find_early_table_space (unsigned long begin, +static unsigned long __init calculate_table_space_size (unsigned long begin,unsigned long end) { -unsigned long puds, pmds, ptes, tables, start =0 , good_end = end; -phys_addr_t base; +unsigned long puds, pmds, ptes, tables; puds = (end +PUD_SIZE -1 ) >>PUD_SHIFT ; tables =roundup (puds *sizeof (pud_t),PAGE_SIZE );
@@ -76,9 +75,17 @@ static void __init find_early_table_space(unsigned long begin,#ifdef CONFIG_X86_32 /* for fixmap */ tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); - good_end = max_pfn_mapped <<PAGE_SHIFT ;#endif +return tables; +} + +static void __init find_early_table_space (unsigned long start, +unsigned long good_end, +unsigned long tables) +{ +phys_addr_t base; + base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE );if (!base)panic ("Cannot find space for the kernel page tables" );
@@ -86,10 +93,6 @@ static void __init find_early_table_space(unsigned long begin, pgt_buf_start = base >>PAGE_SHIFT ; pgt_buf_end = pgt_buf_start; pgt_buf_top = pgt_buf_start + (tables >>PAGE_SHIFT ); - -printk (KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx]\n" , - end -1 , pgt_buf_start <<PAGE_SHIFT , - (pgt_buf_top <<PAGE_SHIFT ) -1 ); }static void __init probe_page_size_mask (void )
@@ -282,6 +285,8 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,void __init init_mem_mapping (void ) { +unsigned long tables, good_end, end; +probe_page_size_mask ();/*
@@ -292,10 +297,18 @@ void __init init_mem_mapping(void)* nodes are discovered. */ #ifdef CONFIG_X86_64 -find_early_table_space (0 , max_pfn<<PAGE_SHIFT ); + end = max_pfn <<PAGE_SHIFT ; + good_end = end;#else -find_early_table_space (0 , max_low_pfn<<PAGE_SHIFT ); + end = max_low_pfn <<PAGE_SHIFT ; + good_end = max_pfn_mapped <<PAGE_SHIFT ;#endif + tables =calculate_table_space_size (0 , end); +find_early_table_space (0 , good_end, tables); +printk (KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx] prealloc\n" , + end -1 , pgt_buf_start <<PAGE_SHIFT , + (pgt_buf_top <<PAGE_SHIFT ) -1 ); + max_low_pfn_mapped =init_memory_mapping (0 , max_low_pfn<<PAGE_SHIFT ); max_pfn_mapped = max_low_pfn_mapped;
@@ -322,9 +335,13 @@ void __init init_mem_mapping(void)* RO all the pagetable pages, including the ones that are beyond * pgt_buf_end at that time. */ -if (pgt_buf_end > pgt_buf_start) +if (pgt_buf_end > pgt_buf_start) { +printk (KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx] final\n" , + end -1 , pgt_buf_start <<PAGE_SHIFT , + (pgt_buf_end <<PAGE_SHIFT ) -1 ); x86_init.mapping.pagetable_reserve (PFN_PHYS (pgt_buf_start),PFN_PHYS (pgt_buf_end)); + }/* stop the wrong using */ pgt_buf_top =0 ;
Signature · 1 line
1.7.7
PATCH 7/13 x86, mm: Move down two calculate_table_space_size down.
In reply to Yinghai LuSo later could make it call split_mem_range.
--- arch/x86/mm/init.c | 116 ++++++++++++++++++++++++++-------------------------- 1 files changed, 58 insertions(+), 58 deletions(-)
arch/x86/mm/init.c +58 -58
@@ -37,64 +37,6 @@ struct map_range {static int page_size_mask; -static unsigned long __init calculate_table_space_size (unsigned long begin, -unsigned long end) -{ -unsigned long puds, pmds, ptes, tables; - - puds = (end +PUD_SIZE -1 ) >>PUD_SHIFT ; - tables =roundup (puds *sizeof (pud_t),PAGE_SIZE ); - -if (page_size_mask & (1 <<PG_LEVEL_1G )) { -unsigned long extra; - - extra = end - ((end>>PUD_SHIFT ) <<PUD_SHIFT ); - pmds = (extra +PMD_SIZE -1 ) >>PMD_SHIFT ; - }else - pmds = (end +PMD_SIZE -1 ) >>PMD_SHIFT ; - - tables +=roundup (pmds *sizeof (pmd_t),PAGE_SIZE ); - -if (page_size_mask & (1 <<PG_LEVEL_2M )) { -unsigned long extra; - - extra = end - ((end>>PMD_SHIFT ) <<PMD_SHIFT ); -#ifdef CONFIG_X86_32 - extra +=PMD_SIZE ; -#endif -/* The first 2/4M doesn't use large pages. */ -if (begin <PMD_SIZE ) - extra += (PMD_SIZE - begin) >>PAGE_SHIFT ; - - ptes = (extra +PAGE_SIZE -1 ) >>PAGE_SHIFT ; - }else - ptes = (end +PAGE_SIZE -1 ) >>PAGE_SHIFT ; - - tables +=roundup (ptes *sizeof (pte_t),PAGE_SIZE ); - -#ifdef CONFIG_X86_32 -/* for fixmap */ - tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); -#endif - -return tables; -} - -static void __init find_early_table_space (unsigned long start, -unsigned long good_end, -unsigned long tables) -{ -phys_addr_t base; - - base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE ); -if (!base) -panic ("Cannot find space for the kernel page tables" ); - - pgt_buf_start = base >>PAGE_SHIFT ; - pgt_buf_end = pgt_buf_start; - pgt_buf_top = pgt_buf_start + (tables >>PAGE_SHIFT ); -} -static void __init probe_page_size_mask (void ) {#if !defined(CONFIG_DEBUG_PAGEALLOC ) && !defined(CONFIG_KMEMCHECK )
@@ -249,6 +191,64 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range,return nr_range; } +static unsigned long __init calculate_table_space_size (unsigned long begin, +unsigned long end) +{ +unsigned long puds, pmds, ptes, tables; + + puds = (end +PUD_SIZE -1 ) >>PUD_SHIFT ; + tables =roundup (puds *sizeof (pud_t),PAGE_SIZE ); + +if (page_size_mask & (1 <<PG_LEVEL_1G )) { +unsigned long extra; + + extra = end - ((end>>PUD_SHIFT ) <<PUD_SHIFT ); + pmds = (extra +PMD_SIZE -1 ) >>PMD_SHIFT ; + }else + pmds = (end +PMD_SIZE -1 ) >>PMD_SHIFT ; + + tables +=roundup (pmds *sizeof (pmd_t),PAGE_SIZE ); + +if (page_size_mask & (1 <<PG_LEVEL_2M )) { +unsigned long extra; + + extra = end - ((end>>PMD_SHIFT ) <<PMD_SHIFT ); +#ifdef CONFIG_X86_32 + extra +=PMD_SIZE ; +#endif +/* The first 2/4M doesn't use large pages. */ +if (begin <PMD_SIZE ) + extra += (PMD_SIZE - begin) >>PAGE_SHIFT ; + + ptes = (extra +PAGE_SIZE -1 ) >>PAGE_SHIFT ; + }else + ptes = (end +PAGE_SIZE -1 ) >>PAGE_SHIFT ; + + tables +=roundup (ptes *sizeof (pte_t),PAGE_SIZE ); + +#ifdef CONFIG_X86_32 +/* for fixmap */ + tables +=roundup (__end_of_fixed_addresses *sizeof (pte_t),PAGE_SIZE ); +#endif + +return tables; +} + +static void __init find_early_table_space (unsigned long start, +unsigned long good_end, +unsigned long tables) +{ +phys_addr_t base; + + base =memblock_find_in_range (start, good_end, tables,PAGE_SIZE ); +if (!base) +panic ("Cannot find space for the kernel page tables" ); + + pgt_buf_start = base >>PAGE_SHIFT ; + pgt_buf_end = pgt_buf_start; + pgt_buf_top = pgt_buf_start + (tables >>PAGE_SHIFT ); +} +/* * Setup the direct mapping of the physical memory at PAGE_OFFSET. * This runs before bootmem is initialized and gets pages directly from
Signature · 1 line
1.7.7
PATCH 8/13 x86, mm: Set memblock initial limit to 1M
In reply to Yinghai Lumemblock_x86_fill() could double memory array.
If we set max_pfn_mapped to 512M, so memory array could be around 512M. So kdump will not get big range (like 512M) under 1024M.
Try to put it down under 1M, it could use about 4k or so.
Also we need this one when we try to only map ram range only later. if the early double the range near 512M, and later init_mem_mapping() first several range could under 512M, then after mapping get reset, we will lose access the memblock memory array. but we are using memblock memory array for iteration.
--- arch/x86/kernel/setup.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/kernel/setup.c +1 -1
@@ -889,7 +889,7 @@ void __init setup_arch(char **cmdline_p)cleanup_highmap (); - memblock.current_limit =get_max_mapped (); + memblock.current_limit =ISA_END_ADDRESS ;memblock_x86_fill ();/*
Signature · 1 line
1.7.7
PATCH 9/13 x86: if kernel .text .data .bss are not marked as E820_RAM, complain and fix
In reply to Yinghai LuFrom: Jacob Shin <[email protected]>
There could be cases where user supplied memmap=exactmap memory mappings do not mark the region where the kernel .text .data and .bss reside as E820_RAM, as reported here:
https://lkml.org/lkml/2012/8/14/86
Handle it by complaining, and adding the range back into the e820.
--- arch/x86/kernel/setup.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-)
arch/x86/kernel/setup.c +14 -0
@@ -831,6 +831,20 @@ 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 ); + } +trim_bios_range ();#ifdef CONFIG_X86_32 if (ppro_with_ram_bug ()) {
Signature · 1 line
1.7.7
PATCH 10/13 x86: Fixup code testing if a pfn is direct mapped
In reply to Yinghai LuFrom: Jacob Shin <[email protected]>
Update code that previously assumed pfns [ 0 - max_low_pfn_mapped ) and [ 4GB - max_pfn_mapped ) were always direct mapped, to now look up pfn_mapped ranges instead.
-v2: change applying sequence to keep git bisecting working.
so add dummy pfn_range_is_mapped(). - Yinghai Lu
--- arch/x86/include/asm/page_types.h | 8 ++++++++ arch/x86/kernel/cpu/amd.c | 8 +++----- arch/x86/platform/efi/efi.c | 8 ++++---- 3 files changed, 15 insertions(+), 9 deletions(-)
arch/x86/include/asm/page_types.h +8 -0
@@ -51,6 +51,14 @@ static inline phys_addr_t get_max_mapped(void)return (phys_addr_t )max_pfn_mapped <<PAGE_SHIFT ; } +static inline bool pfn_range_is_mapped (unsigned long start_pfn, +unsigned long end_pfn) +{ +return end_pfn <= max_low_pfn_mapped || + (end_pfn > (1UL << (32 -PAGE_SHIFT )) && + end_pfn <= max_pfn_mapped); +} +extern unsigned long init_memory_mapping (unsigned long start,unsigned long end);
arch/x86/kernel/cpu/amd.c +3 -5
@@ -676,12 +676,10 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)* benefit in doing so. */ if (!rdmsrl_safe (MSR_K8_TSEG_ADDR , &tseg)) { +unsigned long pfn = tseg >>PAGE_SHIFT ; +printk (KERN_DEBUG "tseg: %010llx\n" , tseg); -if ((tseg>>PMD_SHIFT ) < - (max_low_pfn_mapped>>(PMD_SHIFT -PAGE_SHIFT )) || - ((tseg>>PMD_SHIFT ) < - (max_pfn_mapped>>(PMD_SHIFT -PAGE_SHIFT )) && - (tseg>>PMD_SHIFT ) >= (1ULL <<(32 -PMD_SHIFT )))) +if (pfn_range_is_mapped (pfn, pfn +1 ))set_memory_4k ((unsigned long )__va (tseg),1 ); } }
arch/x86/platform/efi/efi.c +4 -4
@@ -823,7 +823,7 @@ void __init efi_enter_virtual_mode(void)efi_memory_desc_t *md, *prev_md =NULL ;efi_status_t status;unsigned long size; -u64 end, systab, addr, npages, end_pfn; +u64 end, systab, addr, npages, start_pfn, end_pfn;void *p, *va, *new_memmap =NULL ;int count =0 ;
@@ -876,10 +876,10 @@ void __init efi_enter_virtual_mode(void) size = md->num_pages <<EFI_PAGE_SHIFT ; end = md->phys_addr + size; + start_pfn =PFN_DOWN (md->phys_addr); end_pfn =PFN_UP (end); -if (end_pfn <= max_low_pfn_mapped - || (end_pfn > (1UL << (32 -PAGE_SHIFT )) - && end_pfn <= max_pfn_mapped)) + +if (pfn_range_is_mapped (start_pfn, end_pfn)) va =__va (md->phys_addr);else va =efi_ioremap (md->phys_addr, size, md->type);
Signature · 1 line
1.7.7
PATCH 11/13 x86: Only direct map addresses that are marked as E820_RAM
In reply to Yinghai LuFrom: Jacob Shin <[email protected]>
Currently direct mappings are created for [ 0 to max_low_pfn<<PAGE_SHIFT ) and [ 4GB to max_pfn<<PAGE_SHIFT ), which may include regions that are not backed by actual DRAM. This is fine for holes under 4GB which are covered by fixed and variable range MTRRs to be UC. However, we run into trouble on higher memory addresses which cannot be covered by MTRRs.
Our system with 1TB of RAM has an e820 that looks like this:
BIOS-e820: [mem 0x0000000000000000-0x00000000000983ff] usable
BIOS-e820: [mem 0x0000000000098400-0x000000000009ffff] reserved
BIOS-e820: [mem 0x00000000000d0000-0x00000000000fffff] reserved
BIOS-e820: [mem 0x0000000000100000-0x00000000c7ebffff] usable
BIOS-e820: [mem 0x00000000c7ec0000-0x00000000c7ed7fff] ACPI data
BIOS-e820: [mem 0x00000000c7ed8000-0x00000000c7ed9fff] ACPI NVS
BIOS-e820: [mem 0x00000000c7eda000-0x00000000c7ffffff] reserved
BIOS-e820: [mem 0x00000000fec00000-0x00000000fec0ffff] reserved
BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
BIOS-e820: [mem 0x00000000fff00000-0x00000000ffffffff] reserved
BIOS-e820: [mem 0x0000000100000000-0x000000e037ffffff] usable
BIOS-e820: [mem 0x000000e038000000-0x000000fcffffffff] reserved
BIOS-e820: [mem 0x0000010000000000-0x0000011ffeffffff] usable
and so direct mappings are created for huge memory hole between 0x000000e038000000 to 0x0000010000000000. Even though the kernel never generates memory accesses in that region, since the page tables mark them incorrectly as being WB, our (AMD) processor ends up causing a MCE while doing some memory bookkeeping/optimizations around that area.
This patch iterates through e820 and only direct maps ranges that are marked as E820_RAM, and keeps track of those pfn ranges. Depending on the alignment of E820 ranges, this may possibly result in using smaller size (i.e. 4K instead of 2M or 1G) page tables.
-v2: move changes from setup.c to mm/init.c, also use for_each_mem_pfn_range
instead. - Yinghai Lu
-v3: add calculate_all_table_space_size() to get correct needed page table
size. - Yinghai Lu
--- arch/x86/include/asm/page_types.h | 8 +-- arch/x86/kernel/setup.c | 8 ++- arch/x86/mm/init.c | 119 +++++++++++++++++++++++++++++++++---- arch/x86/mm/init_64.c | 6 +- 4 files changed, 116 insertions(+), 25 deletions(-)
arch/x86/include/asm/page_types.h +1 -7
@@ -51,13 +51,7 @@ static inline phys_addr_t get_max_mapped(void)return (phys_addr_t )max_pfn_mapped <<PAGE_SHIFT ; } -static inline bool pfn_range_is_mapped (unsigned long start_pfn, -unsigned long end_pfn) -{ -return end_pfn <= max_low_pfn_mapped || - (end_pfn > (1UL << (32 -PAGE_SHIFT )) && - end_pfn <= max_pfn_mapped); -} +bool pfn_range_is_mapped (unsigned long start_pfn,unsigned long end_pfn);extern unsigned long init_memory_mapping (unsigned long start,unsigned long end);
arch/x86/kernel/setup.c +5 -3
@@ -115,9 +115,11 @@#include <asm/prom.h> /* -* end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries. -* The direct mapping extends to max_pfn_mapped, so that we can directly access -* apertures, ACPI and other tables without having to play with fixmaps. +* max_low_pfn_mapped: highest direct mapped pfn under 4GB +* max_pfn_mapped: highest direct mapped pfn over 4GB +* +* The direct mapping only covers E820_RAM regions, so the ranges and gaps are +* represented by pfn_mapped */ unsigned long max_low_pfn_mapped;unsigned long max_pfn_mapped;
arch/x86/mm/init.c +108 -11
152 lines not on this page · raw message
arch/x86/mm/init_64.c +2 -4
@@ -657,13 +657,11 @@ int arch_add_memory(int nid, u64 start, u64 size) {struct pglist_data *pgdat =NODE_DATA (nid);struct zone *zone = pgdat->node_zones +ZONE_NORMAL ; -unsigned long last_mapped_pfn, start_pfn = start >>PAGE_SHIFT ; +unsigned long start_pfn = start >>PAGE_SHIFT ;unsigned long nr_pages = size >>PAGE_SHIFT ;int ret; - last_mapped_pfn =init_memory_mapping (start, start + size); -if (last_mapped_pfn > max_pfn_mapped) - max_pfn_mapped = last_mapped_pfn; +init_memory_mapping (start, start + size); ret =__add_pages (nid, zone, start_pfn, nr_pages);WARN_ON_ONCE (ret);
Signature · 1 line
1.7.7
PATCH 12/13 x86/mm: calculate_table_space_size based on memory ranges that are being mapped
In reply to Yinghai LuFrom: Jacob Shin <[email protected]>
Current logic finds enough space for direct mapping page tables from 0 to end. Instead, we only need to find enough space to cover mr[0].start to mr[nr_range].end -- the range that is actually being mapped by init_memory_mapping()
This patch also reportedly fixes suspend/resume issue reported in:
https://lkml.org/lkml/2012/8/11/83
-v2: update with calculate_table_space_size()
clear max_pfn_mapped before init_all_memory_mapping to get right value
-Yinghai Lu
--- arch/x86/mm/init.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 files changed, 30 insertions(+), 21 deletions(-)
arch/x86/mm/init.c +30 -21
@@ -191,39 +191,48 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range,return nr_range; } -static unsigned long __init calculate_table_space_size (unsigned long begin, +static unsigned long __init calculate_table_space_size (unsigned long start,unsigned long end) { -unsigned long puds, pmds, ptes, tables; +unsigned long puds =0 , pmds =0 , ptes =0 , tables; +struct map_range mr[NR_RANGE_MR ]; +int nr_range, i; - puds = (end +PUD_SIZE -1 ) >>PUD_SHIFT ; - tables =roundup (puds *sizeof (pud_t),PAGE_SIZE ); +pr_info ("calculate_table_space_size: [mem %#010lx-%#010lx]\n" , + start, end -1 ); -if (page_size_mask & (1 <<PG_LEVEL_1G )) { -unsigned long extra; +memset (mr,0 ,sizeof (mr)); + nr_range =0 ; + nr_range =split_mem_range (mr, nr_range, start, end); - extra = end - ((end>>PUD_SHIFT ) <<PUD_SHIFT ); - pmds = (extra +PMD_SIZE -1 ) >>PMD_SHIFT ; - }else - pmds = (end +PMD_SIZE -1 ) >>PMD_SHIFT ; +for (i =0 ; i < nr_range; i++) { +unsigned long range, extra; - tables +=roundup (pmds *sizeof (pmd_t),PAGE_SIZE ); + range = mr[i].end - mr[i].start; + puds += (range +PUD_SIZE -1 ) >>PUD_SHIFT ; -if (page_size_mask & (1 <<PG_LEVEL_2M )) { -unsigned long extra; +if (mr[i].page_size_mask & (1 <<PG_LEVEL_1G )) { + extra = range - ((range >>PUD_SHIFT ) <<PUD_SHIFT ); + pmds += (extra +PMD_SIZE -1 ) >>PMD_SHIFT ; + }else + pmds += (range +PMD_SIZE -1 ) >>PMD_SHIFT ; - extra = end - ((end>>PMD_SHIFT ) <<PMD_SHIFT ); +if (mr[i].page_size_mask & (1 <<PG_LEVEL_2M )) { + extra = range - ((range >>PMD_SHIFT ) <<PMD_SHIFT );#ifdef CONFIG_X86_32 - extra +=PMD_SIZE ; + extra +=PMD_SIZE ;#endif -/* The first 2/4M doesn't use large pages. */ -if (begin <PMD_SIZE ) - extra += (PMD_SIZE - begin) >>PAGE_SHIFT ; +/* The first 2/4M doesn't use large pages. */ +if (mr[i].start <PMD_SIZE ) + extra +=PMD_SIZE - mr[i].start; - ptes = (extra +PAGE_SIZE -1 ) >>PAGE_SHIFT ; - }else - ptes = (end +PAGE_SIZE -1 ) >>PAGE_SHIFT ; + ptes += (extra +PAGE_SIZE -1 ) >>PAGE_SHIFT ; + }else + ptes += (range +PAGE_SIZE -1 ) >>PAGE_SHIFT ; + } + tables =roundup (puds *sizeof (pud_t),PAGE_SIZE ); + tables +=roundup (pmds *sizeof (pmd_t),PAGE_SIZE ); tables +=roundup (ptes *sizeof (pte_t),PAGE_SIZE );#ifdef CONFIG_X86_32
Signature · 1 line
1.7.7
PATCH 13/13 x86, mm: Use func pointer to table size calculation and mapping
In reply to Yinghai LuThey all need to go over ram range in same sequence. So add shared function to reduce duplicated code.
-v2: Change to walk_ram_ranges() according to Pekka Enberg.
--- arch/x86/mm/init.c | 64 ++++++++++++++++++--------------------------------- 1 files changed, 23 insertions(+), 41 deletions(-)
arch/x86/mm/init.c +23 -41
@@ -243,14 +243,15 @@ static unsigned long __init calculate_table_space_size(unsigned long start,return tables; } -static unsigned long __init calculate_all_table_space_size (void ) +static void __init walk_ram_ranges ( +void (*work_fn)(unsigned long ,unsigned long ,void *), +void *data) {unsigned long start_pfn, end_pfn; -unsigned long tables;int i;/* the ISA range is always mapped regardless of memory holes */ - tables =calculate_table_space_size (0 ,ISA_END_ADDRESS ); +work_fn (0 ,ISA_END_ADDRESS , data);for_each_mem_pfn_range (i,MAX_NUMNODES , &start_pfn, &end_pfn,NULL ) {u64 start = start_pfn <<PAGE_SHIFT ;
@@ -269,10 +270,15 @@ static unsigned long __init calculate_all_table_space_size(void)if ((end >>PAGE_SHIFT ) > max_low_pfn) end = max_low_pfn <<PAGE_SHIFT ;#endif - tables +=calculate_table_space_size (start, end); +work_fn (start, end, data); } +} -return tables; +static void __init size_work_fn (unsigned long start,unsigned long end,void *data) +{ +unsigned long *size = data; + + *size +=calculate_table_space_size (start, end); } static void __init find_early_table_space(unsigned long start,
@@ -361,45 +367,15 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,* Depending on the alignment of E820 ranges, this may possibly result in using * smaller size (i.e. 4K instead of 2M or 1G) page tables. */ -static void __init init_all_memory_mapping (void ) +static void __init mapping_work_fn (unsigned long start,unsigned long end, +void *data) { -unsigned long start_pfn, end_pfn; -int i; - -/* the ISA range is always mapped regardless of memory holes */ -init_memory_mapping (0 ,ISA_END_ADDRESS ); - -for_each_mem_pfn_range (i,MAX_NUMNODES , &start_pfn, &end_pfn,NULL ) { -u64 start = start_pfn <<PAGE_SHIFT ; -u64 end = end_pfn <<PAGE_SHIFT ; - -if (end <=ISA_END_ADDRESS ) -continue ; - -if (start <ISA_END_ADDRESS ) - start =ISA_END_ADDRESS ; -#ifdef CONFIG_X86_32 -/* on 32 bit, we only map up to max_low_pfn */ -if ((start >>PAGE_SHIFT ) >= max_low_pfn) -continue ; - -if ((end >>PAGE_SHIFT ) > max_low_pfn) - end = max_low_pfn <<PAGE_SHIFT ; -#endif -init_memory_mapping (start, end); - } - -#ifdef CONFIG_X86_64 -if (max_pfn > max_low_pfn) { -/* can we preseve max_low_pfn ?*/ - max_low_pfn = max_pfn; - } -#endif +init_memory_mapping (start, end); }void __init init_mem_mapping (void ) { -unsigned long tables, good_end, end; +unsigned long tables =0 , good_end, end;probe_page_size_mask ();
@@ -417,15 +393,21 @@ void __init init_mem_mapping(void) end = max_low_pfn <<PAGE_SHIFT ; good_end = max_pfn_mapped <<PAGE_SHIFT ;#endif - tables =calculate_all_table_space_size (); +walk_ram_ranges (size_work_fn, &tables);find_early_table_space (0 , good_end, tables);printk (KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx] prealloc\n" , end -1 , pgt_buf_start <<PAGE_SHIFT , (pgt_buf_top <<PAGE_SHIFT ) -1 ); max_pfn_mapped =0 ;/* will get exact value next */ -init_all_memory_mapping (); +walk_ram_ranges (mapping_work_fn,NULL ); +#ifdef CONFIG_X86_64 +if (max_pfn > max_low_pfn) { +/* can we preseve max_low_pfn ?*/ + max_low_pfn = max_pfn; + } +#endif /* * Reserve the kernel pagetable pages we used (pgt_buf_start - * pgt_buf_end) and free the other ones (pgt_buf_end - pgt_buf_top)
Signature · 1 line
1.7.7