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