mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 16:35:28 +00:00
parent
e7d57ded36
commit
14e9a89cba
@ -210,7 +210,7 @@ class Kernel::Mode_transition_control
|
||||
enum {
|
||||
SIZE_LOG2 = Genode::Translation_table::MIN_PAGE_SIZE_LOG2,
|
||||
SIZE = 1 << SIZE_LOG2,
|
||||
VIRT_BASE = Processor::EXCEPTION_ENTRY,
|
||||
VIRT_BASE = Processor::exception_entry,
|
||||
ALIGN_LOG2 = Genode::Translation_table::ALIGNM_LOG2,
|
||||
ALIGN = 1 << ALIGN_LOG2,
|
||||
};
|
||||
|
@ -46,7 +46,7 @@ class Kernel::Idle_thread : public Thread
|
||||
|
||||
enum {
|
||||
STACK_SIZE = sizeof(addr_t) * 32,
|
||||
STACK_ALIGNM = Cpu::DATA_ACCESS_ALIGNM,
|
||||
STACK_ALIGNM = Cpu::data_access_align,
|
||||
};
|
||||
|
||||
char _stack[STACK_SIZE] __attribute__((aligned(STACK_ALIGNM)));
|
||||
|
@ -35,26 +35,20 @@ class Genode::Arm
|
||||
{
|
||||
public:
|
||||
|
||||
enum {
|
||||
TTBCR_N = 0,
|
||||
EXCEPTION_ENTRY = 0xffff0000,
|
||||
DATA_ACCESS_ALIGNM = 4,
|
||||
};
|
||||
static constexpr addr_t exception_entry = 0xffff0000;
|
||||
static constexpr addr_t data_access_align = 4;
|
||||
|
||||
/**
|
||||
* Multiprocessor affinity register
|
||||
*/
|
||||
struct Mpidr : Register<32>
|
||||
{
|
||||
struct Aff_0 : Bitfield<0, 8> { };
|
||||
struct Aff_0 : Bitfield<0, 8> { }; /* affinity value 0 */
|
||||
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
asm volatile ("mrc p15, 0, %[v], c0, c0, 5" : [v] "=r" (v) ::);
|
||||
asm volatile ("mrc p15, 0, %0, c0, c0, 5" : "=r" (v) :: );
|
||||
return v;
|
||||
}
|
||||
};
|
||||
@ -64,13 +58,10 @@ class Genode::Arm
|
||||
*/
|
||||
struct Ctr : Register<32>
|
||||
{
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
asm volatile ("mrc p15, 0, %[v], c0, c0, 1" : [v]"=r"(v) :: );
|
||||
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r" (v) :: );
|
||||
return v;
|
||||
}
|
||||
};
|
||||
@ -85,9 +76,6 @@ class Genode::Arm
|
||||
struct I : Bitfield<12,1> { }; /* enable instruction caches */
|
||||
struct V : Bitfield<13,1> { }; /* select exception entry */
|
||||
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
@ -95,14 +83,11 @@ class Genode::Arm
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write register value
|
||||
*/
|
||||
static void write(access_t const v) {
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0" :: "r" (v) : ); }
|
||||
|
||||
/**
|
||||
* Initialization that is common
|
||||
* Do initialization that is common on value 'v'
|
||||
*/
|
||||
static void init_common(access_t & v)
|
||||
{
|
||||
@ -112,7 +97,7 @@ class Genode::Arm
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization for virtual kernel stage
|
||||
* Do initialization for virtual mode in kernel on value 'v'
|
||||
*/
|
||||
static void init_virt_kernel(access_t & v) { M::set(v, 1); }
|
||||
};
|
||||
@ -122,28 +107,15 @@ class Genode::Arm
|
||||
*/
|
||||
struct Ttbcr : Register<32>
|
||||
{
|
||||
struct N : Bitfield<0, 3> { }; /* base address width */
|
||||
|
||||
/**
|
||||
* Write register, only in privileged CPU mode
|
||||
*/
|
||||
static void write(access_t const v) {
|
||||
asm volatile ("mcr p15, 0, %[v], c2, c0, 2" :: [v]"r"(v) : ); }
|
||||
asm volatile ("mcr p15, 0, %0, c2, c0, 2" :: "r" (v) : ); }
|
||||
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
asm volatile ("mrc p15, 0, %[v], c2, c0, 2" : [v]"=r"(v) :: );
|
||||
asm volatile ("mrc p15, 0, %0, c2, c0, 2" : "=r" (v) :: );
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value for the switch to virtual mode in kernel
|
||||
*/
|
||||
static access_t init_virt_kernel() { return N::bits(TTBCR_N); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -151,21 +123,15 @@ class Genode::Arm
|
||||
*/
|
||||
struct Ttbr0 : Register<32>
|
||||
{
|
||||
struct Ba : Bitfield<14-TTBCR_N, 18+TTBCR_N> { };
|
||||
struct Ba : Bitfield<14, 18> { }; /* base */
|
||||
|
||||
/**
|
||||
* Write register, only in privileged CPU mode
|
||||
*/
|
||||
static void write(access_t const v) {
|
||||
asm volatile ("mcr p15, 0, %[v], c2, c0, 0" :: [v]"r"(v) : ); }
|
||||
asm volatile ("mcr p15, 0, %0, c2, c0, 0" :: "r" (v) : ); }
|
||||
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
asm volatile ("mrc p15, 0, %[v], c2, c0, 0" : [v]"=r"(v) :: );
|
||||
asm volatile ("mrc p15, 0, %0, c2, c0, 0" : "=r" (v) :: );
|
||||
return v;
|
||||
}
|
||||
};
|
||||
@ -175,48 +141,15 @@ class Genode::Arm
|
||||
*/
|
||||
struct Dacr : Register<32>
|
||||
{
|
||||
enum Dx_values { NO_ACCESS = 0, CLIENT = 1 };
|
||||
struct D0 : Bitfield<0,2> { }; /* access mode for domain 0 */
|
||||
|
||||
/**
|
||||
* Access values for the 16 available domains
|
||||
*/
|
||||
struct D0 : Bitfield<0,2> { };
|
||||
struct D1 : Bitfield<2,2> { };
|
||||
struct D2 : Bitfield<4,2> { };
|
||||
struct D3 : Bitfield<6,2> { };
|
||||
struct D4 : Bitfield<8,2> { };
|
||||
struct D5 : Bitfield<10,2> { };
|
||||
struct D6 : Bitfield<12,2> { };
|
||||
struct D7 : Bitfield<14,2> { };
|
||||
struct D8 : Bitfield<16,2> { };
|
||||
struct D9 : Bitfield<18,2> { };
|
||||
struct D10 : Bitfield<20,2> { };
|
||||
struct D11 : Bitfield<22,2> { };
|
||||
struct D12 : Bitfield<24,2> { };
|
||||
struct D13 : Bitfield<26,2> { };
|
||||
struct D14 : Bitfield<28,2> { };
|
||||
struct D15 : Bitfield<30,2> { };
|
||||
|
||||
/**
|
||||
* Write register, only in privileged CPU mode
|
||||
*/
|
||||
static void write(access_t const v) {
|
||||
asm volatile ("mcr p15, 0, %[v], c3, c0, 0" :: [v]"r"(v) : ); }
|
||||
asm volatile ("mcr p15, 0, %0, c3, c0, 0" :: "r" (v) : ); }
|
||||
|
||||
/**
|
||||
* Initialize for Genodes operational mode
|
||||
* Return value initialized for virtual mode in kernel
|
||||
*/
|
||||
static access_t init_virt_kernel()
|
||||
{
|
||||
return D0::bits(CLIENT) | D1::bits(NO_ACCESS) |
|
||||
D2::bits(NO_ACCESS) | D3::bits(NO_ACCESS) |
|
||||
D4::bits(NO_ACCESS) | D5::bits(NO_ACCESS) |
|
||||
D6::bits(NO_ACCESS) | D7::bits(NO_ACCESS) |
|
||||
D8::bits(NO_ACCESS) | D9::bits(NO_ACCESS) |
|
||||
D10::bits(NO_ACCESS) | D11::bits(NO_ACCESS) |
|
||||
D12::bits(NO_ACCESS) | D13::bits(NO_ACCESS) |
|
||||
D14::bits(NO_ACCESS) | D15::bits(NO_ACCESS);
|
||||
}
|
||||
static access_t init_virt_kernel() { return D0::bits(1); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -224,14 +157,8 @@ class Genode::Arm
|
||||
*/
|
||||
struct Icimvau : Register<32>
|
||||
{
|
||||
/**
|
||||
* Write register value
|
||||
*/
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile (
|
||||
"mcr p15, 0, %[v], c7, c5, 1\n" :: [v] "r" (v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 1" :: "r" (v) : ); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -239,14 +166,8 @@ class Genode::Arm
|
||||
*/
|
||||
struct Dccmvac : Register<32>
|
||||
{
|
||||
/**
|
||||
* Write register value
|
||||
*/
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile (
|
||||
"mcr p15, 0, %[v], c7, c10, 1\n" :: [v] "r" (v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r" (v) : ); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -254,21 +175,13 @@ class Genode::Arm
|
||||
*/
|
||||
struct Cidr : Register<32>
|
||||
{
|
||||
/**
|
||||
* Write register value
|
||||
*/
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %[v], c13, c0, 1" :: [v]"r"(v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile ("mcr p15, 0, %0, c13, c0, 1" :: "r" (v) : ); }
|
||||
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
asm volatile ("mrc p15, 0, %[v], c13, c0, 1" : [v]"=r"(v) :: );
|
||||
asm volatile ("mrc p15, 0, %0, c13, c0, 1" : "=r" (v) :: );
|
||||
return v;
|
||||
}
|
||||
};
|
||||
@ -278,81 +191,59 @@ class Genode::Arm
|
||||
*/
|
||||
struct Psr : Register<32>
|
||||
{
|
||||
struct M : Bitfield<0,5> /* processor mode */
|
||||
{
|
||||
enum { USER = 0b10000, SUPERVISOR = 0b10011 };
|
||||
};
|
||||
|
||||
struct T : Bitfield<5,1> /* instruction state */
|
||||
{
|
||||
enum { ARM = 0 };
|
||||
};
|
||||
static constexpr access_t usr = 16;
|
||||
static constexpr access_t svc = 19;
|
||||
|
||||
struct M : Bitfield<0,5> { }; /* CPU mode */
|
||||
struct F : Bitfield<6,1> { }; /* FIQ disable */
|
||||
struct I : Bitfield<7,1> { }; /* IRQ disable */
|
||||
struct A : Bitfield<8,1> { }; /* asynchronous abort disable */
|
||||
struct A : Bitfield<8,1> { }; /* async. abort disable */
|
||||
|
||||
struct E : Bitfield<9,1> /* load/store endianess */
|
||||
{
|
||||
enum { LITTLE = 0 };
|
||||
};
|
||||
|
||||
struct J : Bitfield<24,1> /* instruction state */
|
||||
{
|
||||
enum { ARM = 0 };
|
||||
};
|
||||
|
||||
/**
|
||||
* Read register
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
asm volatile ("mrs %[v], cpsr" : [v] "=r" (v) : : );
|
||||
asm volatile ("mrs %0, cpsr" : "=r" (v) :: );
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write register
|
||||
*/
|
||||
static void write(access_t const v) {
|
||||
asm volatile ("msr cpsr, %[v]" : : [v] "r" (v) : ); }
|
||||
asm volatile ("msr cpsr, %0" :: "r" (v) : ); }
|
||||
|
||||
/**
|
||||
* Initial value for a user execution context with trustzone
|
||||
*
|
||||
* FIXME: This function should not be declared in 'Arm' but in
|
||||
* 'Arm_v7', but for now the declaration is necessary
|
||||
* because of 'User_context::User_context()'.
|
||||
* Return value initialized for user execution with trustzone
|
||||
*/
|
||||
inline static access_t init_user_with_trustzone();
|
||||
|
||||
/**
|
||||
* Initial value for an userland execution context
|
||||
* Do common initialization on register value 'v'
|
||||
*/
|
||||
static access_t init_user()
|
||||
static void init_common(access_t & v)
|
||||
{
|
||||
return M::bits(M::USER) |
|
||||
T::bits(T::ARM) |
|
||||
F::bits(1) |
|
||||
I::bits(0) |
|
||||
A::bits(1) |
|
||||
E::bits(E::LITTLE) |
|
||||
J::bits(J::ARM);
|
||||
F::set(v, 1);
|
||||
A::set(v, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial value for the kernel execution context
|
||||
* Return initial value for user execution
|
||||
*/
|
||||
static access_t init_user()
|
||||
{
|
||||
access_t v = 0;
|
||||
init_common(v);
|
||||
M::set(v, usr);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return initial value for the kernel
|
||||
*/
|
||||
static access_t init_kernel()
|
||||
{
|
||||
return M::bits(M::SUPERVISOR) |
|
||||
T::bits(T::ARM) |
|
||||
F::bits(1) |
|
||||
I::bits(1) |
|
||||
A::bits(1) |
|
||||
E::bits(E::LITTLE) |
|
||||
J::bits(J::ARM);
|
||||
access_t v = 0;
|
||||
init_common(v);
|
||||
M::set(v, svc);
|
||||
I::set(v, 1);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
@ -361,17 +252,12 @@ class Genode::Arm
|
||||
*/
|
||||
struct Fsr : Register<32>
|
||||
{
|
||||
/**
|
||||
* Fault status encoding
|
||||
*/
|
||||
enum Fault_status
|
||||
{
|
||||
SECTION_TRANSLATION = 5,
|
||||
PAGE_TRANSLATION = 7,
|
||||
};
|
||||
static constexpr access_t section = 5;
|
||||
static constexpr access_t page = 7;
|
||||
|
||||
struct Fs_3_0 : Bitfield<0, 4> { }; /* fault status */
|
||||
struct Fs_4 : Bitfield<10, 1> { }; /* fault status */
|
||||
struct Fs_0 : Bitfield<0, 4> { }; /* fault status */
|
||||
struct Fs_1 : Bitfield<10, 1> { }; /* fault status */
|
||||
struct Fs : Bitset_2<Fs_0, Fs_1> { }; /* fault status */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -379,25 +265,12 @@ class Genode::Arm
|
||||
*/
|
||||
struct Ifsr : Fsr
|
||||
{
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
asm volatile ("mrc p15, 0, %[v], c5, c0, 1" : [v]"=r"(v) :: );
|
||||
asm volatile ("mrc p15, 0, %0, c5, c0, 1" : "=r" (v) :: );
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read fault status
|
||||
*/
|
||||
static Fault_status fault_status()
|
||||
{
|
||||
access_t const v = read();
|
||||
return (Fault_status)(Fs_3_0::get(v) |
|
||||
(Fs_4::get(v) << Fs_3_0::WIDTH));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -407,24 +280,12 @@ class Genode::Arm
|
||||
{
|
||||
struct Wnr : Bitfield<11, 1> { }; /* write not read bit */
|
||||
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
asm volatile ("mrc p15, 0, %[v], c5, c0, 0" : [v]"=r"(v) :: );
|
||||
asm volatile ("mrc p15, 0, %0, c5, c0, 0" : "=r" (v) :: );
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read fault status
|
||||
*/
|
||||
static Fault_status fault_status() {
|
||||
access_t const v = read();
|
||||
return (Fault_status)(Fs_3_0::get(v) |
|
||||
(Fs_4::get(v) << Fs_3_0::WIDTH));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -432,10 +293,8 @@ class Genode::Arm
|
||||
*/
|
||||
struct Dfar : Register<32>
|
||||
{
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read() {
|
||||
static access_t read()
|
||||
{
|
||||
access_t v;
|
||||
asm volatile ("mrc p15, 0, %[v], c6, c0, 0" : [v]"=r"(v) :: );
|
||||
return v;
|
||||
@ -477,10 +336,9 @@ class Genode::Arm
|
||||
*/
|
||||
User_context();
|
||||
|
||||
/***************************************************
|
||||
** Communication between user and context holder **
|
||||
***************************************************/
|
||||
|
||||
/**
|
||||
* Support for kernel calls
|
||||
*/
|
||||
void user_arg_0(unsigned const arg) { r0 = arg; }
|
||||
void user_arg_1(unsigned const arg) { r1 = arg; }
|
||||
void user_arg_2(unsigned const arg) { r2 = arg; }
|
||||
@ -511,62 +369,52 @@ class Genode::Arm
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the context is in a page fault due to a translation miss
|
||||
* Return if the context is in a page fault due to translation miss
|
||||
*
|
||||
* \param va holds the virtual fault-address if call returns 1
|
||||
* \param w holds wether it's a write fault if call returns 1
|
||||
*/
|
||||
bool in_fault(addr_t & va, addr_t & w) const
|
||||
{
|
||||
/* determine fault type */
|
||||
switch (cpu_exception) {
|
||||
|
||||
case PREFETCH_ABORT: {
|
||||
|
||||
/* check if fault was caused by a translation miss */
|
||||
Ifsr::Fault_status const fs = Ifsr::fault_status();
|
||||
if (fs == Ifsr::SECTION_TRANSLATION ||
|
||||
fs == Ifsr::PAGE_TRANSLATION)
|
||||
{
|
||||
Ifsr::access_t const fs = Ifsr::Fs::get(Ifsr::read());
|
||||
if (fs != Ifsr::section && fs != Ifsr::page) { return 0; }
|
||||
|
||||
/* fetch fault data */
|
||||
w = 0;
|
||||
va = ip;
|
||||
return 1;
|
||||
}
|
||||
return 0; }
|
||||
return 1; }
|
||||
|
||||
case DATA_ABORT: {
|
||||
|
||||
/* check if fault was caused by translation miss */
|
||||
Dfsr::Fault_status const fs = Dfsr::fault_status();
|
||||
if(fs == Dfsr::SECTION_TRANSLATION ||
|
||||
fs == Dfsr::PAGE_TRANSLATION)
|
||||
{
|
||||
Dfsr::access_t const fs = Dfsr::Fs::get(Dfsr::read());
|
||||
if (fs != Dfsr::section && fs != Dfsr::page) { return 0; }
|
||||
|
||||
/* fetch fault data */
|
||||
Dfsr::access_t const dfsr = Dfsr::read();
|
||||
w = Dfsr::Wnr::get(dfsr);
|
||||
va = Dfar::read();
|
||||
return 1;
|
||||
}
|
||||
return 0; }
|
||||
return 1; }
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
default: return 0; }
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if current execution context is running in user mode
|
||||
*/
|
||||
inline static bool is_user() {
|
||||
return Psr::M::get(Psr::read()) == Psr::M::USER; }
|
||||
static bool is_user() { return Psr::M::get(Psr::read()) == Psr::usr; }
|
||||
|
||||
/**
|
||||
* Invalidate all entries of all instruction caches
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static void invalidate_instr_caches() {
|
||||
asm volatile ("mcr p15, 0, %[rd], c7, c5, 0" :: [rd]"r"(0) : ); }
|
||||
__attribute__((always_inline)) static void invalidate_instr_caches() {
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 0" :: "r" (0) : ); }
|
||||
|
||||
/**
|
||||
* Flush all entries of all data caches
|
||||
@ -588,14 +436,12 @@ class Genode::Arm
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all TLB entries of one address space
|
||||
*
|
||||
* \param pid ID of the targeted address space
|
||||
* Invalidate all TLB entries of the address space named 'pid'
|
||||
*/
|
||||
static void flush_tlb_by_pid(unsigned const pid)
|
||||
{
|
||||
flush_caches();
|
||||
asm volatile ("mcr p15, 0, %[pid], c8, c7, 2" :: [pid]"r"(pid) : );
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 2" :: "r" (pid) : );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -604,41 +450,36 @@ class Genode::Arm
|
||||
static void flush_tlb()
|
||||
{
|
||||
flush_caches();
|
||||
asm volatile ("mcr p15, 0, %[rd], c8, c7, 0" :: [rd]"r"(0) : );
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 0" :: "r" (0) : );
|
||||
}
|
||||
|
||||
static constexpr addr_t line_size = 1 << Board::CACHE_LINE_SIZE_LOG2;
|
||||
static constexpr addr_t line_align_mask = ~(line_size - 1);
|
||||
|
||||
/**
|
||||
* Clean every data-cache entry within a virtual region
|
||||
* Flush data-cache entries for virtual region ['base', 'base + size')
|
||||
*/
|
||||
static void
|
||||
flush_data_caches_by_virt_region(addr_t base, size_t const size)
|
||||
{
|
||||
enum {
|
||||
LINE_SIZE = 1 << Board::CACHE_LINE_SIZE_LOG2,
|
||||
LINE_ALIGNM_MASK = ~(LINE_SIZE - 1),
|
||||
};
|
||||
addr_t const top = base + size;
|
||||
base = base & LINE_ALIGNM_MASK;
|
||||
for (; base < top; base += LINE_SIZE) { Dccmvac::write(base); }
|
||||
base &= line_align_mask;
|
||||
for (; base < top; base += line_size) { Dccmvac::write(base); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate every instruction-cache entry within a virtual region
|
||||
* Bin instr.-cache entries for virtual region ['base', 'base + size')
|
||||
*/
|
||||
static void
|
||||
invalidate_instr_caches_by_virt_region(addr_t base, size_t const size)
|
||||
{
|
||||
enum {
|
||||
LINE_SIZE = 1 << Board::CACHE_LINE_SIZE_LOG2,
|
||||
LINE_ALIGNM_MASK = ~(LINE_SIZE - 1),
|
||||
};
|
||||
addr_t const top = base + size;
|
||||
base = base & LINE_ALIGNM_MASK;
|
||||
for (; base < top; base += LINE_SIZE) { Icimvau::write(base); }
|
||||
base &= line_align_mask;
|
||||
for (; base < top; base += line_size) { Icimvau::write(base); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the processor support multiple cores
|
||||
* Return true if the CPU supports multiple cores
|
||||
*/
|
||||
static bool is_smp() { return PROCESSORS > 1; }
|
||||
};
|
||||
|
@ -29,11 +29,14 @@
|
||||
namespace Genode
|
||||
{
|
||||
/**
|
||||
* Memory region attributes for the translation descriptor 'T'
|
||||
* Commons for all translations
|
||||
*/
|
||||
template <typename T>
|
||||
static typename T::access_t
|
||||
arm_memory_region_attr(Page_flags const & flags);
|
||||
class Translation;
|
||||
|
||||
/**
|
||||
* Second level translation table
|
||||
*/
|
||||
class Page_table;
|
||||
|
||||
/**
|
||||
* First level translation table
|
||||
@ -41,40 +44,42 @@ namespace Genode
|
||||
class Translation_table;
|
||||
}
|
||||
|
||||
class Genode::Translation_table
|
||||
class Genode::Translation
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* Return permission configuration according to given mapping flags
|
||||
*
|
||||
* \param T targeted translation-table-descriptor type
|
||||
* \param flags mapping flags
|
||||
*
|
||||
* \return descriptor value with AP and XN set and the rest left zero
|
||||
* Return TEX value for device-memory translations
|
||||
*/
|
||||
template <typename T>
|
||||
static typename T::access_t
|
||||
access_permission_bits(Page_flags const & flags)
|
||||
{
|
||||
typedef typename T::Xn Xn;
|
||||
typedef typename T::Ap Ap;
|
||||
typedef typename T::access_t access_t;
|
||||
bool const w = flags.writeable;
|
||||
bool const p = flags.privileged;
|
||||
access_t ap;
|
||||
if (w) { if (p) { ap = Ap::bits(0b001); }
|
||||
else { ap = Ap::bits(0b011); }
|
||||
} else { if (p) { ap = Ap::bits(0b101); }
|
||||
else { ap = Ap::bits(0b010); }
|
||||
}
|
||||
return Xn::bits(!flags.executable) | ap;
|
||||
}
|
||||
static constexpr unsigned _device_tex();
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Second level translation table
|
||||
* Return translation according to flags 'f' and phys. address 'pa'
|
||||
*/
|
||||
class Page_table
|
||||
template <typename T> static typename T::access_t
|
||||
_create(Page_flags const & f, addr_t const pa)
|
||||
{
|
||||
typename T::access_t v = T::Pa::masked(pa);
|
||||
T::S::set(v, Cpu::is_smp());
|
||||
T::Ng::set(v, !f.global);
|
||||
T::Xn::set(v, !f.executable);
|
||||
if (f.device) { T::Tex::set(v, _device_tex()); }
|
||||
else {
|
||||
switch (f.cacheable) {
|
||||
case CACHED: T::Tex::set(v, 5);
|
||||
case WRITE_COMBINED: T::B::set(v, 1); break;
|
||||
case UNCACHED: T::Tex::set(v, 1); break; } }
|
||||
if (f.writeable) if (f.privileged) T::Ap::set(v, 1);
|
||||
else T::Ap::set(v, 3);
|
||||
else if (f.privileged) T::Ap::set(v, 5);
|
||||
else T::Ap::set(v, 2);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
class Genode::Page_table
|
||||
{
|
||||
public:
|
||||
|
||||
@ -87,11 +92,8 @@ class Genode::Translation_table
|
||||
/**
|
||||
* Common descriptor structure
|
||||
*/
|
||||
struct Descriptor : Register<32>
|
||||
struct Descriptor : Register<32>, Translation
|
||||
{
|
||||
/**
|
||||
* Descriptor types
|
||||
*/
|
||||
enum Type { FAULT, SMALL_PAGE };
|
||||
|
||||
enum {
|
||||
@ -112,35 +114,23 @@ class Genode::Translation_table
|
||||
access_t const t0 = Type_0::get(v);
|
||||
if (t0 == 0) { return FAULT; }
|
||||
access_t const t1 = Type_1::get(v);
|
||||
if (t1 == 1) return SMALL_PAGE;
|
||||
if (t1 == 1) { return SMALL_PAGE; }
|
||||
return FAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set descriptor type of 'v'
|
||||
* At descriptor value 'v' set type to 't'
|
||||
*/
|
||||
static void type(access_t & v, Type const t)
|
||||
{
|
||||
switch (t) {
|
||||
case FAULT:
|
||||
Type_0::set(v, 0);
|
||||
return;
|
||||
case SMALL_PAGE:
|
||||
Type_1::set(v, 1);
|
||||
return;
|
||||
}
|
||||
case FAULT: Type_0::set(v, 0); return;
|
||||
case SMALL_PAGE: Type_1::set(v, 1); return; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate descriptor 'v'
|
||||
*/
|
||||
static void invalidate(access_t & v) { type(v, FAULT); }
|
||||
|
||||
/**
|
||||
* Return if descriptor 'v' is valid
|
||||
*/
|
||||
static bool valid(access_t & v) {
|
||||
return type(v) != FAULT; }
|
||||
static bool valid(access_t & v) { return type(v) != FAULT; }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -150,27 +140,20 @@ class Genode::Translation_table
|
||||
{
|
||||
struct Xn : Bitfield<0, 1> { }; /* execute never */
|
||||
struct B : Bitfield<2, 1> { }; /* mem region attr. */
|
||||
struct C : Bitfield<3, 1> { }; /* mem region attr. */
|
||||
struct Ap_0 : Bitfield<4, 2> { }; /* access permission */
|
||||
struct Tex : Bitfield<6, 3> { }; /* mem region attr. */
|
||||
struct Ap_1 : Bitfield<9, 1> { }; /* access permission */
|
||||
struct S : Bitfield<10, 1> { }; /* shareable bit */
|
||||
struct Ng : Bitfield<11, 1> { }; /* not global bit */
|
||||
struct Pa : Bitfield<12, 20> { }; /* physical base */
|
||||
|
||||
struct Ap : Bitset_2<Ap_0, Ap_1> { }; /* access permission */
|
||||
|
||||
/**
|
||||
* Compose descriptor value
|
||||
* Return page descriptor for physical address 'pa' and 'flags'
|
||||
*/
|
||||
static access_t create(Page_flags const & flags,
|
||||
addr_t const pa)
|
||||
static access_t create(Page_flags const & flags, addr_t const pa)
|
||||
{
|
||||
access_t v = access_permission_bits<Small_page>(flags);
|
||||
v |= arm_memory_region_attr<Small_page>(flags);
|
||||
v |= Ng::bits(!flags.global);
|
||||
v |= S::bits(Cpu::is_smp());
|
||||
v |= Pa::masked(pa);
|
||||
access_t v = _create<Small_page>(flags, pa);
|
||||
Descriptor::type(v, Descriptor::SMALL_PAGE);
|
||||
return v;
|
||||
}
|
||||
@ -178,11 +161,7 @@ class Genode::Translation_table
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Table payload
|
||||
*
|
||||
* Must be the only member of this class
|
||||
*/
|
||||
/* table payload that must be the only member of this class */
|
||||
Descriptor::access_t _entries[SIZE/sizeof(Descriptor::access_t)];
|
||||
|
||||
enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 };
|
||||
@ -273,15 +252,11 @@ class Genode::Translation_table
|
||||
constexpr size_t sz = Descriptor::VIRT_SIZE;
|
||||
|
||||
for (unsigned i; (size > 0) && _index_by_vo(i, vo);
|
||||
size = (size < sz) ? 0 : size - sz, vo += sz) {
|
||||
|
||||
switch (Descriptor::type(_entries[i])) {
|
||||
|
||||
case Descriptor::SMALL_PAGE:
|
||||
size = (size < sz) ? 0 : size - sz, vo += sz)
|
||||
{
|
||||
switch (Descriptor::type(_entries[i])) {
|
||||
case Descriptor::SMALL_PAGE:
|
||||
Descriptor::invalidate(_entries[i]);
|
||||
}
|
||||
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
@ -292,25 +267,22 @@ class Genode::Translation_table
|
||||
*/
|
||||
bool empty()
|
||||
{
|
||||
for (unsigned i = 0; i <= MAX_INDEX; i++)
|
||||
if (Descriptor::valid(_entries[i])) return false;
|
||||
for (unsigned i = 0; i <= MAX_INDEX; i++) {
|
||||
if (Descriptor::valid(_entries[i])) return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
} __attribute__((aligned(1<<Page_table::ALIGNM_LOG2)));
|
||||
|
||||
|
||||
enum { DOMAIN = 0 };
|
||||
|
||||
class Genode::Translation_table
|
||||
{
|
||||
public:
|
||||
|
||||
enum {
|
||||
SIZE_LOG2 = 14,
|
||||
SIZE = 1 << SIZE_LOG2,
|
||||
ALIGNM_LOG2 = SIZE_LOG2,
|
||||
|
||||
MAX_COSTS_PER_TRANSLATION = sizeof(Page_table),
|
||||
|
||||
MAX_PAGE_SIZE_LOG2 = 20,
|
||||
MIN_PAGE_SIZE_LOG2 = 12,
|
||||
};
|
||||
@ -318,11 +290,8 @@ class Genode::Translation_table
|
||||
/**
|
||||
* A first level translation descriptor
|
||||
*/
|
||||
struct Descriptor : Register<32>
|
||||
struct Descriptor : Register<32>, Translation
|
||||
{
|
||||
/**
|
||||
* Descriptor types
|
||||
*/
|
||||
enum Type { FAULT, PAGE_TABLE, SECTION };
|
||||
|
||||
enum {
|
||||
@ -344,13 +313,9 @@ class Genode::Translation_table
|
||||
{
|
||||
switch (Type_0::get(v)) {
|
||||
case 0: return FAULT;
|
||||
case 1: return PAGE_TABLE;
|
||||
}
|
||||
|
||||
switch (Type_1::get(v)) {
|
||||
case 1: return SECTION;
|
||||
}
|
||||
case 1: return PAGE_TABLE; }
|
||||
|
||||
if (Type_1::get(v) == 1) { return SECTION; }
|
||||
return FAULT;
|
||||
}
|
||||
|
||||
@ -360,26 +325,13 @@ class Genode::Translation_table
|
||||
static void type(access_t & v, Type const t)
|
||||
{
|
||||
switch (t) {
|
||||
case FAULT:
|
||||
Type_0::set(v, 0);
|
||||
return;
|
||||
case PAGE_TABLE:
|
||||
Type_0::set(v, 1);
|
||||
return;
|
||||
case SECTION:
|
||||
Type_1::set(v, 1);
|
||||
return;
|
||||
}
|
||||
case FAULT: Type_0::set(v, 0); return;
|
||||
case PAGE_TABLE: Type_0::set(v, 1); return;
|
||||
case SECTION: Type_1::set(v, 1); return; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate descriptor 'v'
|
||||
*/
|
||||
static void invalidate(access_t & v) { type(v, FAULT); }
|
||||
|
||||
/**
|
||||
* Return if descriptor 'v' is valid
|
||||
*/
|
||||
static bool valid(access_t & v) { return type(v) != FAULT; }
|
||||
|
||||
static inline Type align(addr_t vo, addr_t pa, size_t size)
|
||||
@ -398,12 +350,11 @@ class Genode::Translation_table
|
||||
struct Pa : Bitfield<10, 22> { }; /* physical base */
|
||||
|
||||
/**
|
||||
* Compose descriptor value
|
||||
* Return descriptor value for page table 'pt
|
||||
*/
|
||||
static access_t create(Page_table * const pt)
|
||||
{
|
||||
access_t v = Domain::bits(DOMAIN) |
|
||||
Pa::masked((addr_t)pt);
|
||||
access_t v = Pa::masked((addr_t)pt);
|
||||
Descriptor::type(v, Descriptor::PAGE_TABLE);
|
||||
return v;
|
||||
}
|
||||
@ -415,9 +366,7 @@ class Genode::Translation_table
|
||||
struct Section : Descriptor
|
||||
{
|
||||
struct B : Bitfield<2, 1> { }; /* mem. region attr. */
|
||||
struct C : Bitfield<3, 1> { }; /* mem. region attr. */
|
||||
struct Xn : Bitfield<4, 1> { }; /* execute never bit */
|
||||
struct Domain : Bitfield<5, 4> { }; /* domain */
|
||||
struct Ap_0 : Bitfield<10, 2> { }; /* access permission */
|
||||
struct Tex : Bitfield<12, 3> { }; /* mem. region attr. */
|
||||
struct Ap_1 : Bitfield<15, 1> { }; /* access permission */
|
||||
@ -427,17 +376,11 @@ class Genode::Translation_table
|
||||
struct Ap : Bitset_2<Ap_0, Ap_1> { }; /* access permission */
|
||||
|
||||
/**
|
||||
* Compose descriptor value
|
||||
* Return section descriptor for physical address 'pa' and 'flags'
|
||||
*/
|
||||
static access_t create(Page_flags const & flags,
|
||||
addr_t const pa)
|
||||
static access_t create(Page_flags const & flags, addr_t const pa)
|
||||
{
|
||||
access_t v = access_permission_bits<Section>(flags);
|
||||
v |= arm_memory_region_attr<Section>(flags);
|
||||
v |= Domain::bits(DOMAIN);
|
||||
v |= S::bits(Cpu::is_smp());
|
||||
v |= Ng::bits(!flags.global);
|
||||
v |= Pa::masked(pa);
|
||||
access_t v = _create<Section>(flags, pa);
|
||||
Descriptor::type(v, Descriptor::SECTION);
|
||||
return v;
|
||||
}
|
||||
@ -451,15 +394,9 @@ class Genode::Translation_table
|
||||
enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 };
|
||||
|
||||
/**
|
||||
* Get entry index by virtual offset
|
||||
* Try to get entry index in 'i' for virtual offset 'vo!
|
||||
*
|
||||
* \param i is overridden with the resulting index
|
||||
* \param vo offset within the virtual region represented
|
||||
* by this table
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval <0 if virtual offset couldn't be resolved,
|
||||
* in this case 'i' reside invalid
|
||||
* \return wether it was successful
|
||||
*/
|
||||
bool _index_by_vo(unsigned & i, addr_t const vo) const
|
||||
{
|
||||
@ -478,12 +415,9 @@ class Genode::Translation_table
|
||||
* \param flags mapping flags
|
||||
* \param slab second level page slab allocator
|
||||
*/
|
||||
void _insert_second_level(unsigned i,
|
||||
addr_t const vo,
|
||||
addr_t const pa,
|
||||
size_t const size,
|
||||
Page_flags const & flags,
|
||||
Page_slab * slab)
|
||||
void _insert_second_level(unsigned i, addr_t const vo, addr_t const pa,
|
||||
size_t const size, Page_flags const & flags,
|
||||
Page_slab * const slab)
|
||||
{
|
||||
Page_table * pt = 0;
|
||||
switch (Descriptor::type(_entries[i])) {
|
||||
@ -499,13 +433,13 @@ class Genode::Translation_table
|
||||
_entries[i] = Page_table_descriptor::create(pt_phys);
|
||||
|
||||
/* some processors need to act on changed translations */
|
||||
Cpu::translation_added((addr_t)&_entries[i],
|
||||
sizeof(Descriptor::access_t));
|
||||
size_t const dsize = sizeof(Descriptor::access_t);
|
||||
Cpu::translation_added((addr_t)&_entries[i], dsize);
|
||||
}
|
||||
|
||||
case Descriptor::PAGE_TABLE:
|
||||
{
|
||||
/* use allocator to retrieve virtual address of page table */
|
||||
/* use allocator to retrieve virtual addr. of page table */
|
||||
void * pt_phys = (void*)
|
||||
Page_table_descriptor::Pa::masked(_entries[i]);
|
||||
pt = (Page_table *) slab->virt_addr(pt_phys);
|
||||
@ -514,11 +448,11 @@ class Genode::Translation_table
|
||||
}
|
||||
|
||||
default: assert(0);
|
||||
};
|
||||
}
|
||||
|
||||
/* insert translation */
|
||||
pt->insert_translation(vo - Section::Pa::masked(vo),
|
||||
pa, size, flags);
|
||||
addr_t const pt_vo = vo - Section::Pa::masked(vo);
|
||||
pt->insert_translation(pt_vo, pa, size, flags);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -542,26 +476,21 @@ class Genode::Translation_table
|
||||
*/
|
||||
static addr_t max_virt_offset()
|
||||
{
|
||||
return (MAX_INDEX << Descriptor::VIRT_SIZE_LOG2)
|
||||
+ (Descriptor::VIRT_SIZE - 1);
|
||||
constexpr addr_t base = MAX_INDEX << Descriptor::VIRT_SIZE_LOG2;
|
||||
return base + (Descriptor::VIRT_SIZE - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert translations into this table
|
||||
*
|
||||
* \param vo offset of the virtual region represented
|
||||
* by the translation within the virtual
|
||||
* region represented by this table
|
||||
* \param pa base of the physical backing store
|
||||
* \param size size of the translated region
|
||||
* \param flags mapping flags
|
||||
* \param slab second level page slab allocator
|
||||
* \param vo offset of virt. transl. region in virt. table region
|
||||
* \param pa base of physical backing store
|
||||
* \param size size of translated region
|
||||
* \param f mapping flags
|
||||
* \param s second level page slab allocator
|
||||
*/
|
||||
void insert_translation(addr_t vo,
|
||||
addr_t pa,
|
||||
size_t size,
|
||||
Page_flags const & flags,
|
||||
Page_slab * slab)
|
||||
void insert_translation(addr_t vo, addr_t pa, size_t size,
|
||||
Page_flags const & f, Page_slab * const s)
|
||||
{
|
||||
/* check sanity */
|
||||
assert(!(vo & Page_table::Descriptor::VIRT_OFFSET_MASK) &&
|
||||
@ -569,8 +498,8 @@ class Genode::Translation_table
|
||||
|
||||
for (unsigned i; (size > 0) && _index_by_vo (i, vo);) {
|
||||
|
||||
addr_t end = (vo + Descriptor::VIRT_SIZE)
|
||||
& Descriptor::VIRT_BASE_MASK;
|
||||
addr_t const ve = (vo + Descriptor::VIRT_SIZE);
|
||||
addr_t const end = ve & Descriptor::VIRT_BASE_MASK;
|
||||
|
||||
/* decide granularity of entry that can be inserted */
|
||||
switch (Descriptor::align(vo, pa, size)) {
|
||||
@ -578,29 +507,25 @@ class Genode::Translation_table
|
||||
case Descriptor::SECTION:
|
||||
{
|
||||
/* compose new entry */
|
||||
Section::access_t const e = Section::create(flags, pa);
|
||||
|
||||
/* check if it is a good idea to override the entry */
|
||||
assert(!Descriptor::valid(_entries[i]) ||
|
||||
_entries[i] == e);
|
||||
Section::access_t const e = Section::create(f, pa);
|
||||
|
||||
/* override entry */
|
||||
if (_entries[i] == e) { break; }
|
||||
assert(!Descriptor::valid(_entries[i]));
|
||||
_entries[i] = e;
|
||||
|
||||
/* some CPUs need to act on changed translations */
|
||||
Cpu::translation_added((addr_t)&_entries[i],
|
||||
sizeof(Descriptor::access_t));
|
||||
constexpr size_t ds = sizeof(Descriptor::access_t);
|
||||
Cpu::translation_added((addr_t)&_entries[i], ds);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
_insert_second_level(i, vo, pa, min(size, end-vo), flags, slab);
|
||||
}
|
||||
_insert_second_level(i, vo, pa, min(size, end - vo), f, s);
|
||||
};
|
||||
|
||||
/* check whether we wrap */
|
||||
if (end < vo) return;
|
||||
if (end < vo) { return; }
|
||||
|
||||
size_t sz = end - vo;
|
||||
size = (size > sz) ? size - sz : 0;
|
||||
@ -623,8 +548,8 @@ class Genode::Translation_table
|
||||
|
||||
for (unsigned i; (size > 0) && _index_by_vo(i, vo);) {
|
||||
|
||||
addr_t end = (vo + Descriptor::VIRT_SIZE)
|
||||
& Descriptor::VIRT_BASE_MASK;
|
||||
constexpr addr_t dbm = Descriptor::VIRT_BASE_MASK;
|
||||
addr_t const end = (vo + Descriptor::VIRT_SIZE) & dbm;
|
||||
|
||||
switch (Descriptor::type(_entries[i])) {
|
||||
|
||||
@ -647,11 +572,7 @@ class Genode::Translation_table
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Descriptor::invalidate(_entries[i]);
|
||||
}
|
||||
}
|
||||
default: Descriptor::invalidate(_entries[i]); }
|
||||
|
||||
/* check whether we wrap */
|
||||
if (end < vo) return;
|
||||
|
@ -39,79 +39,55 @@ class Genode::Arm_gic_distributor : public Mmio
|
||||
{
|
||||
public:
|
||||
|
||||
enum { NR_OF_IRQ = 1024 };
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Arm_gic_distributor(addr_t const base) : Mmio(base) { }
|
||||
static constexpr unsigned nr_of_irq = 1024;
|
||||
|
||||
/**
|
||||
* Control register
|
||||
*/
|
||||
struct Ctlr : Register<0x000, 32>
|
||||
{
|
||||
struct Enable : Bitfield<0,1> { };
|
||||
};
|
||||
struct Ctlr : Register<0x000, 32> {
|
||||
struct Enable : Bitfield<0,1> { }; };
|
||||
|
||||
/**
|
||||
* Controller type register
|
||||
*/
|
||||
struct Typer : Register<0x004, 32>
|
||||
{
|
||||
struct It_lines_number : Bitfield<0,5> { };
|
||||
struct Cpu_number : Bitfield<5,3> { };
|
||||
};
|
||||
struct Typer : Register<0x004, 32> {
|
||||
struct It_lines_number : Bitfield<0,5> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt group register
|
||||
*/
|
||||
struct Igroupr : Register_array<0x80, 32, NR_OF_IRQ, 1>
|
||||
{
|
||||
struct Group_status : Bitfield<0, 1> { };
|
||||
};
|
||||
struct Igroupr : Register_array<0x80, 32, nr_of_irq, 1> {
|
||||
struct Group_status : Bitfield<0, 1> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt set enable registers
|
||||
*/
|
||||
struct Isenabler : Register_array<0x100, 32, NR_OF_IRQ, 1, true>
|
||||
{
|
||||
struct Set_enable : Bitfield<0, 1> { };
|
||||
};
|
||||
struct Isenabler : Register_array<0x100, 32, nr_of_irq, 1, true> {
|
||||
struct Set_enable : Bitfield<0, 1> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt clear enable registers
|
||||
*/
|
||||
struct Icenabler : Register_array<0x180, 32, NR_OF_IRQ, 1, true>
|
||||
{
|
||||
struct Clear_enable : Bitfield<0, 1> { };
|
||||
};
|
||||
struct Icenabler : Register_array<0x180, 32, nr_of_irq, 1, true> {
|
||||
struct Clear_enable : Bitfield<0, 1> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt priority level registers
|
||||
*/
|
||||
struct Ipriorityr : Register_array<0x400, 32, NR_OF_IRQ, 8>
|
||||
{
|
||||
enum { GET_MIN = 0xff };
|
||||
|
||||
struct Priority : Bitfield<0, 8> { };
|
||||
};
|
||||
struct Ipriorityr : Register_array<0x400, 32, nr_of_irq, 8> {
|
||||
struct Priority : Bitfield<0, 8> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt processor target registers
|
||||
*/
|
||||
struct Itargetsr : Register_array<0x800, 32, NR_OF_IRQ, 8>
|
||||
{
|
||||
struct Cpu_targets : Bitfield<0, 8> { };
|
||||
};
|
||||
struct Itargetsr : Register_array<0x800, 32, nr_of_irq, 8> {
|
||||
struct Cpu_targets : Bitfield<0, 8> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt configuration registers
|
||||
*/
|
||||
struct Icfgr : Register_array<0xc00, 32, NR_OF_IRQ, 2>
|
||||
{
|
||||
struct Edge_triggered : Bitfield<1, 1> { };
|
||||
};
|
||||
struct Icfgr : Register_array<0xc00, 32, nr_of_irq, 2> {
|
||||
struct Edge_triggered : Bitfield<1, 1> { }; };
|
||||
|
||||
/**
|
||||
* Software generated interrupt register
|
||||
@ -123,27 +99,27 @@ class Genode::Arm_gic_distributor : public Mmio
|
||||
};
|
||||
|
||||
/**
|
||||
* Minimum supported interrupt priority
|
||||
* Constructor
|
||||
*/
|
||||
Ipriorityr::access_t min_priority()
|
||||
Arm_gic_distributor(addr_t const base) : Mmio(base) { }
|
||||
|
||||
/**
|
||||
* Return minimum IRQ priority
|
||||
*/
|
||||
unsigned min_priority()
|
||||
{
|
||||
write<Ipriorityr::Priority>(Ipriorityr::GET_MIN, 0);
|
||||
write<Ipriorityr::Priority>(~0, 0);
|
||||
return read<Ipriorityr::Priority>(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum supported interrupt priority
|
||||
* Return highest IRQ number
|
||||
*/
|
||||
Ipriorityr::access_t max_priority() { return 0; }
|
||||
|
||||
/**
|
||||
* ID of the maximum supported interrupt
|
||||
*/
|
||||
Typer::access_t max_interrupt()
|
||||
unsigned max_irq()
|
||||
{
|
||||
enum { LINE_WIDTH_LOG2 = 5 };
|
||||
Typer::access_t lnr = read<Typer::It_lines_number>();
|
||||
return ((lnr + 1) << LINE_WIDTH_LOG2) - 1;
|
||||
constexpr unsigned line_width_log2 = 5;
|
||||
Typer::access_t const lnr = read<Typer::It_lines_number>();
|
||||
return ((lnr + 1) << line_width_log2) - 1;
|
||||
}
|
||||
};
|
||||
|
||||
@ -151,20 +127,12 @@ class Genode::Arm_gic_cpu_interface : public Mmio
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Arm_gic_cpu_interface(addr_t const base) : Mmio(base) { }
|
||||
|
||||
/**
|
||||
* Control register
|
||||
*/
|
||||
struct Ctlr : Register<0x00, 32>
|
||||
{
|
||||
/* Without security extension */
|
||||
struct Enable : Bitfield<0,1> { };
|
||||
|
||||
/* In a secure world */
|
||||
struct Enable_grp0 : Bitfield<0,1> { };
|
||||
struct Enable_grp1 : Bitfield<1,1> { };
|
||||
struct Fiq_en : Bitfield<3,1> { };
|
||||
@ -173,74 +141,66 @@ class Genode::Arm_gic_cpu_interface : public Mmio
|
||||
/**
|
||||
* Priority mask register
|
||||
*/
|
||||
struct Pmr : Register<0x04, 32>
|
||||
{
|
||||
struct Priority : Bitfield<0,8> { };
|
||||
};
|
||||
struct Pmr : Register<0x04, 32> {
|
||||
struct Priority : Bitfield<0,8> { }; };
|
||||
|
||||
/**
|
||||
* Binary point register
|
||||
*/
|
||||
struct Bpr : Register<0x08, 32>
|
||||
{
|
||||
enum { NO_PREEMPTION = 7 };
|
||||
|
||||
struct Binary_point : Bitfield<0,3> { };
|
||||
};
|
||||
struct Bpr : Register<0x08, 32> {
|
||||
struct Binary_point : Bitfield<0,3> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt acknowledge register
|
||||
*/
|
||||
struct Iar : Register<0x0c, 32, true>
|
||||
{
|
||||
struct Irq_id : Bitfield<0,10> { };
|
||||
};
|
||||
struct Iar : Register<0x0c, 32, true> {
|
||||
struct Irq_id : Bitfield<0,10> { }; };
|
||||
|
||||
/**
|
||||
* End of interrupt register
|
||||
*/
|
||||
struct Eoir : Register<0x10, 32, true>
|
||||
{
|
||||
struct Irq_id : Bitfield<0,10> { };
|
||||
struct Cpu_id : Bitfield<10,3> { };
|
||||
};
|
||||
struct Eoir : Register<0x10, 32, true> {
|
||||
struct Irq_id : Bitfield<0,10> { }; };
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Arm_gic_cpu_interface(addr_t const base) : Mmio(base) { }
|
||||
};
|
||||
|
||||
class Genode::Arm_gic
|
||||
{
|
||||
protected:
|
||||
|
||||
enum {
|
||||
MIN_SPI = 32,
|
||||
SPURIOUS_ID = 1023,
|
||||
};
|
||||
|
||||
typedef Arm_gic_cpu_interface Cpui;
|
||||
typedef Arm_gic_distributor Distr;
|
||||
|
||||
static constexpr unsigned min_spi = 32;
|
||||
static constexpr unsigned spurious_id = 1023;
|
||||
|
||||
Distr _distr;
|
||||
Cpui _cpui;
|
||||
unsigned const _max_interrupt;
|
||||
unsigned const _max_irq;
|
||||
unsigned _last_request;
|
||||
|
||||
/**
|
||||
* Return inter-processor interrupt of a specific processor
|
||||
*
|
||||
* \param processor_id kernel name of targeted processor
|
||||
* Return inter-processor IRQ of the CPU with kernel name 'cpu_id'
|
||||
*/
|
||||
unsigned _ip_interrupt(unsigned const processor_id) const
|
||||
{
|
||||
return processor_id + 1;
|
||||
}
|
||||
unsigned _ipi(unsigned const cpu_id) const { return cpu_id + 1; }
|
||||
|
||||
/**
|
||||
* Platform specific initialization
|
||||
*/
|
||||
void _init();
|
||||
|
||||
/**
|
||||
* Return wether kernel name 'irq_id' addresses a valid IRQ
|
||||
*/
|
||||
bool _valid(unsigned const irq_id) const { return irq_id <= _max_irq; }
|
||||
|
||||
public:
|
||||
|
||||
enum { NR_OF_IRQ = Distr::NR_OF_IRQ };
|
||||
enum { NR_OF_IRQ = Distr::nr_of_irq };
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -248,124 +208,83 @@ class Genode::Arm_gic
|
||||
Arm_gic(addr_t const distr_base, addr_t const cpu_base)
|
||||
:
|
||||
_distr(distr_base), _cpui(cpu_base),
|
||||
_max_interrupt(_distr.max_interrupt()),
|
||||
_last_request(SPURIOUS_ID)
|
||||
{
|
||||
_init();
|
||||
}
|
||||
_max_irq(_distr.max_irq()),
|
||||
_last_request(spurious_id) { _init(); }
|
||||
|
||||
/**
|
||||
* Initialize processor local interface of the controller
|
||||
* Initialize CPU local interface of the controller
|
||||
*/
|
||||
void init_processor_local()
|
||||
{
|
||||
/* disable the priority filter */
|
||||
_cpui.write<Cpui::Pmr::Priority>(_distr.min_priority());
|
||||
|
||||
/* disable preemption of interrupt handling by interrupts */
|
||||
_cpui.write<Cpui::Bpr::Binary_point>(Cpui::Bpr::NO_PREEMPTION);
|
||||
/* disable preemption of IRQ handling by other IRQs */
|
||||
_cpui.write<Cpui::Bpr::Binary_point>(~0);
|
||||
|
||||
/* enable device */
|
||||
_cpui.write<Cpui::Ctlr::Enable>(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the last interrupt request
|
||||
* Try to take an IRQ and return wether it was successful
|
||||
*
|
||||
* \return True if the request with ID 'i' is treated as accepted
|
||||
* by the CPU and awaits an subsequently 'finish_request'
|
||||
* call. Otherwise this returns false and the value of 'i'
|
||||
* remains useless.
|
||||
* \param irq_id contains kernel name of taken IRQ on success
|
||||
*/
|
||||
bool take_request(unsigned & i)
|
||||
bool take_request(unsigned & irq_id)
|
||||
{
|
||||
_last_request = _cpui.read<Cpui::Iar::Irq_id>();
|
||||
i = _last_request;
|
||||
return valid(i);
|
||||
irq_id = _last_request;
|
||||
return _valid(irq_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the last request that was taken via 'take_request'
|
||||
* End the last taken IRQ
|
||||
*/
|
||||
void finish_request()
|
||||
{
|
||||
if (!valid(_last_request)) return;
|
||||
_cpui.write<Cpui::Eoir>(Cpui::Eoir::Irq_id::bits(_last_request) |
|
||||
Cpui::Eoir::Cpu_id::bits(0) );
|
||||
_last_request = SPURIOUS_ID;
|
||||
if (!_valid(_last_request)) { return; }
|
||||
_cpui.write<Cpui::Eoir::Irq_id>(_last_request);
|
||||
_last_request = spurious_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if 'i' is a valid interrupt request ID at the device
|
||||
*/
|
||||
bool valid(unsigned const i) const { return i <= _max_interrupt; }
|
||||
|
||||
/**
|
||||
* Unmask all interrupts
|
||||
*/
|
||||
void unmask()
|
||||
{
|
||||
for (unsigned i=0; i <= _max_interrupt; i++) {
|
||||
_distr.write<Distr::Isenabler::Set_enable>(1, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmask interrupt and assign it to a specific processor
|
||||
* Unmask IRQ and assign it to one CPU
|
||||
*
|
||||
* \param interrupt_id kernel name of targeted interrupt
|
||||
* \param processor_id kernel name of targeted processor
|
||||
* \param irq_id kernel name of targeted IRQ
|
||||
* \param cpu_id kernel name of targeted CPU
|
||||
*/
|
||||
void unmask(unsigned const interrupt_id, unsigned const processor_id)
|
||||
void unmask(unsigned const irq_id, unsigned const cpu_id)
|
||||
{
|
||||
unsigned const targets = 1 << processor_id;
|
||||
_distr.write<Distr::Itargetsr::Cpu_targets>(targets, interrupt_id);
|
||||
_distr.write<Distr::Isenabler::Set_enable>(1, interrupt_id);
|
||||
unsigned const targets = 1 << cpu_id;
|
||||
_distr.write<Distr::Itargetsr::Cpu_targets>(targets, irq_id);
|
||||
_distr.write<Distr::Isenabler::Set_enable>(1, irq_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mask all interrupts
|
||||
* Mask IRQ with kernel name 'irq_id'
|
||||
*/
|
||||
void mask()
|
||||
{
|
||||
for (unsigned i=0; i <= _max_interrupt; i++) {
|
||||
_distr.write<Distr::Icenabler::Clear_enable>(1, i);
|
||||
}
|
||||
}
|
||||
void mask(unsigned const irq_id) {
|
||||
_distr.write<Distr::Icenabler::Clear_enable>(1, irq_id); }
|
||||
|
||||
/**
|
||||
* Mask specific interrupt
|
||||
* Return wether an IRQ is inter-processor IRQ of a CPU
|
||||
*
|
||||
* \param interrupt_id kernel name of targeted interrupt
|
||||
* \param irq_id kernel name of the IRQ
|
||||
* \param cpu_id kernel name of the CPU
|
||||
*/
|
||||
void mask(unsigned const interrupt_id)
|
||||
{
|
||||
_distr.write<Distr::Icenabler::Clear_enable>(1, interrupt_id);
|
||||
}
|
||||
bool is_ip_interrupt(unsigned const irq_id, unsigned const cpu_id) {
|
||||
return irq_id == _ipi(cpu_id); }
|
||||
|
||||
/**
|
||||
* Wether an interrupt is inter-processor interrupt of a processor
|
||||
*
|
||||
* \param interrupt_id kernel name of the interrupt
|
||||
* \param processor_id kernel name of the processor
|
||||
* Raise inter-processor IRQ of the CPU with kernel name 'cpu_id'
|
||||
*/
|
||||
bool is_ip_interrupt(unsigned const interrupt_id,
|
||||
unsigned const processor_id)
|
||||
{
|
||||
return interrupt_id == _ip_interrupt(processor_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the inter-processor interrupt of a processor
|
||||
*
|
||||
* \param processor_id kernel name of the processor
|
||||
*/
|
||||
void trigger_ip_interrupt(unsigned const processor_id)
|
||||
void trigger_ip_interrupt(unsigned const cpu_id)
|
||||
{
|
||||
typedef Distr::Sgir Sgir;
|
||||
Sgir::access_t sgir = 0;
|
||||
Sgir::Sgi_int_id::set(sgir, _ip_interrupt(processor_id));
|
||||
Sgir::Cpu_target_list::set(sgir, 1 << processor_id);
|
||||
Sgir::Sgi_int_id::set(sgir, _ipi(cpu_id));
|
||||
Sgir::Cpu_target_list::set(sgir, 1 << cpu_id);
|
||||
_distr.write<Sgir>(sgir);
|
||||
}
|
||||
};
|
||||
|
@ -146,7 +146,7 @@ class Genode::Cpu : public Arm
|
||||
Cidr::write(process_id);
|
||||
Dacr::write(Dacr::init_virt_kernel());
|
||||
Ttbr0::write(Ttbr0::init(table));
|
||||
Ttbcr::write(Ttbcr::init_virt_kernel());
|
||||
Ttbcr::write(0);
|
||||
Sctlr::write(Sctlr::init_virt_kernel());
|
||||
}
|
||||
|
||||
|
@ -18,21 +18,6 @@
|
||||
/* core includes */
|
||||
#include <spec/arm/short_translation_table.h>
|
||||
|
||||
template <typename T>
|
||||
static typename T::access_t
|
||||
Genode::arm_memory_region_attr(Page_flags const & flags)
|
||||
{
|
||||
typedef typename T::Tex Tex;
|
||||
typedef typename T::C C;
|
||||
typedef typename T::B B;
|
||||
if (flags.device) { return 0; }
|
||||
|
||||
switch (flags.cacheable) {
|
||||
case CACHED: return Tex::bits(5) | B::bits(1);
|
||||
case WRITE_COMBINED: return B::bits(1);
|
||||
case UNCACHED: return Tex::bits(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
constexpr unsigned Genode::Translation::_device_tex() { return 0; }
|
||||
|
||||
#endif /* _TRANSLATION_TABLE_H_ */
|
||||
|
@ -166,33 +166,10 @@ class Genode::Arm_v7 : public Arm
|
||||
*/
|
||||
struct Nsacr : Register<32>
|
||||
{
|
||||
/************************************************
|
||||
** Coprocessor 0-13 non-secure acccess enable **
|
||||
************************************************/
|
||||
|
||||
struct Cpnsae10 : Bitfield<10, 1> { };
|
||||
struct Cpnsae11 : Bitfield<11, 1> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Translation table base control register
|
||||
*/
|
||||
struct Ttbcr : Arm::Ttbcr
|
||||
{
|
||||
struct Pd0 : Bitfield<4,1> { }; /* disable walk for TTBR0 */
|
||||
struct Pd1 : Bitfield<5,1> { }; /* disable walk for TTBR1 */
|
||||
|
||||
/**
|
||||
* Value for the switch to virtual mode in kernel
|
||||
*/
|
||||
static access_t init_virt_kernel()
|
||||
{
|
||||
return Arm::Ttbcr::init_virt_kernel() |
|
||||
Pd0::bits(0) |
|
||||
Pd1::bits(0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* System control register
|
||||
*/
|
||||
@ -252,9 +229,7 @@ class Genode::Arm_v7 : public Arm
|
||||
struct Irgn : Bitset_2<Irgn_0, Irgn_1> { }; /* inner cache attr */
|
||||
|
||||
/**
|
||||
* Return initialized value
|
||||
*
|
||||
* \param table base of targeted translation table
|
||||
* Return value initialized with translation table 'table'
|
||||
*/
|
||||
static access_t init(addr_t const table)
|
||||
{
|
||||
@ -283,7 +258,7 @@ class Genode::Arm_v7 : public Arm
|
||||
Cidr::write(process_id);
|
||||
Dacr::write(Dacr::init_virt_kernel());
|
||||
Ttbr0::write(Ttbr0::init(table));
|
||||
Ttbcr::write(Ttbcr::init_virt_kernel());
|
||||
Ttbcr::write(0);
|
||||
Sctlr::write(Sctlr::init_virt_kernel());
|
||||
inval_branch_predicts();
|
||||
}
|
||||
@ -317,32 +292,20 @@ class Genode::Arm_v7 : public Arm
|
||||
******************************/
|
||||
|
||||
/**
|
||||
* Set the exception-vector's base-address for the monitor mode
|
||||
* software stack.
|
||||
*
|
||||
* \param addr address of the exception vector's base
|
||||
* Set exception-vector's address for monitor mode to 'a'
|
||||
*/
|
||||
static inline void mon_exception_entry_at(addr_t const addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %[rd], c12, c0, 1" : : [rd] "r" (addr));
|
||||
}
|
||||
static void mon_exception_entry_at(addr_t const a) {
|
||||
asm volatile ("mcr p15, 0, %[rd], c12, c0, 1" : : [rd] "r" (a)); }
|
||||
|
||||
/**
|
||||
* Enable access of co-processors cp10 and cp11 from non-secure mode.
|
||||
*/
|
||||
static inline void allow_coprocessor_nonsecure()
|
||||
{
|
||||
Nsacr::access_t rd = Nsacr::Cpnsae10::bits(1) |
|
||||
Nsacr::Cpnsae11::bits(1);
|
||||
asm volatile ("mcr p15, 0, %[rd], c1, c1, 2" : : [rd] "r" (rd));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all predictions about the future control-flow
|
||||
*/
|
||||
static void invalidate_control_flow_predictions()
|
||||
{
|
||||
asm volatile ("mcr p15, 0, r0, c7, c5, 6");
|
||||
Nsacr::access_t v = 0;
|
||||
Nsacr::Cpnsae10::set(v, 1);
|
||||
Nsacr::Cpnsae11::set(v, 1);
|
||||
asm volatile ("mcr p15, 0, %[v], c1, c1, 2" : : [v] "r" (v));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -351,18 +314,15 @@ class Genode::Arm_v7 : public Arm
|
||||
static void data_synchronization_barrier() { asm volatile ("dsb"); }
|
||||
|
||||
/**
|
||||
* Enable secondary processors that loop on wait-for-event
|
||||
*
|
||||
* \param ip initial instruction pointer for secondary processors
|
||||
* Enable secondary processors with instr. pointer 'ip'
|
||||
*/
|
||||
static void start_secondary_processors(void * const ip)
|
||||
{
|
||||
if (is_smp()) {
|
||||
if (!is_smp()) { return; }
|
||||
Board::secondary_processors_ip(ip);
|
||||
data_synchronization_barrier();
|
||||
asm volatile ("sev\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next interrupt as cheap as possible
|
||||
@ -391,18 +351,13 @@ void Genode::Arm::invalidate_data_caches()
|
||||
}
|
||||
|
||||
|
||||
Genode::Arm::Psr::access_t
|
||||
Genode::Arm::Psr::init_user_with_trustzone()
|
||||
Genode::Arm::Psr::access_t Genode::Arm::Psr::init_user_with_trustzone()
|
||||
{
|
||||
return M::bits(M::USER) |
|
||||
T::bits(T::ARM) |
|
||||
F::bits(0) |
|
||||
I::bits(1) |
|
||||
A::bits(1) |
|
||||
E::bits(E::LITTLE) |
|
||||
J::bits(J::ARM);
|
||||
access_t v = 0;
|
||||
M::set(v, usr);
|
||||
I::set(v, 1);
|
||||
A::set(v, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _SPEC__ARM_V7__CPU_SUPPORT_H_ */
|
||||
|
||||
|
@ -18,21 +18,6 @@
|
||||
/* core includes */
|
||||
#include <spec/arm/short_translation_table.h>
|
||||
|
||||
template <typename T>
|
||||
static typename T::access_t
|
||||
Genode::arm_memory_region_attr(Page_flags const & flags)
|
||||
{
|
||||
typedef typename T::Tex Tex;
|
||||
typedef typename T::C C;
|
||||
typedef typename T::B B;
|
||||
if (flags.device) { return Tex::bits(2); }
|
||||
|
||||
switch (flags.cacheable) {
|
||||
case CACHED: return Tex::bits(5) | B::bits(1);
|
||||
case WRITE_COMBINED: return B::bits(1);
|
||||
case UNCACHED: return Tex::bits(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
constexpr unsigned Genode::Translation::_device_tex() { return 2; }
|
||||
|
||||
#endif /* _TRANSLATION_TABLE_H_ */
|
||||
|
@ -24,91 +24,25 @@ namespace Genode
|
||||
|
||||
class Genode::Pic : public Mmio
|
||||
{
|
||||
/**
|
||||
* Interrupt control register
|
||||
*/
|
||||
struct Intcntl : Register<0x0, 32>
|
||||
{
|
||||
struct Nm : Bitfield<18,1> /* IRQ mode */
|
||||
{
|
||||
enum { SW_CONTROL = 0 };
|
||||
};
|
||||
private:
|
||||
|
||||
struct Fiad : Bitfield<19,1> { }; /* FIQ rises prio in arbiter */
|
||||
struct Niad : Bitfield<20,1> { }; /* IRQ rises prio in arbiter */
|
||||
struct Fidis : Bitfield<21,1> { }; /* FIQ disable */
|
||||
struct Nidis : Bitfield<22,1> { }; /* IRQ disable */
|
||||
struct Abfen : Bitfield<24,1> { }; /* if ABFLAG is sticky */
|
||||
struct Abflag : Bitfield<25,1> { }; /* rise prio in bus arbiter */
|
||||
|
||||
static access_t init_value()
|
||||
{
|
||||
return Nm::bits(Nm::SW_CONTROL) |
|
||||
Fiad::bits(0) |
|
||||
Niad::bits(0) |
|
||||
Fidis::bits(0) |
|
||||
Nidis::bits(0) |
|
||||
Abfen::bits(0) |
|
||||
Abflag::bits(0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Normal interrupt mask register
|
||||
*/
|
||||
struct Nimask : Register<0x4, 32>
|
||||
{
|
||||
enum { NONE_MASKED = ~0 };
|
||||
};
|
||||
|
||||
/**
|
||||
* Interrupt enable number register
|
||||
*/
|
||||
struct Intennum : Register<0x8, 32>
|
||||
{
|
||||
struct Enable : Bitfield<0,6> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Interrupt disable number register
|
||||
*/
|
||||
struct Intdisnum : Register<0xc, 32>
|
||||
{
|
||||
struct Disable : Bitfield<0,6> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Interrupt enable register
|
||||
*/
|
||||
struct Intenableh : Register<0x10, 32> { };
|
||||
struct Intenablel : Register<0x14, 32> { };
|
||||
|
||||
/**
|
||||
* Interrupt type register
|
||||
*/
|
||||
struct Inttype { enum { ALL_IRQS = 0 }; };
|
||||
struct Inttypeh : Register<0x18, 32> { };
|
||||
struct Inttypel : Register<0x1c, 32> { };
|
||||
struct Intcntl : Register<0x0, 32> { }; /* IRQ control register */
|
||||
struct Nimask : Register<0x4, 32> { }; /* normal IRQ mask reg. */
|
||||
struct Intennum : Register<0x8, 32> { }; /* IRQ enable nr. reg. */
|
||||
struct Intdisnum : Register<0xc, 32> { }; /* IRQ disable nr. reg. */
|
||||
struct Intenableh : Register<0x10, 32> { }; /* IRQ enable register */
|
||||
struct Intenablel : Register<0x14, 32> { }; /* IRQ enable register */
|
||||
struct Inttypeh : Register<0x18, 32> { }; /* IRQ type register */
|
||||
struct Inttypel : Register<0x1c, 32> { }; /* IRQ type register */
|
||||
struct Intsrch : Register<0x48, 32> { }; /* IRQ source register */
|
||||
struct Intsrcl : Register<0x4c, 32> { }; /* IRQ source register */
|
||||
struct Nipndh : Register<0x58, 32> { }; /* normal IRQ pending */
|
||||
struct Nipndl : Register<0x5c, 32> { }; /* normal IRQ pending */
|
||||
|
||||
/**
|
||||
* Normal interrupt priority registers
|
||||
*/
|
||||
struct Nipriority : Register_array<0x20, 32, 8, 32>
|
||||
{
|
||||
enum { ALL_LOWEST = 0 };
|
||||
};
|
||||
|
||||
/**
|
||||
* Interrupt source registers
|
||||
*/
|
||||
struct Intsrch : Register<0x48, 32> { };
|
||||
struct Intsrcl : Register<0x4c, 32> { };
|
||||
|
||||
/**
|
||||
* Normal interrupt pending registers
|
||||
*/
|
||||
struct Nipndh : Register<0x58, 32> { };
|
||||
struct Nipndl : Register<0x5c, 32> { };
|
||||
struct Nipriority : Register_array<0x20, 32, 8, 32> { };
|
||||
|
||||
/**
|
||||
* Normal interrupt vector and status register
|
||||
@ -118,95 +52,62 @@ class Genode::Pic : public Mmio
|
||||
struct Nvector : Bitfield<16, 16> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate request number 'i'
|
||||
*/
|
||||
bool _valid(unsigned const i) const { return i < NR_OF_IRQ; }
|
||||
|
||||
public:
|
||||
|
||||
enum { NR_OF_IRQ = 64 };
|
||||
|
||||
/**
|
||||
* Constructor, enables all interrupts
|
||||
* Constructor
|
||||
*/
|
||||
Pic() : Mmio(Board::AVIC_MMIO_BASE)
|
||||
{
|
||||
mask();
|
||||
write<Nimask>(Nimask::NONE_MASKED);
|
||||
write<Intcntl>(Intcntl::init_value());
|
||||
write<Inttypeh>(Inttype::ALL_IRQS);
|
||||
write<Inttypel>(Inttype::ALL_IRQS);
|
||||
for (unsigned i = 0; i < Nipriority::ITEMS; i++)
|
||||
write<Nipriority>(Nipriority::ALL_LOWEST, i);
|
||||
write<Intenablel>(0);
|
||||
write<Intenableh>(0);
|
||||
write<Nimask>(~0);
|
||||
write<Intcntl>(0);
|
||||
write<Inttypeh>(0);
|
||||
write<Inttypel>(0);
|
||||
for (unsigned i = 0; i < Nipriority::ITEMS; i++) {
|
||||
write<Nipriority>(0, i); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize processor local interface of the controller
|
||||
*/
|
||||
void init_processor_local() { }
|
||||
|
||||
/**
|
||||
* Receive a pending request number 'i'
|
||||
* Try to receive an IRQ in 'i' and return wether it was successful
|
||||
*/
|
||||
bool take_request(unsigned & i)
|
||||
{
|
||||
i = read<Nivecsr::Nvector>();
|
||||
return valid(i) ? true : false;
|
||||
return _valid(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the last taken request
|
||||
* Unmask IRQ 'i'
|
||||
*/
|
||||
void finish_request() {
|
||||
/* requests disappear by source retraction or masking */ }
|
||||
void unmask(unsigned const i, unsigned) {
|
||||
if (_valid(i)) { write<Intennum>(i); } }
|
||||
|
||||
/**
|
||||
* Validate request number 'i'
|
||||
* Mask IRQ 'i'
|
||||
*/
|
||||
bool valid(unsigned const i) const {
|
||||
return i < NR_OF_IRQ; }
|
||||
void mask(unsigned const i) { if (i < NR_OF_IRQ) write<Intdisnum>(i); }
|
||||
|
||||
/**
|
||||
* Mask all interrupts
|
||||
* Return wether IRQ 'irq_id' is inter-processor IRQ of CPU 'cpu_id'
|
||||
*/
|
||||
void mask()
|
||||
{
|
||||
write<Intenablel>(0);
|
||||
write<Intenableh>(0);
|
||||
}
|
||||
bool is_ip_interrupt(unsigned, unsigned) { return false; }
|
||||
|
||||
/**
|
||||
* Unmask interrupt
|
||||
*
|
||||
* \param interrupt_id kernel name of targeted interrupt
|
||||
*/
|
||||
void unmask(unsigned const interrupt_id, unsigned)
|
||||
{
|
||||
if (interrupt_id < NR_OF_IRQ) {
|
||||
write<Intennum>(interrupt_id);
|
||||
}
|
||||
}
|
||||
/*************
|
||||
** Dummies **
|
||||
*************/
|
||||
|
||||
/**
|
||||
* Mask interrupt 'i'
|
||||
*/
|
||||
void mask(unsigned const i) {
|
||||
if (i < NR_OF_IRQ) write<Intdisnum>(i); }
|
||||
|
||||
/**
|
||||
* Wether an interrupt is inter-processor interrupt of a processor
|
||||
*
|
||||
* \param interrupt_id kernel name of the interrupt
|
||||
* \param processor_id kernel name of the processor
|
||||
*/
|
||||
bool is_ip_interrupt(unsigned const interrupt_id,
|
||||
unsigned const processor_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the inter-processor interrupt of a processor
|
||||
*
|
||||
* \param processor_id kernel name of the processor
|
||||
*/
|
||||
void trigger_ip_interrupt(unsigned const processor_id) { }
|
||||
void init_processor_local() { }
|
||||
void trigger_ip_interrupt(unsigned) { }
|
||||
void finish_request() { /* done by source retraction or masking */ }
|
||||
};
|
||||
|
||||
namespace Kernel { class Pic : public Genode::Pic { }; }
|
||||
|
@ -46,73 +46,40 @@ class Genode::Pic : public Mmio
|
||||
struct Nsen_mask : Bitfield<31,1> { };
|
||||
};
|
||||
|
||||
struct Priomask : Register<0xc, 32>
|
||||
{
|
||||
struct Mask : Bitfield<0,8> { };
|
||||
};
|
||||
|
||||
struct Syncctrl : Register<0x10, 32>
|
||||
{
|
||||
struct Syncmode : Bitfield<0,2> { };
|
||||
};
|
||||
|
||||
struct Dsmint : Register<0x14, 32>
|
||||
{
|
||||
struct Dsm : Bitfield<0,1> { };
|
||||
};
|
||||
/**
|
||||
* Priority mask register
|
||||
*/
|
||||
struct Priomask : Register<0xc, 32> {
|
||||
struct Mask : Bitfield<0,8> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt security registers
|
||||
*/
|
||||
struct Intsec : Register_array<0x80, 32, NR_OF_IRQ, 1>
|
||||
{
|
||||
struct Nonsecure : Bitfield<0, 1> { };
|
||||
};
|
||||
struct Intsec : Register_array<0x80, 32, NR_OF_IRQ, 1> {
|
||||
struct Nonsecure : Bitfield<0, 1> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt set enable registers
|
||||
*/
|
||||
struct Enset : Register_array<0x100, 32, NR_OF_IRQ, 1, true>
|
||||
{
|
||||
struct Set_enable : Bitfield<0, 1> { };
|
||||
};
|
||||
struct Enset : Register_array<0x100, 32, NR_OF_IRQ, 1, true> {
|
||||
struct Set_enable : Bitfield<0, 1> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt clear enable registers
|
||||
*/
|
||||
struct Enclear : Register_array<0x180, 32, NR_OF_IRQ, 1, true>
|
||||
{
|
||||
struct Clear_enable : Bitfield<0, 1> { };
|
||||
};
|
||||
struct Enclear : Register_array<0x180, 32, NR_OF_IRQ, 1, true> {
|
||||
struct Clear_enable : Bitfield<0, 1> { }; };
|
||||
|
||||
/**
|
||||
* Interrupt priority level registers
|
||||
*/
|
||||
struct Priority : Register_array<0x400, 32, NR_OF_IRQ, 8>
|
||||
{
|
||||
enum { MIN_PRIO = 0xff };
|
||||
};
|
||||
|
||||
/**
|
||||
* Pending registers
|
||||
*/
|
||||
struct Pndr : Register_array<0xd00, 32, NR_OF_IRQ, 1>
|
||||
{
|
||||
struct Pending : Bitfield<0, 1> { };
|
||||
};
|
||||
struct Priority : Register_array<0x400, 32, NR_OF_IRQ, 8> { };
|
||||
|
||||
/**
|
||||
* Highest interrupt pending registers
|
||||
*/
|
||||
struct Hipndr : Register_array<0xd80, 32, NR_OF_IRQ, 1, true>
|
||||
{
|
||||
struct Pending : Bitfield<0, 1> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Maximum supported interrupt priority
|
||||
*/
|
||||
unsigned _max_priority() { return 255; }
|
||||
struct Hipndr : Register_array<0xd80, 32, NR_OF_IRQ, 1, true> {
|
||||
struct Pending : Bitfield<0, 1> { }; };
|
||||
|
||||
/**
|
||||
* Initializes security extension if needed
|
||||
@ -131,104 +98,66 @@ class Genode::Pic : public Mmio
|
||||
write<Enclear::Clear_enable>(1, i);
|
||||
}
|
||||
write<Priomask::Mask>(0x1f);
|
||||
write<Intctrl>(Intctrl::Enable::bits(1) |
|
||||
Intctrl::Nsen::bits(1) |
|
||||
Intctrl::Nsen_mask::bits(1));
|
||||
Intctrl::access_t v = 0;
|
||||
Intctrl::Enable::set(v, 1);
|
||||
Intctrl::Nsen::set(v, 1);
|
||||
Intctrl::Nsen_mask::set(v, 1);
|
||||
write<Intctrl>(v);
|
||||
_init_security_ext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark interrupt unsecure
|
||||
*
|
||||
* \param i targeted interrupt
|
||||
* Mark interrupt 'i' unsecure
|
||||
*/
|
||||
void unsecure(unsigned const i);
|
||||
|
||||
/**
|
||||
* Mark interrupt secure
|
||||
*
|
||||
* \param i targeted interrupt
|
||||
* Mark interrupt 'i' secure
|
||||
*/
|
||||
void secure(unsigned const i);
|
||||
|
||||
/**
|
||||
* Initialize processor local interface of the controller
|
||||
*/
|
||||
void init_processor_local() { }
|
||||
|
||||
/**
|
||||
* Receive a pending request number 'i'
|
||||
*/
|
||||
bool take_request(unsigned & i)
|
||||
{
|
||||
for (unsigned j = 0; j < NR_OF_IRQ; j++) {
|
||||
if (read<Hipndr::Pending>(j)) {
|
||||
if (!read<Hipndr::Pending>(j)) { continue; }
|
||||
i = j;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the last taken request
|
||||
*/
|
||||
void finish_request() { }
|
||||
|
||||
/**
|
||||
* Validate request number 'i'
|
||||
*/
|
||||
bool valid(unsigned const i) const {
|
||||
return i < NR_OF_IRQ; }
|
||||
bool valid(unsigned const i) const { return i < NR_OF_IRQ; }
|
||||
|
||||
/**
|
||||
* Mask all interrupts
|
||||
* Unmask interrupt 'i'
|
||||
*/
|
||||
void mask()
|
||||
{
|
||||
for (unsigned i=0; i < NR_OF_IRQ; i++)
|
||||
write<Enclear::Clear_enable>(1, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmask interrupt
|
||||
*
|
||||
* \param interrupt_id kernel name of targeted interrupt
|
||||
*/
|
||||
void unmask(unsigned const interrupt_id, unsigned)
|
||||
{
|
||||
if (interrupt_id < NR_OF_IRQ) {
|
||||
write<Enset::Set_enable>(1, interrupt_id);
|
||||
}
|
||||
}
|
||||
void unmask(unsigned const i, unsigned) {
|
||||
if (valid(i)) { write<Enset::Set_enable>(1, i); } }
|
||||
|
||||
/**
|
||||
* Mask interrupt 'i'
|
||||
*/
|
||||
void mask(unsigned const i)
|
||||
{
|
||||
if (i < NR_OF_IRQ)
|
||||
write<Enclear::Clear_enable>(1, i);
|
||||
}
|
||||
void mask(unsigned const i) {
|
||||
if (valid(i)) { write<Enclear::Clear_enable>(1, i); } }
|
||||
|
||||
/**
|
||||
* Wether an interrupt is inter-processor interrupt of a processor
|
||||
*
|
||||
* \param interrupt_id kernel name of the interrupt
|
||||
* \param processor_id kernel name of the processor
|
||||
*/
|
||||
bool is_ip_interrupt(unsigned const interrupt_id,
|
||||
unsigned const processor_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool is_ip_interrupt(unsigned, unsigned) { return false; }
|
||||
|
||||
/**
|
||||
* Trigger the inter-processor interrupt of a processor
|
||||
*
|
||||
* \param processor_id kernel name of the processor
|
||||
*/
|
||||
void trigger_ip_interrupt(unsigned const processor_id) { }
|
||||
/*************
|
||||
** Dummies **
|
||||
*************/
|
||||
|
||||
void trigger_ip_interrupt(unsigned) { }
|
||||
void init_processor_local() { }
|
||||
void finish_request() { }
|
||||
};
|
||||
|
||||
namespace Kernel { class Pic : public Genode::Pic { }; }
|
||||
|
@ -50,10 +50,8 @@ namespace Genode
|
||||
|
||||
struct Aux : Register<0x104, 32>
|
||||
{
|
||||
struct Associativity : Bitfield<16,1> {
|
||||
enum { WAY_8, WAY_16 }; };
|
||||
struct Way_size : Bitfield<17,3> {
|
||||
enum { SZ_64KB = 0x3 }; };
|
||||
struct Associativity : Bitfield<16,1> { };
|
||||
struct Way_size : Bitfield<17,3> { };
|
||||
struct Share_override : Bitfield<22,1> { };
|
||||
struct Reserved : Bitfield<25,1> { };
|
||||
struct Ns_lockdown : Bitfield<26,1> { };
|
||||
@ -64,15 +62,17 @@ namespace Genode
|
||||
|
||||
static access_t init_value()
|
||||
{
|
||||
return Associativity::bits(Associativity::WAY_16) |
|
||||
Way_size::bits(Way_size::SZ_64KB) |
|
||||
Share_override::bits(1) |
|
||||
Reserved::bits(1) |
|
||||
Ns_lockdown::bits(1) |
|
||||
Ns_irq_ctrl::bits(1) |
|
||||
Data_prefetch::bits(1) |
|
||||
Inst_prefetch::bits(1) |
|
||||
Early_bresp::bits(1);
|
||||
access_t v = 0;
|
||||
Associativity::set(v, 1);
|
||||
Way_size::set(v, 3);
|
||||
Share_override::set(v, 1);
|
||||
Reserved::set(v, 1);
|
||||
Ns_lockdown::set(v, 1);
|
||||
Ns_irq_ctrl::set(v, 1);
|
||||
Data_prefetch::set(v, 1);
|
||||
Inst_prefetch::set(v, 1);
|
||||
Early_bresp::set(v, 1);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,7 +38,7 @@ class Genode::Pic : public Arm_gic
|
||||
Cpu::PL390_CPU_MMIO_BASE)
|
||||
{
|
||||
/* configure every shared peripheral interrupt */
|
||||
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++) {
|
||||
for (unsigned i = min_spi; i <= _max_interrupt; i++) {
|
||||
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
|
||||
_distr.write<Distr::Ipriorityr::Priority>(0, i);
|
||||
_distr.write<Distr::Itargetsr::Cpu_targets>(0xff, i);
|
||||
@ -55,7 +55,7 @@ class Genode::Pic : public Arm_gic
|
||||
_cpui.write<Cpui::Ctlr>(ctlr);
|
||||
|
||||
/* use whole band of prios */
|
||||
_cpui.write<Cpui::Bpr::Binary_point>(Cpui::Bpr::NO_PREEMPTION);
|
||||
_cpui.write<Cpui::Bpr::Binary_point>(~0);
|
||||
|
||||
/* enable device */
|
||||
_distr.write<Distr::Ctlr>(Distr::Ctlr::Enable::bits(1));
|
||||
|
@ -246,7 +246,6 @@ extern "C" void init_kernel_multiprocessor()
|
||||
/* synchronize data view of all processors */
|
||||
Processor::invalidate_data_caches();
|
||||
Processor::invalidate_instr_caches();
|
||||
Processor::invalidate_control_flow_predictions();
|
||||
Processor::data_synchronization_barrier();
|
||||
|
||||
/* initialize processor in physical mode */
|
||||
|
@ -22,10 +22,9 @@ void Arm_gic::_init()
|
||||
_distr.write<Distr::Ctlr::Enable>(0);
|
||||
|
||||
/* configure every shared peripheral interrupt */
|
||||
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++)
|
||||
{
|
||||
for (unsigned i = min_spi; i <= _max_irq; i++) {
|
||||
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
|
||||
_distr.write<Distr::Ipriorityr::Priority>(_distr.max_priority(), i);
|
||||
_distr.write<Distr::Ipriorityr::Priority>(0, i);
|
||||
}
|
||||
/* enable device */
|
||||
_distr.write<Distr::Ctlr::Enable>(1);
|
||||
|
@ -33,9 +33,11 @@ struct Pmcr : Register<32>
|
||||
|
||||
static access_t enable_and_reset()
|
||||
{
|
||||
return E::bits(1) |
|
||||
P::bits(1) |
|
||||
C::bits(1);
|
||||
access_t v = 0;
|
||||
E::set(v, 1);
|
||||
P::set(v, 1);
|
||||
C::set(v, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
static access_t read()
|
||||
@ -45,10 +47,8 @@ struct Pmcr : Register<32>
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[v], c15, c12, 0" :: [v]"r"(v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile("mcr p15, 0, %[v], c15, c12, 0" :: [v]"r"(v) : ); }
|
||||
};
|
||||
|
||||
|
||||
@ -57,12 +57,7 @@ struct Pmcr : Register<32>
|
||||
*/
|
||||
struct Sysvalcntrr : Register<32>
|
||||
{
|
||||
struct Resetcntr : Bitfield<0,1> { }; /* reset all counter */
|
||||
|
||||
static access_t reset_counter()
|
||||
{
|
||||
return Resetcntr::bits(0);
|
||||
}
|
||||
static access_t reset_counter() { return 0; }
|
||||
|
||||
static access_t read()
|
||||
{
|
||||
@ -71,10 +66,8 @@ struct Sysvalcntrr : Register<32>
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[v], c15, c12, 1" :: [v]"r"(v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile("mcr p15, 0, %[v], c15, c12, 1" :: [v]"r"(v) : ); }
|
||||
};
|
||||
|
||||
|
||||
@ -85,10 +78,7 @@ struct Accvalctlr : Register<32>
|
||||
{
|
||||
struct V : Bitfield<0,1> { }; /* enable access in user-mode */
|
||||
|
||||
static access_t enable_user_access()
|
||||
{
|
||||
return V::bits(1);
|
||||
}
|
||||
static access_t enable_user_access() { return V::bits(1); }
|
||||
|
||||
static access_t read()
|
||||
{
|
||||
@ -97,18 +87,16 @@ struct Accvalctlr : Register<32>
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[v], c15, c9, 0" :: [v]"r"(v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile("mcr p15, 0, %[v], c15, c9, 0" :: [v]"r"(v) : ); }
|
||||
};
|
||||
|
||||
|
||||
void Kernel::Perf_counter::enable()
|
||||
{
|
||||
/* enable counters and disable overflow interrupt. */
|
||||
Pmcr::access_t v = Pmcr::enable_and_reset() |
|
||||
Pmcr::D::bits(1); /* count every 64 cycles */
|
||||
Pmcr::access_t v = Pmcr::enable_and_reset();
|
||||
Pmcr::D::set(v, 1); /* count every 64 cycles */
|
||||
Pmcr::write(v);
|
||||
|
||||
Sysvalcntrr::write(Sysvalcntrr::reset_counter());
|
||||
|
@ -33,9 +33,11 @@ struct Pmcr : Register<32>
|
||||
|
||||
static access_t enable_and_reset()
|
||||
{
|
||||
return E::bits(1) |
|
||||
P::bits(1) |
|
||||
C::bits(1);
|
||||
access_t v = 0;
|
||||
E::set(v, 1);
|
||||
P::set(v, 1);
|
||||
C::set(v, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
static access_t read()
|
||||
@ -45,10 +47,8 @@ struct Pmcr : Register<32>
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[v], c9, c12, 0" :: [v]"r"(v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile("mcr p15, 0, %[v], c9, c12, 0" :: [v]"r"(v) : ); }
|
||||
};
|
||||
|
||||
|
||||
@ -57,15 +57,17 @@ struct Pmcr : Register<32>
|
||||
*/
|
||||
struct Pmintenclr : Register<32>
|
||||
{
|
||||
struct C : Bitfield<31,1> { }; /* disable cycle counter overflow interrupt request */
|
||||
struct P0 : Bitfield<0,1> { }; /* disable pmc0 overflow interrupt request */
|
||||
struct P1 : Bitfield<1,1> { }; /* disable pmc1 overflow interrupt reuqest */
|
||||
struct C : Bitfield<31,1> { }; /* disable cycle counter overflow IRQ */
|
||||
struct P0 : Bitfield<0,1> { }; /* disable pmc0 overflow IRQ */
|
||||
struct P1 : Bitfield<1,1> { }; /* disable pmc1 overflow IRQ */
|
||||
|
||||
static access_t disable_overflow_intr()
|
||||
{
|
||||
return C::bits(1) |
|
||||
P0::bits(1) |
|
||||
P1::bits(1);
|
||||
access_t v = 0;
|
||||
C::set(v, 1) ;
|
||||
P0::set(v, 1);
|
||||
P1::set(v, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
static access_t read()
|
||||
@ -75,10 +77,8 @@ struct Pmintenclr : Register<32>
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[v], c9, c14, 2" :: [v]"r"(v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile("mcr p15, 0, %[v], c9, c14, 2" :: [v]"r"(v) : ); }
|
||||
};
|
||||
|
||||
|
||||
@ -95,11 +95,13 @@ struct Pmcntenset : Register<32>
|
||||
|
||||
static access_t enable_counter()
|
||||
{
|
||||
return C::bits(1) |
|
||||
P0::bits(1) |
|
||||
P1::bits(1) |
|
||||
P2::bits(1) |
|
||||
P3::bits(1);
|
||||
access_t v = 0;
|
||||
C::set(v, 1);
|
||||
P0::set(v, 1);
|
||||
P1::set(v, 1);
|
||||
P2::set(v, 1);
|
||||
P3::set(v, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
static access_t read()
|
||||
@ -109,10 +111,8 @@ struct Pmcntenset : Register<32>
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c9, c12, 1" :: [v]"r"(v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile("mcr p15, 0, %0, c9, c12, 1" :: [v]"r"(v) : ); }
|
||||
};
|
||||
|
||||
|
||||
@ -127,9 +127,11 @@ struct Pmovsr : Register<32>
|
||||
|
||||
static access_t clear_overflow_flags()
|
||||
{
|
||||
return C::bits(1) |
|
||||
P0::bits(1) |
|
||||
P1::bits(1);
|
||||
access_t v = 0;
|
||||
C::set(v, 1);
|
||||
P0::set(v, 1);
|
||||
P1::set(v, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
static access_t read()
|
||||
@ -139,10 +141,8 @@ struct Pmovsr : Register<32>
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c9, c12, 3" :: [v]"r"(v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile("mcr p15, 0, %0, c9, c12, 3" :: [v]"r"(v) : ); }
|
||||
};
|
||||
|
||||
|
||||
@ -153,10 +153,7 @@ struct Pmuseren : Register<32>
|
||||
{
|
||||
struct En : Bitfield<0,1> { }; /* enable user mode access */
|
||||
|
||||
static access_t enable()
|
||||
{
|
||||
return En::bits(1);
|
||||
}
|
||||
static access_t enable() { return En::bits(1); }
|
||||
|
||||
static access_t read()
|
||||
{
|
||||
@ -165,10 +162,8 @@ struct Pmuseren : Register<32>
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c9, c14, 0" :: [v]"r"(v) : );
|
||||
}
|
||||
static void write(access_t const v) {
|
||||
asm volatile("mcr p15, 0, %0, c9, c14, 0" :: [v]"r"(v) : ); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief Programmable interrupt controller for core
|
||||
* \author Martin stein
|
||||
* \author Stefan Kalkowski
|
||||
* \author Martin Stein
|
||||
* \date 2011-10-26
|
||||
*/
|
||||
|
||||
@ -19,22 +20,25 @@ using namespace Genode;
|
||||
void Arm_gic::_init()
|
||||
{
|
||||
/* configure every shared peripheral interrupt */
|
||||
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++) {
|
||||
for (unsigned i = min_spi; i <= _max_irq; i++) {
|
||||
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
|
||||
_distr.write<Distr::Ipriorityr::Priority>(0, i);
|
||||
_distr.write<Distr::Itargetsr::Cpu_targets>(0xff, i);
|
||||
_distr.write<Distr::Itargetsr::Cpu_targets>(~0, i);
|
||||
}
|
||||
|
||||
/* disable the priority filter */
|
||||
_cpui.write<Cpui::Pmr::Priority>(0xff);
|
||||
_cpui.write<Cpui::Pmr::Priority>(~0);
|
||||
|
||||
/* signal secure IRQ via FIQ interface */
|
||||
_cpui.write<Cpui::Ctlr>(Cpui::Ctlr::Enable_grp0::bits(1) |
|
||||
Cpui::Ctlr::Enable_grp1::bits(1) |
|
||||
Cpui::Ctlr::Fiq_en::bits(1));
|
||||
typedef Cpui::Ctlr Ctlr;
|
||||
Ctlr::access_t v = 0;
|
||||
Ctlr::Enable_grp0::set(v, 1);
|
||||
Ctlr::Enable_grp1::set(v, 1);
|
||||
Ctlr::Fiq_en::set(v, 1);
|
||||
_cpui.write<Ctlr>(v);
|
||||
|
||||
/* use whole band of prios */
|
||||
_cpui.write<Cpui::Bpr::Binary_point>(Cpui::Bpr::NO_PREEMPTION);
|
||||
_cpui.write<Cpui::Bpr::Binary_point>(~0);
|
||||
|
||||
/* enable device */
|
||||
_distr.write<Distr::Ctlr>(Distr::Ctlr::Enable::bits(1));
|
||||
|
Loading…
x
Reference in New Issue
Block a user