arch/arm64: Add support for TTB relocation to DRAM
When transitioning between boot stages, it is often necessary to move the Translation Table Base (TTB) from a temporary pre-RAM location to a permanent post-RAM region. ARM64 page tables contain absolute physical addresses for lower-level tables. When moving the TTB from one base address to another, these internal pointers must be adjusted. Implement mmu_relocate_ttb() to handle this transition. The logic copies the tables from _preram_ttb to _postram_ttb and performs a fixup on all descriptors to reflect the new offset. This ensures memory mapping remains consistent after the TTB base changes. BUG=b:436391478 TEST=Verify successful TTB relocation and stable MMU state on Quartz. Change-Id: I7fdd69bfa82fc3dae919693f4d5d0314687cbef9 Signed-off-by: Kapil Porwal <kapilporwal@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/91367 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Subrata Banik <subratabanik@google.com> Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
parent
493770d730
commit
99d409d3ba
2 changed files with 78 additions and 5 deletions
|
|
@ -76,16 +76,25 @@ static const char *table_level_name(size_t xlat_size)
|
|||
}
|
||||
}
|
||||
|
||||
static int init_next_free_table(void *start, void *end)
|
||||
{
|
||||
if ((void *)next_free_table < start || (void *)next_free_table >= end)
|
||||
next_free_table = start;
|
||||
while (next_free_table[0] != UNUSED_DESC) {
|
||||
next_free_table += GRANULE_SIZE / sizeof(*next_free_table);
|
||||
if ((void *)next_free_table >= end)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Func : setup_new_table
|
||||
* Desc : Get next free table from TTB and set it up to match old parent entry.
|
||||
*/
|
||||
static uint64_t *setup_new_table(uint64_t desc, size_t xlat_size)
|
||||
{
|
||||
while (next_free_table[0] != UNUSED_DESC) {
|
||||
next_free_table += GRANULE_SIZE/sizeof(*next_free_table);
|
||||
if (_ettb - (u8 *)next_free_table <= 0)
|
||||
die("Ran out of page table space!");
|
||||
}
|
||||
if (init_next_free_table(_ttb, _ettb))
|
||||
die("Ran out of page table space!");
|
||||
|
||||
void *frame_base = (void *)(desc & XLAT_ADDR_MASK);
|
||||
const char *level_name = table_level_name(xlat_size);
|
||||
|
|
@ -243,6 +252,7 @@ void mmu_config_range(void *start, size_t size, uint64_t tag)
|
|||
print_tag(BIOS_INFO, tag);
|
||||
|
||||
sanity_check(base_addr, temp_size);
|
||||
assert(raw_read_ttbr0() == (uint64_t)_ttb);
|
||||
|
||||
while (temp_size)
|
||||
temp_size -= init_xlat_table(base_addr + (size - temp_size),
|
||||
|
|
@ -326,3 +336,64 @@ void mmu_enable(void)
|
|||
|
||||
isb();
|
||||
}
|
||||
|
||||
/*
|
||||
* Func : mmu_relocate_ttb
|
||||
* Desc : Relocates a Translation Table Base (TTB) from _preram_ttb
|
||||
* to _postram_ttb. This involves copying the table data and updating
|
||||
* all internal pointers within the translation table entries to reflect
|
||||
* the new location.
|
||||
*/
|
||||
void mmu_relocate_ttb(void)
|
||||
{
|
||||
const uintptr_t old_base = (uintptr_t)_preram_ttb;
|
||||
const uintptr_t new_base = (uintptr_t)_postram_ttb;
|
||||
const uintptr_t offset = new_base - old_base;
|
||||
|
||||
ASSERT_MSG(offset, "TTB relocation is not required.\n");
|
||||
|
||||
/* Ensure that next_free_table pointer is correct. */
|
||||
init_next_free_table(_preram_ttb, _epreram_ttb);
|
||||
|
||||
const size_t used_size = (uintptr_t)next_free_table - old_base;
|
||||
uint64_t *entry;
|
||||
uint64_t *end = (uint64_t *)(new_base + used_size);
|
||||
|
||||
printk(BIOS_INFO, "Relocating TTB: 0x%lx -> 0x%lx (offset 0x%lx)\n",
|
||||
old_base, new_base, offset);
|
||||
|
||||
/* Copy the used TTB region to the new location. */
|
||||
memcpy((void *)new_base, (void *)old_base, used_size);
|
||||
|
||||
/*
|
||||
* Update all internal table pointers. Since the entire TTB region is
|
||||
* moved as a single block, every table pointer inside the descriptors
|
||||
* needs to be adjusted by the same relative offset.
|
||||
*/
|
||||
for (entry = (uint64_t *)new_base; entry < end; entry++) {
|
||||
/*
|
||||
* In ARMv8, a descriptor with bits [1:0] == 0b11 can be either a
|
||||
* Table descriptor or a Page descriptor. To differentiate, we
|
||||
* check the Access Flag (bit 10). Table descriptors do not use
|
||||
* this bit, whereas we ensure all Page/Block descriptors have it
|
||||
* set. This relies on TCR.HAFT[42] remaining 0.
|
||||
*/
|
||||
if ((*entry & DESC_MASK) == TABLE_DESC && !(*entry & BLOCK_ACCESS))
|
||||
*entry += offset;
|
||||
}
|
||||
|
||||
/* Mark remaining table slots unused (first PTE == UNUSED_DESC). */
|
||||
for (entry = end; (u8 *)entry < _epostram_ttb; entry += GRANULE_SIZE / sizeof(*entry))
|
||||
*entry = UNUSED_DESC;
|
||||
|
||||
/* Update TTBR0 to point to the new base address. */
|
||||
dsb();
|
||||
raw_write_ttbr0((uintptr_t)new_base);
|
||||
isb();
|
||||
|
||||
tlb_invalidate_all();
|
||||
dsb();
|
||||
isb();
|
||||
|
||||
printk(BIOS_INFO, "TTB relocation is complete.\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,5 +152,7 @@ void mmu_config_range(void *start, size_t size, uint64_t tag);
|
|||
void mmu_enable(void);
|
||||
/* Disable the MMU (which also disables dcache but not icache). */
|
||||
void mmu_disable(void);
|
||||
/* Relocates a Translation Table Base (TTB) from _preram_ttb to _postram_ttb */
|
||||
void mmu_relocate_ttb(void);
|
||||
|
||||
#endif /* __ARCH_ARM64_MMU_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue