Skip to content

Commit

Permalink
x86/mm/ident_map: Use gbpages only where full GB page should be mapped.
Browse files Browse the repository at this point in the history
When ident_pud_init() uses only gbpages 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.  On UV systems, this
ends up including regions that will cause hardware to halt the system
if accessed (these are marked "reserved" by BIOS).  Even processor
speculation into these regions is enough to trigger the system halt.

Only use gbpages 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
gbpage.  Existing usage starts with larger regions and then adds
smaller regions, so this should not have any great consequence.

[ dhansen: fix up comment formatting, simplifty changelog ]

Signed-off-by: Steve Wahl <steve.wahl@hpe.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/all/20240126164841.170866-1-steve.wahl%40hpe.com
  • Loading branch information
Steve Wahl authored and Dave Hansen committed Feb 12, 2024
1 parent f6a1892 commit d794734
Showing 1 changed file with 18 additions and 5 deletions.
23 changes: 18 additions & 5 deletions arch/x86/mm/ident_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,31 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
for (; addr < end; addr = next) {
pud_t *pud = pud_page + pud_index(addr);
pmd_t *pmd;
bool use_gbpage;

next = (addr & PUD_MASK) + PUD_SIZE;
if (next > end)
next = end;

if (info->direct_gbpages) {
pud_t pudval;
/* if this is already a gbpage, this portion is already mapped */
if (pud_large(*pud))
continue;

/* Is using a gbpage allowed? */
use_gbpage = info->direct_gbpages;

if (pud_present(*pud))
continue;
/* Don't use gbpage if it maps more than the requested region. */
/* at the begining: */
use_gbpage &= ((addr & ~PUD_MASK) == 0);
/* ... or at the end: */
use_gbpage &= ((next & ~PUD_MASK) == 0);

/* Never overwrite existing mappings */
use_gbpage &= !pud_present(*pud);

if (use_gbpage) {
pud_t pudval;

addr &= PUD_MASK;
pudval = __pud((addr - info->offset) | info->page_flag);
set_pud(pud, pudval);
continue;
Expand Down

0 comments on commit d794734

Please sign in to comment.