Skip to content

Commit cc31744

Browse files
swahlhpeKAGA-KOKO
authored andcommitted
x86/mm/ident_map: Use gbpages only where full GB page should be mapped.
When ident_pud_init() uses only GB pages to create identity maps, large ranges of addresses not actually requested can be included in the resulting table; a 4K request will map a full GB. This can include a lot of extra address space past that requested, including areas marked reserved by the BIOS. That allows processor speculation into reserved regions, that on UV systems can cause system halts. Only use GB pages when map creation requests include the full GB page of space. Fall back to using smaller 2M pages when only portions of a GB page are included in the request. No attempt is made to coalesce mapping requests. If a request requires a map entry at the 2M (pmd) level, subsequent mapping requests within the same 1G region will also be at the pmd level, even if adjacent or overlapping such requests could have been combined to map a full GB page. Existing usage starts with larger regions and then adds smaller regions, so this should not have any great consequence. Signed-off-by: Steve Wahl <steve.wahl@hpe.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Pavin Joseph <me@pavinjoseph.com> Tested-by: Sarah Brofeldt <srhb@dbc.dk> Tested-by: Eric Hagberg <ehagberg@gmail.com> Link: https://lore.kernel.org/all/20240717213121.3064030-3-steve.wahl@hpe.com
1 parent 5760929 commit cc31744

1 file changed

Lines changed: 18 additions & 5 deletions

File tree

arch/x86/mm/ident_map.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,31 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
9999
for (; addr < end; addr = next) {
100100
pud_t *pud = pud_page + pud_index(addr);
101101
pmd_t *pmd;
102+
bool use_gbpage;
102103

103104
next = (addr & PUD_MASK) + PUD_SIZE;
104105
if (next > end)
105106
next = end;
106107

107-
if (info->direct_gbpages) {
108-
pud_t pudval;
108+
/* if this is already a gbpage, this portion is already mapped */
109+
if (pud_leaf(*pud))
110+
continue;
111+
112+
/* Is using a gbpage allowed? */
113+
use_gbpage = info->direct_gbpages;
109114

110-
if (pud_present(*pud))
111-
continue;
115+
/* Don't use gbpage if it maps more than the requested region. */
116+
/* at the begining: */
117+
use_gbpage &= ((addr & ~PUD_MASK) == 0);
118+
/* ... or at the end: */
119+
use_gbpage &= ((next & ~PUD_MASK) == 0);
120+
121+
/* Never overwrite existing mappings */
122+
use_gbpage &= !pud_present(*pud);
123+
124+
if (use_gbpage) {
125+
pud_t pudval;
112126

113-
addr &= PUD_MASK;
114127
pudval = __pud((addr - info->offset) | info->page_flag);
115128
set_pud(pud, pudval);
116129
continue;

0 commit comments

Comments
 (0)