blob: ea1235cfa4db63e615f870e88249b7453390d3e3 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <arch/arm64/hypervisor/el2_state.h>
#include <arch/asm_macros.h>
#include <asm.h>
#include <zircon/errors.h>
// For details please refer to ARM Generic Interrupt Controller Architecture
// Specification, version 3.0 and version 4.0. Table 8-6 Mapping of MSR and MRS
// to virtual interface control registers, AArch64 state and Table 8-8 Mapping
// of MCR and MRC to virtual interface control registers, AArch32 state.
#define ICH_AP0R(x) S3_4_C12_C8_ ## x
#define ICH_AP1R(x) S3_4_C12_C9_ ## x
#define ICH_HCR_EL2 S3_4_C12_C11_0
#define ICH_VTR_EL2 S3_4_C12_C11_1
#define ICH_MISR_EL2 S3_4_C12_C11_2
#define ICH_ELRSR_EL2 S3_4_C12_C11_5
#define ICH_VMCR_EL2 S3_4_C12_C11_7
#define ICH_LR0(x) S3_4_C12_C12_ ## x
#define ICH_LR8(x) S3_4_C12_C13_ ## x
#define ICH_LR0_EL2 ICH_LR0(0)
#define ICH_LR1_EL2 ICH_LR0(1)
#define ICH_LR2_EL2 ICH_LR0(2)
#define ICH_LR3_EL2 ICH_LR0(3)
#define ICH_LR4_EL2 ICH_LR0(4)
#define ICH_LR5_EL2 ICH_LR0(5)
#define ICH_LR6_EL2 ICH_LR0(6)
#define ICH_LR7_EL2 ICH_LR0(7)
#define ICH_LR8_EL2 ICH_LR8(0)
#define ICH_LR9_EL2 ICH_LR8(1)
#define ICH_LR10_EL2 ICH_LR8(2)
#define ICH_LR11_EL2 ICH_LR8(3)
#define ICH_LR12_EL2 ICH_LR8(4)
#define ICH_LR13_EL2 ICH_LR8(5)
#define ICH_LR14_EL2 ICH_LR8(6)
#define ICH_LR15_EL2 ICH_LR8(7)
#define ICH_LR(x) ICH_LR ## x ## _EL2
#define READ_SYSREG 0
#define WRITE_SYSREG 1
.section .text.el2,"ax",@progbits
.align 12
// Temporary registers to use.
reg_xa .req x11
reg_xb .req x12
reg_wb .req w12
reg_xc .req x13
.macro read_sysreg sysreg, off
mrs reg_xa, \sysreg
str reg_xa, [x0, \off]
.endm
.macro write_sysreg sysreg, off
ldr reg_xa, [x0, \off]
msr \sysreg, reg_xa
.endm
// Calculate the jump table index from a value in memory:
// reg_xb = max - x0[off]
.macro gic_index max, off
ldurb reg_wb, [x0, \off]
mov reg_xc, \max
sub reg_xb, reg_xc, reg_xb
.endm
// Branch to an address within a jump table, calculated as follows:
// address = table + (reg_xb << 3)
.macro gic_jump table
adr reg_xc, \table
add reg_xc, reg_xc, reg_xb, lsl 3
br reg_xc
.endm
// void arm64_el2_gicv3_read_gich_state(zx_paddr_t state)
FUNCTION(arm64_el2_gicv3_read_gich_state)
mov reg_xa, READ_SYSREG
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_read_gich_state)
// void arm64_el2_gicv3_write_gich_state(zx_paddr_t state, uint32_t hcr)
FUNCTION(arm64_el2_gicv3_write_gich_state)
mov reg_xa, WRITE_SYSREG
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_write_gich_state)
FUNCTION_LABEL(el2_hvc_gich_state)
cbnz reg_xa, el2_hvc_write_gich_state
FUNCTION_LABEL(el2_hvc_read_gich_state)
msr ICH_HCR_EL2, xzr
read_sysreg ICH_VMCR_EL2, IS_VMCR
read_sysreg ICH_MISR_EL2, IS_MISR
read_sysreg ICH_ELRSR_EL2, IS_ELRSR
gic_index 4, IS_NUM_APRS
gic_jump .Lread_ap0r
.Lread_ap0r:
read_sysreg ICH_AP0R(3), IS_APR(0, 3)
read_sysreg ICH_AP0R(2), IS_APR(0, 2)
read_sysreg ICH_AP0R(1), IS_APR(0, 1)
read_sysreg ICH_AP0R(0), IS_APR(0, 0)
gic_jump .Lread_ap1r
.Lread_ap1r:
read_sysreg ICH_AP1R(3), IS_APR(1, 3)
read_sysreg ICH_AP1R(2), IS_APR(1, 2)
read_sysreg ICH_AP1R(1), IS_APR(1, 1)
read_sysreg ICH_AP1R(0), IS_APR(1, 0)
gic_index 16, IS_NUM_LRS
gic_jump .Llr_read_lr
.Llr_read_lr:
read_sysreg ICH_LR(15), IS_LR(15)
read_sysreg ICH_LR(14), IS_LR(14)
read_sysreg ICH_LR(13), IS_LR(13)
read_sysreg ICH_LR(12), IS_LR(12)
read_sysreg ICH_LR(11), IS_LR(11)
read_sysreg ICH_LR(10), IS_LR(10)
read_sysreg ICH_LR(9), IS_LR(9)
read_sysreg ICH_LR(8), IS_LR(8)
read_sysreg ICH_LR(7), IS_LR(7)
read_sysreg ICH_LR(6), IS_LR(6)
read_sysreg ICH_LR(5), IS_LR(5)
read_sysreg ICH_LR(4), IS_LR(4)
read_sysreg ICH_LR(3), IS_LR(3)
read_sysreg ICH_LR(2), IS_LR(2)
read_sysreg ICH_LR(1), IS_LR(1)
read_sysreg ICH_LR(0), IS_LR(0)
b el2_gicv3_done
FUNCTION_LABEL(el2_hvc_write_gich_state)
msr ICH_HCR_EL2, x1
write_sysreg ICH_VMCR_EL2, IS_VMCR
gic_index 4, IS_NUM_APRS
gic_jump .Lwrite_ap0r
.Lwrite_ap0r:
write_sysreg ICH_AP0R(3), IS_APR(0, 3)
write_sysreg ICH_AP0R(2), IS_APR(0, 2)
write_sysreg ICH_AP0R(1), IS_APR(0, 1)
write_sysreg ICH_AP0R(0), IS_APR(0, 0)
gic_jump .Lwrite_ap1r
.Lwrite_ap1r:
write_sysreg ICH_AP1R(3), IS_APR(1, 3)
write_sysreg ICH_AP1R(2), IS_APR(1, 2)
write_sysreg ICH_AP1R(1), IS_APR(1, 1)
write_sysreg ICH_AP1R(0), IS_APR(1, 0)
gic_index 16, IS_NUM_LRS
gic_jump .Llr_write_lr
.Llr_write_lr:
write_sysreg ICH_LR(15), IS_LR(15)
write_sysreg ICH_LR(14), IS_LR(14)
write_sysreg ICH_LR(13), IS_LR(13)
write_sysreg ICH_LR(12), IS_LR(12)
write_sysreg ICH_LR(11), IS_LR(11)
write_sysreg ICH_LR(10), IS_LR(10)
write_sysreg ICH_LR(9), IS_LR(9)
write_sysreg ICH_LR(8), IS_LR(8)
write_sysreg ICH_LR(7), IS_LR(7)
write_sysreg ICH_LR(6), IS_LR(6)
write_sysreg ICH_LR(5), IS_LR(5)
write_sysreg ICH_LR(4), IS_LR(4)
write_sysreg ICH_LR(3), IS_LR(3)
write_sysreg ICH_LR(2), IS_LR(2)
write_sysreg ICH_LR(1), IS_LR(1)
write_sysreg ICH_LR(0), IS_LR(0)
b el2_gicv3_done
// uint32_t arm64_el2_gicv3_read_gich_vtr()
FUNCTION(arm64_el2_gicv3_read_gich_vtr)
hvc 6
ret
END_FUNCTION(arm64_el2_gicv3_read_gich_vtr)
FUNCTION_LABEL(el2_hvc_gich_vtr)
mrs x0, ICH_VTR_EL2
b el2_gicv3_done
FUNCTION_LABEL(el2_gicv3_done)
msr vttbr_el2, xzr
isb
eret