arm64: Fixes for booting in EL2 w/ E2H
* E2H (EL2 Host) is enabled by default and usually can't be disabled on CPUs with FEAT_VHE. Since EL2 becomes a superset of EL1 with E2H, we can simply do nothing and everything that expects EL1 will Just Work * Changed some register bits numbers to avoid C integer promotion issues * sEmptyTable needs to be filled in earler, before the kernel team is created. Otherwise, we put the uninitialized value of sEmptyTable in TTBR0, which immediately pends SError on Apple M1 Change-Id: I84ff7fd9134448f27315dadfd12bdd9df8c75b10 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10547 Reviewed-by: waddlesplash <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
13abea7517
commit
593f25d6f1
@@ -80,6 +80,7 @@
|
||||
#define HCR_RW 0x0000000080000000
|
||||
#define HCR_CD 0x0000000100000000
|
||||
#define HCR_ID 0x0000000200000000
|
||||
#define HCR_E2H 0x0000000400000000
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -597,27 +597,27 @@
|
||||
#define PSR_FLAGS 0xf0000000
|
||||
|
||||
/* TCR_EL1 - Translation Control Register */
|
||||
#define TCR_ASID_16 (1 << 36)
|
||||
#define TCR_ASID_16 (1UL << 36)
|
||||
|
||||
#define TCR_IPS_SHIFT 32
|
||||
#define TCR_IPS_32BIT (0 << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_36BIT (1 << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_40BIT (2 << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_42BIT (3 << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_44BIT (4 << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_48BIT (5 << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_32BIT (0UL << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_36BIT (1UL << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_40BIT (2UL << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_42BIT (3UL << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_44BIT (4UL << TCR_IPS_SHIFT)
|
||||
#define TCR_IPS_48BIT (5UL << TCR_IPS_SHIFT)
|
||||
|
||||
#define TCR_TG0_SHIFT 14
|
||||
#define TCR_TG0_4K (0 << TCR_TG0_SHIFT)
|
||||
#define TCR_TG0_64K (1 << TCR_TG0_SHIFT)
|
||||
#define TCR_TG0_16K (2 << TCR_TG0_SHIFT)
|
||||
#define TCR_TG0_MASK (3 << TCR_TG0_SHIFT)
|
||||
#define TCR_TG0_4K (0UL << TCR_TG0_SHIFT)
|
||||
#define TCR_TG0_64K (1UL << TCR_TG0_SHIFT)
|
||||
#define TCR_TG0_16K (2UL << TCR_TG0_SHIFT)
|
||||
#define TCR_TG0_MASK (3UL << TCR_TG0_SHIFT)
|
||||
|
||||
#define TCR_TG1_SHIFT 30
|
||||
#define TCR_TG1_16K (1 << TCR_TG1_SHIFT)
|
||||
#define TCR_TG1_4K (2 << TCR_TG1_SHIFT)
|
||||
#define TCR_TG1_64K (3 << TCR_TG1_SHIFT)
|
||||
#define TCR_TG1_MASK (3 << TCR_TG1_SHIFT)
|
||||
#define TCR_TG1_16K (1UL << TCR_TG1_SHIFT)
|
||||
#define TCR_TG1_4K (2UL << TCR_TG1_SHIFT)
|
||||
#define TCR_TG1_64K (3UL << TCR_TG1_SHIFT)
|
||||
#define TCR_TG1_MASK (3UL << TCR_TG1_SHIFT)
|
||||
|
||||
#define TCR_SH1_SHIFT 28
|
||||
#define TCR_SH1_IS (0x3UL << TCR_SH1_SHIFT)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <efi/types.h>
|
||||
|
||||
#include <kernel/arch/arm64/arm_registers.h>
|
||||
#include <kernel/arch/arm64/arch_hypervisor.h>
|
||||
#include <kernel/arch/arm64/arch_pte.h>
|
||||
|
||||
#include <arch_kernel.h>
|
||||
|
||||
@@ -167,18 +167,26 @@ arch_start_kernel(addr_t kernelEntry)
|
||||
serial_init();
|
||||
serial_enable();
|
||||
|
||||
switch (el) {
|
||||
case 1:
|
||||
arch_mmu_setup_EL1(READ_SPECIALREG(TCR_EL1));
|
||||
break;
|
||||
case 2:
|
||||
arch_mmu_setup_EL1(READ_SPECIALREG(TCR_EL2));
|
||||
arch_cache_disable();
|
||||
_arch_transition_EL2_EL1();
|
||||
break;
|
||||
default:
|
||||
panic("Unexpected Exception Level\n");
|
||||
break;
|
||||
// If we have E2H available, we want to also enable TGE
|
||||
// so exceptions don't get taken to EL1
|
||||
bool e2h = false;
|
||||
if (el == 2) {
|
||||
uint64 hcr = READ_SPECIALREG(HCR_EL2);
|
||||
if ((hcr & HCR_E2H) != 0) {
|
||||
e2h = true;
|
||||
WRITE_SPECIALREG(HCR_EL2, hcr | HCR_TGE);
|
||||
}
|
||||
}
|
||||
|
||||
// EL2 with E2H enabled behaves as a superset of EL1
|
||||
//
|
||||
// EL2 without E2H enabled does not, so we need to drop to EL1
|
||||
if (el == 1 || e2h) {
|
||||
arch_mmu_setup_EL1(READ_SPECIALREG(TCR_EL1));
|
||||
} else {
|
||||
arch_mmu_setup_EL1(READ_SPECIALREG(TCR_EL2));
|
||||
arch_cache_disable();
|
||||
_arch_transition_EL2_EL1();
|
||||
}
|
||||
|
||||
arch_cache_enable();
|
||||
|
||||
@@ -20,16 +20,6 @@ static char sPhysicalPageMapperData[sizeof(PMAPPhysicalPageMapper)];
|
||||
static phys_addr_t sEmptyTable;
|
||||
|
||||
|
||||
static void
|
||||
arch_vm_alloc_empty_table(void)
|
||||
{
|
||||
vm_page_reservation reservation;
|
||||
vm_page_reserve_pages(&reservation, 1, VM_PRIORITY_SYSTEM);
|
||||
vm_page* page = vm_page_allocate_page(&reservation, PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR);
|
||||
DEBUG_PAGE_ACCESS_END(page);
|
||||
sEmptyTable = page->physical_page_number << PAGE_SHIFT;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_vm_install_empty_table_ttbr0(void)
|
||||
@@ -103,6 +93,9 @@ arch_vm_translation_map_init(kernel_args* args, VMPhysicalPageMapper** _physical
|
||||
|
||||
*_physicalPageMapper = new (&sPhysicalPageMapperData) PMAPPhysicalPageMapper();
|
||||
|
||||
// Create an empty page table for use when we don't want a userspace page table.
|
||||
sEmptyTable = vm_allocate_early_physical_page(args) << PAGE_SHIFT;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -112,9 +105,6 @@ arch_vm_translation_map_init_post_sem(kernel_args* args)
|
||||
{
|
||||
dprintf("arch_vm_translation_map_init_post_sem\n");
|
||||
|
||||
// Create an empty page table for use when we don't want a userspace page table.
|
||||
arch_vm_alloc_empty_table();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user