blob: 4f9cb4bb361918f98faeac0eea2208ac88d85948 [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/asm_macros.h>
#include <asm.h>
#include <zircon/errors.h>
// For details please refer to ARM Generic Interrupt Controller Architecture Specification,
// GIC architecture 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_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_AP0R0_EL2 S3_4_C12_C8_0
#define ICH_VMCR_EL2 S3_4_C12_C11_7
#define ICH_HCR_EL2_ID 0
#define ICH_VTR_EL2_ID 1
#define ICH_MISR_EL2_ID 2
#define ICH_ELRSR_EL2_ID 3
#define ICH_AP0R0_EL2_ID 4
#define ICH_VMCR_EL2_ID 5
#define ICH_LR_EL2_ID 6
#define LR0_EL2(x) S3_4_C12_C12_ ## x
#define LR8_EL2(x) S3_4_C12_C13_ ## x
#define ICH_LR0 LR0_EL2(0)
#define ICH_LR1 LR0_EL2(1)
#define ICH_LR2 LR0_EL2(2)
#define ICH_LR3 LR0_EL2(3)
#define ICH_LR4 LR0_EL2(4)
#define ICH_LR5 LR0_EL2(5)
#define ICH_LR6 LR0_EL2(6)
#define ICH_LR7 LR0_EL2(7)
#define ICH_LR8 LR8_EL2(0)
#define ICH_LR9 LR8_EL2(1)
#define ICH_LR10 LR8_EL2(2)
#define ICH_LR11 LR8_EL2(3)
#define ICH_LR12 LR8_EL2(4)
#define ICH_LR13 LR8_EL2(5)
#define ICH_LR14 LR8_EL2(6)
#define ICH_LR15 LR8_EL2(7)
#define ICH_LR(x) ICH_LR ## x
#define READ_SYSREG_ID 0
#define WRITE_SYSREG_ID 1
.section .text.el2,"ax",@progbits
.align 12
.macro read_sysreg literal
mrs x0, \literal
b el2_gicv3_done
.endm
.macro write_sysreg literal
msr \literal, x0
b el2_gicv3_done
.endm
.macro invalid_write
b el2_gicv3_done
nop
.endm
// Branch to an address within a jump table, calculated as follows:
// address = table + (reg << 3)
.macro gic_jump table reg
adr x9, \table
add x9, x9, \reg, lsl 3
br x9
.endm
// x0 - Value to write
// x1 - Index for ICH register
// x2 - READ/WRITE
// x3 - Register name/enum
FUNCTION_LABEL(el2_hvc_sysreg)
cbnz x2, .write_sys
gic_jump .Lread_sys x3
.Lread_sys:
read_sysreg ICH_HCR_EL2
read_sysreg ICH_VTR_EL2
read_sysreg ICH_MISR_EL2
read_sysreg ICH_ELRSR_EL2
read_sysreg ICH_AP0R0_EL2
read_sysreg ICH_VMCR_EL2
b el2_gicv3_read_lr
.write_sys:
gic_jump .Lwrite_sys x3
.Lwrite_sys:
write_sysreg ICH_HCR_EL2
invalid_write // ICH_VTR_EL2 is readonly
invalid_write // ICH_MISR_EL2 is readonly
invalid_write // ICH_ELRSR_EL2 is readonly
write_sysreg ICH_AP0R0_EL2
write_sysreg ICH_VMCR_EL2
b el2_gicv3_write_lr
// uint32_t arm64_el2_gicv3_read_gich_hcr();
FUNCTION(arm64_el2_gicv3_read_gich_hcr)
mov x2, READ_SYSREG_ID
mov x3, ICH_HCR_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_read_gich_hcr)
// void arm64_el2_gicv3_write_gich_hcr(uint32_t val)
FUNCTION(arm64_el2_gicv3_write_gich_hcr)
mov x2, WRITE_SYSREG_ID
mov x3, ICH_HCR_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_write_gich_hcr)
// uint32_t arm64_el2_gicv3_read_gich_vtr();
FUNCTION(arm64_el2_gicv3_read_gich_vtr)
mov x2, READ_SYSREG_ID
mov x3, ICH_VTR_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_read_gich_vtr)
// uint32_t arm64_el2_gicv3_read_gich_vmcr();
FUNCTION(arm64_el2_gicv3_read_gich_vmcr)
mov x2, READ_SYSREG_ID
mov x3, ICH_VMCR_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_read_gich_vmcr)
// void arm64_el2_gicv3_write_gich_vmcr(uint32_t val)
FUNCTION(arm64_el2_gicv3_write_gich_vmcr)
mov x2, WRITE_SYSREG_ID
mov x3, ICH_VMCR_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_write_gich_vmcr)
// uint32_t arm64_el2_gicv3_read_gich_elrsr();
FUNCTION(arm64_el2_gicv3_read_gich_elrsr)
mov x2, READ_SYSREG_ID
mov x3, ICH_ELRSR_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_read_gich_elrsr)
// uint32_t arm64_el2_gicv3_read_gich_apr();
FUNCTION(arm64_el2_gicv3_read_gich_apr)
mov x2, READ_SYSREG_ID
mov x3, ICH_AP0R0_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_read_gich_apr)
// void arm64_el2_gicv3_write_gich_apr(uint32_t val)
FUNCTION(arm64_el2_gicv3_write_gich_apr)
mov x2, WRITE_SYSREG_ID
mov x3, ICH_AP0R0_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_write_gich_apr)
// uint32_t arm64_el2_gicv3_read_gich_misr();
FUNCTION(arm64_el2_gicv3_read_gich_misr)
mov x2, READ_SYSREG_ID
mov x3, ICH_MISR_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_read_gich_misr)
// uint64_t arm64_el2_gicv3_read_gich_lr(uint32_t index);
FUNCTION(arm64_el2_gicv3_read_gich_lr)
mov x1, x0
mov x2, READ_SYSREG_ID
mov x3, ICH_LR_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_read_gich_lr)
// void arm64_el2_gicv3_write_gich_lr(uint64_t val, uint32_t index)
FUNCTION(arm64_el2_gicv3_write_gich_lr)
mov x2, WRITE_SYSREG_ID
mov x3, ICH_LR_EL2_ID
hvc 5
ret
END_FUNCTION(arm64_el2_gicv3_write_gich_lr)
// x1 - Index for LR register
FUNCTION_LABEL(el2_gicv3_read_lr)
gic_jump .Llr_read_table x1
.Llr_read_table:
read_sysreg ICH_LR(0)
read_sysreg ICH_LR(1)
read_sysreg ICH_LR(2)
read_sysreg ICH_LR(3)
read_sysreg ICH_LR(4)
read_sysreg ICH_LR(5)
read_sysreg ICH_LR(6)
read_sysreg ICH_LR(7)
read_sysreg ICH_LR(8)
read_sysreg ICH_LR(9)
read_sysreg ICH_LR(10)
read_sysreg ICH_LR(11)
read_sysreg ICH_LR(12)
read_sysreg ICH_LR(13)
read_sysreg ICH_LR(14)
read_sysreg ICH_LR(15)
// x0 - Value to write
// x1 - Index for LR register
FUNCTION_LABEL(el2_gicv3_write_lr)
gic_jump .Llr_write_table x1
.Llr_write_table:
write_sysreg ICH_LR(0)
write_sysreg ICH_LR(1)
write_sysreg ICH_LR(2)
write_sysreg ICH_LR(3)
write_sysreg ICH_LR(4)
write_sysreg ICH_LR(5)
write_sysreg ICH_LR(6)
write_sysreg ICH_LR(7)
write_sysreg ICH_LR(8)
write_sysreg ICH_LR(9)
write_sysreg ICH_LR(10)
write_sysreg ICH_LR(11)
write_sysreg ICH_LR(12)
write_sysreg ICH_LR(13)
write_sysreg ICH_LR(14)
write_sysreg ICH_LR(15)
FUNCTION_LABEL(el2_gicv3_done)
msr vttbr_el2, xzr
isb
eret