genode/repos/base-hw/src/include/hw/spec/arm_64/cpu.h

289 lines
7.0 KiB
C++

/*
* \brief CPU definitions for ARM 64bit
* \author Stefan Kalkowski
* \date 2019-05-22
*/
/*
* Copyright (C) 2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SRC__LIB__HW__SPEC__ARM_64__CPU_H_
#define _SRC__LIB__HW__SPEC__ARM_64__CPU_H_
#define SYSTEM_REGISTER(sz, name, reg, ...) \
struct name : Genode::Register<sz> \
{ \
static access_t read() \
{ \
access_t v; \
asm volatile ("mrs %0, " #reg : "=r" (v)); \
return v; \
} \
\
static void write(access_t const v) { \
asm volatile ("msr " #reg ", %0" :: "r" (v)); } \
\
__VA_ARGS__; \
};
namespace Hw { struct Arm_64_cpu; }
struct Hw::Arm_64_cpu
{
SYSTEM_REGISTER(64, Actlr_el1, actlr_el1);
SYSTEM_REGISTER(64, Amair_el1, amair_el1);
SYSTEM_REGISTER(32, Ccsidr_el1, ccsidr_el1);
SYSTEM_REGISTER(64, Clidr_el1, clidr_el1,
enum Cache_type {
NO_CACHE,
INSTRUCTION_CACHE,
DATA_CACHE,
SEPARATE_CACHE,
UNIFIED_CACHE
};
);
SYSTEM_REGISTER(32, Csselr_el1, csselr_el1,
struct Instr : Bitfield<0, 1> {};
struct Level : Bitfield<1, 3> {};
);
SYSTEM_REGISTER(32, Cpacr_el1, cpacr_el1);
SYSTEM_REGISTER(32, Cptr_el2, cptr_el2,
struct Tta : Bitfield<20, 1> {}; );
SYSTEM_REGISTER(64, Current_el, currentel,
enum Level { EL0, EL1, EL2, EL3 };
struct El : Bitfield<2, 2> {};
);
struct Esr : Genode::Register<64>
{
struct Ec : Bitfield<26, 6>
{
enum Exception {
SVC = 0b010101,
INST_ABORT_LOW_LEVEL = 0b100000,
INST_ABORT_SAME_LEVEL = 0b100001,
DATA_ABORT_LOW_LEVEL = 0b100100,
DATA_ABORT_SAME_LEVEL = 0b100101,
};
};
struct Iss : Bitfield<0, 25>
{
struct Abort : Register<32>
{
struct Level : Bitfield<0, 2> {};
struct Fsc : Bitfield<2, 4>
{
enum Fault {
ADDR_SIZE,
TRANSLATION,
ACCESS_FLAG,
PERMISSION
};
enum Data_abort_fault { ALIGNMENT = 8 };
};
struct Write : Bitfield<6, 1> {};
};
};
};
SYSTEM_REGISTER(64, Esr_el1, esr_el1);
SYSTEM_REGISTER(64, Far_el1, far_el1);
SYSTEM_REGISTER(32, Fpcr, fpcr);
SYSTEM_REGISTER(64, Hcr_el2, hcr_el2,
struct Rw : Bitfield<31, 1> {};
);
SYSTEM_REGISTER(32, Hstr_el2, hstr_el2);
SYSTEM_REGISTER(64, Id_aa64isar0_el1, id_aa64isar0_el1);
SYSTEM_REGISTER(64, Id_aa64isar1_el1, id_aa64isar1_el1);
SYSTEM_REGISTER(64, Id_aa64mmfr0_el1, id_aa64mmfr0_el1);
SYSTEM_REGISTER(64, Id_aa64mmfr1_el1, id_aa64mmfr1_el1);
SYSTEM_REGISTER(64, Id_aa64mmfr2_el1, id_aa64mmfr2_el1);
SYSTEM_REGISTER(64, Id_pfr0, id_aa64pfr0_el1,
struct El2 : Bitfield<8, 4> {};
struct El3 : Bitfield<8, 4> {};
);
struct Mair : Genode::Register<64>
{
enum Attributes {
DEVICE_MEMORY = 0x04,
NORMAL_MEMORY_UNCACHED = 0x44,
NORMAL_MEMORY_CACHED = 0xff,
};
struct Attr0 : Bitfield<0, 8> {};
struct Attr1 : Bitfield<8, 8> {};
struct Attr2 : Bitfield<16, 8> {};
struct Attr3 : Bitfield<24, 8> {};
};
SYSTEM_REGISTER(64, Mair_el1, mair_el1);
SYSTEM_REGISTER(64, Mair_el2, mair_el2);
SYSTEM_REGISTER(64, Mpidr, mpidr_el1);
SYSTEM_REGISTER(32, Pmcr_el0, pmcr_el0);
SYSTEM_REGISTER(32, Pmcntenset_el0, pmcntenset_el0);
SYSTEM_REGISTER(32, Pmuserenr_el0, pmuserenr_el0);
SYSTEM_REGISTER(64, Scr, scr_el3,
struct Ns : Bitfield<0, 1> {};
struct Smd : Bitfield<7, 1> {};
struct Rw : Bitfield<10, 1> {};
);
struct Sctlr : Genode::Register<64>
{
struct M : Bitfield<0, 1> { };
struct A : Bitfield<1, 1> { };
struct C : Bitfield<2, 1> { };
struct Sa : Bitfield<3, 1> { };
struct Sa0 : Bitfield<4, 1> { };
struct I : Bitfield<12, 1> { };
struct Uct : Bitfield<15, 1> { };
struct Wxn : Bitfield<19, 1> { };
};
SYSTEM_REGISTER(64, Sctlr_el1, sctlr_el1);
SYSTEM_REGISTER(64, Sctlr_el2, sctlr_el2);
struct Spsr : Genode::Register<64>
{
struct Sp : Bitfield<0, 1> {};
struct El : Bitfield<2, 2> {};
struct F : Bitfield<6, 1> {};
struct I : Bitfield<7, 1> {};
struct A : Bitfield<8, 1> {};
struct D : Bitfield<9, 1> {};
};
SYSTEM_REGISTER(64, Spsr_el2, spsr_el2);
SYSTEM_REGISTER(64, Spsr_el3, spsr_el3);
SYSTEM_REGISTER(64, Tcr_el1, tcr_el1,
struct T0sz : Bitfield<0, 6> { };
struct Epd0 : Bitfield<7, 1> { };
struct Irgn0 : Bitfield<8, 2> { };
struct Orgn0 : Bitfield<10, 2> { };
struct Sh0 : Bitfield<12, 2> { };
struct Tg0 : Bitfield<14, 2> { };
struct T1sz : Bitfield<16, 6> { };
struct A1 : Bitfield<22, 1> { };
struct Epd1 : Bitfield<23, 1> { };
struct Irgn1 : Bitfield<24, 2> { };
struct Orgn1 : Bitfield<26, 2> { };
struct Sh1 : Bitfield<28, 2> { };
struct Tg1 : Bitfield<30, 2> { };
struct Ips : Bitfield<32, 3> { };
struct As : Bitfield<36, 1> { };
);
SYSTEM_REGISTER(64, Tcr_el2, tcr_el2,
struct T0sz : Bitfield<0, 6> { };
struct Irgn0 : Bitfield<8, 2> { };
struct Orgn0 : Bitfield<10, 2> { };
struct Sh0 : Bitfield<12, 2> { };
);
struct Ttbr : Genode::Register<64>
{
struct Baddr : Bitfield<0, 48> { };
struct Asid : Bitfield<48, 16> { };
};
SYSTEM_REGISTER(64, Ttbr0_el1, ttbr0_el1);
SYSTEM_REGISTER(64, Ttbr0_el2, ttbr0_el2);
SYSTEM_REGISTER(64, Ttbr1_el1, ttbr1_el1);
SYSTEM_REGISTER(64, Vbar_el1, vbar_el1);
SYSTEM_REGISTER(64, Vbar_el2, vbar_el2);
SYSTEM_REGISTER(32, Vtcr_el2, vtcr_el2,
struct T0sz : Bitfield<0, 6> {};
struct Sl0 : Bitfield<6, 2> {};
);
SYSTEM_REGISTER(64, Vttbr_el2, vttbr_el2,
struct CnP : Bitfield<0, 1> { };
struct Ba : Bitfield<1, 47> { };
struct Asid : Bitfield<48, 8> { };
);
static inline unsigned current_privilege_level() {
return Current_el::El::get(Current_el::read()); }
/*****************************
** Generic timer interface **
*****************************/
SYSTEM_REGISTER(64, Cntfrq_el0, cntfrq_el0);
SYSTEM_REGISTER(32, Cntp_ctl_el0, cntp_ctl_el0,
struct Enable : Bitfield<0, 1> {};
struct Istatus : Bitfield<2, 1> {};
);
SYSTEM_REGISTER(64, Cntpct_el0, cntpct_el0);
SYSTEM_REGISTER(32, Cntp_tval_el0, cntp_tval_el0);
SYSTEM_REGISTER(32, Cntkctl_el1, cntkctl_el1);
SYSTEM_REGISTER(32, Cnthctl_el2, cnthctl_el2);
using Cntfrq = Cntfrq_el0;
using Cntp_ctl = Cntp_ctl_el0;
using Cntpct = Cntpct_el0;
using Cntp_tval = Cntp_tval_el0;
static inline void wait_for_xchg(volatile int * addr,
int new_value,
int expected_value)
{
asm volatile(
/* check if load value of 'addr' is as expected */
"1: ldxr w7, [%0] \n"
"cmp w7, %w2 \n"
"b.eq 2f \n"
/* if not, wait for other CPU to send us an event */
"wfe \n"
"b.ne 1b \n"
/* if yes, attempt to write 'new_value' to 'addr' */
"2: stxr w7, %w1, [%0]\n"
/* if write failed, restart */
"cbnz w7, 1b \n"
"dmb #0 \n"
:: "r"(addr), "r"(new_value), "r"(expected_value) : "cc", "x7");
}
static inline void wakeup_waiting_cpus()
{
asm volatile(
"dsb #0 \n"
"sev \n"
);
}
};
#undef SYSTEM_REGISTER
#endif /* _SRC__LIB__HW__SPEC__ARM_64__CPU_H_ */