hw: no superfluous ORing of zeros and clean up

fix #710
This commit is contained in:
Martin Stein 2014-08-08 14:38:27 +02:00 committed by Norman Feske
parent e7d57ded36
commit 14e9a89cba
18 changed files with 658 additions and 1237 deletions

View File

@ -210,7 +210,7 @@ class Kernel::Mode_transition_control
enum {
SIZE_LOG2 = Genode::Translation_table::MIN_PAGE_SIZE_LOG2,
SIZE = 1 << SIZE_LOG2,
VIRT_BASE = Processor::EXCEPTION_ENTRY,
VIRT_BASE = Processor::exception_entry,
ALIGN_LOG2 = Genode::Translation_table::ALIGNM_LOG2,
ALIGN = 1 << ALIGN_LOG2,
};

View File

@ -46,7 +46,7 @@ class Kernel::Idle_thread : public Thread
enum {
STACK_SIZE = sizeof(addr_t) * 32,
STACK_ALIGNM = Cpu::DATA_ACCESS_ALIGNM,
STACK_ALIGNM = Cpu::data_access_align,
};
char _stack[STACK_SIZE] __attribute__((aligned(STACK_ALIGNM)));

View File

@ -35,26 +35,20 @@ class Genode::Arm
{
public:
enum {
TTBCR_N = 0,
EXCEPTION_ENTRY = 0xffff0000,
DATA_ACCESS_ALIGNM = 4,
};
static constexpr addr_t exception_entry = 0xffff0000;
static constexpr addr_t data_access_align = 4;
/**
* Multiprocessor affinity register
*/
struct Mpidr : Register<32>
{
struct Aff_0 : Bitfield<0, 8> { };
struct Aff_0 : Bitfield<0, 8> { }; /* affinity value 0 */
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c0, c0, 5" : [v] "=r" (v) ::);
asm volatile ("mrc p15, 0, %0, c0, c0, 5" : "=r" (v) :: );
return v;
}
};
@ -64,13 +58,10 @@ class Genode::Arm
*/
struct Ctr : Register<32>
{
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c0, c0, 1" : [v]"=r"(v) :: );
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r" (v) :: );
return v;
}
};
@ -85,9 +76,6 @@ class Genode::Arm
struct I : Bitfield<12,1> { }; /* enable instruction caches */
struct V : Bitfield<13,1> { }; /* select exception entry */
/**
* Read register value
*/
static access_t read()
{
access_t v;
@ -95,14 +83,11 @@ class Genode::Arm
return v;
}
/**
* Write register value
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %0, c1, c0, 0" :: "r" (v) : ); }
/**
* Initialization that is common
* Do initialization that is common on value 'v'
*/
static void init_common(access_t & v)
{
@ -112,7 +97,7 @@ class Genode::Arm
}
/**
* Initialization for virtual kernel stage
* Do initialization for virtual mode in kernel on value 'v'
*/
static void init_virt_kernel(access_t & v) { M::set(v, 1); }
};
@ -122,28 +107,15 @@ class Genode::Arm
*/
struct Ttbcr : Register<32>
{
struct N : Bitfield<0, 3> { }; /* base address width */
/**
* Write register, only in privileged CPU mode
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %[v], c2, c0, 2" :: [v]"r"(v) : ); }
asm volatile ("mcr p15, 0, %0, c2, c0, 2" :: "r" (v) : ); }
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c2, c0, 2" : [v]"=r"(v) :: );
asm volatile ("mrc p15, 0, %0, c2, c0, 2" : "=r" (v) :: );
return v;
}
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel() { return N::bits(TTBCR_N); }
};
/**
@ -151,21 +123,15 @@ class Genode::Arm
*/
struct Ttbr0 : Register<32>
{
struct Ba : Bitfield<14-TTBCR_N, 18+TTBCR_N> { };
struct Ba : Bitfield<14, 18> { }; /* base */
/**
* Write register, only in privileged CPU mode
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %[v], c2, c0, 0" :: [v]"r"(v) : ); }
asm volatile ("mcr p15, 0, %0, c2, c0, 0" :: "r" (v) : ); }
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c2, c0, 0" : [v]"=r"(v) :: );
asm volatile ("mrc p15, 0, %0, c2, c0, 0" : "=r" (v) :: );
return v;
}
};
@ -175,48 +141,15 @@ class Genode::Arm
*/
struct Dacr : Register<32>
{
enum Dx_values { NO_ACCESS = 0, CLIENT = 1 };
struct D0 : Bitfield<0,2> { }; /* access mode for domain 0 */
/**
* Access values for the 16 available domains
*/
struct D0 : Bitfield<0,2> { };
struct D1 : Bitfield<2,2> { };
struct D2 : Bitfield<4,2> { };
struct D3 : Bitfield<6,2> { };
struct D4 : Bitfield<8,2> { };
struct D5 : Bitfield<10,2> { };
struct D6 : Bitfield<12,2> { };
struct D7 : Bitfield<14,2> { };
struct D8 : Bitfield<16,2> { };
struct D9 : Bitfield<18,2> { };
struct D10 : Bitfield<20,2> { };
struct D11 : Bitfield<22,2> { };
struct D12 : Bitfield<24,2> { };
struct D13 : Bitfield<26,2> { };
struct D14 : Bitfield<28,2> { };
struct D15 : Bitfield<30,2> { };
/**
* Write register, only in privileged CPU mode
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %[v], c3, c0, 0" :: [v]"r"(v) : ); }
asm volatile ("mcr p15, 0, %0, c3, c0, 0" :: "r" (v) : ); }
/**
* Initialize for Genodes operational mode
* Return value initialized for virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return D0::bits(CLIENT) | D1::bits(NO_ACCESS) |
D2::bits(NO_ACCESS) | D3::bits(NO_ACCESS) |
D4::bits(NO_ACCESS) | D5::bits(NO_ACCESS) |
D6::bits(NO_ACCESS) | D7::bits(NO_ACCESS) |
D8::bits(NO_ACCESS) | D9::bits(NO_ACCESS) |
D10::bits(NO_ACCESS) | D11::bits(NO_ACCESS) |
D12::bits(NO_ACCESS) | D13::bits(NO_ACCESS) |
D14::bits(NO_ACCESS) | D15::bits(NO_ACCESS);
}
static access_t init_virt_kernel() { return D0::bits(1); }
};
/**
@ -224,14 +157,8 @@ class Genode::Arm
*/
struct Icimvau : Register<32>
{
/**
* Write register value
*/
static void write(access_t const v)
{
asm volatile (
"mcr p15, 0, %[v], c7, c5, 1\n" :: [v] "r" (v) : );
}
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %0, c7, c5, 1" :: "r" (v) : ); }
};
/**
@ -239,14 +166,8 @@ class Genode::Arm
*/
struct Dccmvac : Register<32>
{
/**
* Write register value
*/
static void write(access_t const v)
{
asm volatile (
"mcr p15, 0, %[v], c7, c10, 1\n" :: [v] "r" (v) : );
}
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r" (v) : ); }
};
/**
@ -254,21 +175,13 @@ class Genode::Arm
*/
struct Cidr : Register<32>
{
/**
* Write register value
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c13, c0, 1" :: [v]"r"(v) : );
}
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %0, c13, c0, 1" :: "r" (v) : ); }
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c13, c0, 1" : [v]"=r"(v) :: );
asm volatile ("mrc p15, 0, %0, c13, c0, 1" : "=r" (v) :: );
return v;
}
};
@ -278,81 +191,59 @@ class Genode::Arm
*/
struct Psr : Register<32>
{
struct M : Bitfield<0,5> /* processor mode */
{
enum { USER = 0b10000, SUPERVISOR = 0b10011 };
};
struct T : Bitfield<5,1> /* instruction state */
{
enum { ARM = 0 };
};
static constexpr access_t usr = 16;
static constexpr access_t svc = 19;
struct M : Bitfield<0,5> { }; /* CPU mode */
struct F : Bitfield<6,1> { }; /* FIQ disable */
struct I : Bitfield<7,1> { }; /* IRQ disable */
struct A : Bitfield<8,1> { }; /* asynchronous abort disable */
struct A : Bitfield<8,1> { }; /* async. abort disable */
struct E : Bitfield<9,1> /* load/store endianess */
{
enum { LITTLE = 0 };
};
struct J : Bitfield<24,1> /* instruction state */
{
enum { ARM = 0 };
};
/**
* Read register
*/
static access_t read()
{
access_t v;
asm volatile ("mrs %[v], cpsr" : [v] "=r" (v) : : );
asm volatile ("mrs %0, cpsr" : "=r" (v) :: );
return v;
}
/**
* Write register
*/
static void write(access_t const v) {
asm volatile ("msr cpsr, %[v]" : : [v] "r" (v) : ); }
asm volatile ("msr cpsr, %0" :: "r" (v) : ); }
/**
* Initial value for a user execution context with trustzone
*
* FIXME: This function should not be declared in 'Arm' but in
* 'Arm_v7', but for now the declaration is necessary
* because of 'User_context::User_context()'.
* Return value initialized for user execution with trustzone
*/
inline static access_t init_user_with_trustzone();
/**
* Initial value for an userland execution context
* Do common initialization on register value 'v'
*/
static access_t init_user()
static void init_common(access_t & v)
{
return M::bits(M::USER) |
T::bits(T::ARM) |
F::bits(1) |
I::bits(0) |
A::bits(1) |
E::bits(E::LITTLE) |
J::bits(J::ARM);
F::set(v, 1);
A::set(v, 1);
}
/**
* Initial value for the kernel execution context
* Return initial value for user execution
*/
static access_t init_user()
{
access_t v = 0;
init_common(v);
M::set(v, usr);
return v;
}
/**
* Return initial value for the kernel
*/
static access_t init_kernel()
{
return M::bits(M::SUPERVISOR) |
T::bits(T::ARM) |
F::bits(1) |
I::bits(1) |
A::bits(1) |
E::bits(E::LITTLE) |
J::bits(J::ARM);
access_t v = 0;
init_common(v);
M::set(v, svc);
I::set(v, 1);
return v;
}
};
@ -361,17 +252,12 @@ class Genode::Arm
*/
struct Fsr : Register<32>
{
/**
* Fault status encoding
*/
enum Fault_status
{
SECTION_TRANSLATION = 5,
PAGE_TRANSLATION = 7,
};
static constexpr access_t section = 5;
static constexpr access_t page = 7;
struct Fs_3_0 : Bitfield<0, 4> { }; /* fault status */
struct Fs_4 : Bitfield<10, 1> { }; /* fault status */
struct Fs_0 : Bitfield<0, 4> { }; /* fault status */
struct Fs_1 : Bitfield<10, 1> { }; /* fault status */
struct Fs : Bitset_2<Fs_0, Fs_1> { }; /* fault status */
};
/**
@ -379,25 +265,12 @@ class Genode::Arm
*/
struct Ifsr : Fsr
{
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 1" : [v]"=r"(v) :: );
asm volatile ("mrc p15, 0, %0, c5, c0, 1" : "=r" (v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status()
{
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) |
(Fs_4::get(v) << Fs_3_0::WIDTH));
}
};
/**
@ -407,24 +280,12 @@ class Genode::Arm
{
struct Wnr : Bitfield<11, 1> { }; /* write not read bit */
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 0" : [v]"=r"(v) :: );
asm volatile ("mrc p15, 0, %0, c5, c0, 0" : "=r" (v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status() {
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) |
(Fs_4::get(v) << Fs_3_0::WIDTH));
}
};
/**
@ -432,10 +293,8 @@ class Genode::Arm
*/
struct Dfar : Register<32>
{
/**
* Read register value
*/
static access_t read() {
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c6, c0, 0" : [v]"=r"(v) :: );
return v;
@ -477,10 +336,9 @@ class Genode::Arm
*/
User_context();
/***************************************************
** Communication between user and context holder **
***************************************************/
/**
* Support for kernel calls
*/
void user_arg_0(unsigned const arg) { r0 = arg; }
void user_arg_1(unsigned const arg) { r1 = arg; }
void user_arg_2(unsigned const arg) { r2 = arg; }
@ -511,62 +369,52 @@ class Genode::Arm
}
/**
* Return if the context is in a page fault due to a translation miss
* Return if the context is in a page fault due to translation miss
*
* \param va holds the virtual fault-address if call returns 1
* \param w holds wether it's a write fault if call returns 1
*/
bool in_fault(addr_t & va, addr_t & w) const
{
/* determine fault type */
switch (cpu_exception) {
case PREFETCH_ABORT: {
/* check if fault was caused by a translation miss */
Ifsr::Fault_status const fs = Ifsr::fault_status();
if (fs == Ifsr::SECTION_TRANSLATION ||
fs == Ifsr::PAGE_TRANSLATION)
{
/* fetch fault data */
w = 0;
va = ip;
return 1;
}
return 0; }
Ifsr::access_t const fs = Ifsr::Fs::get(Ifsr::read());
if (fs != Ifsr::section && fs != Ifsr::page) { return 0; }
/* fetch fault data */
w = 0;
va = ip;
return 1; }
case DATA_ABORT: {
/* check if fault was caused by translation miss */
Dfsr::Fault_status const fs = Dfsr::fault_status();
if(fs == Dfsr::SECTION_TRANSLATION ||
fs == Dfsr::PAGE_TRANSLATION)
{
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return 1;
}
return 0; }
Dfsr::access_t const fs = Dfsr::Fs::get(Dfsr::read());
if (fs != Dfsr::section && fs != Dfsr::page) { return 0; }
default: return 0;
}
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return 1; }
default: return 0; }
}
};
/**
* Returns true if current execution context is running in user mode
*/
inline static bool is_user() {
return Psr::M::get(Psr::read()) == Psr::M::USER; }
static bool is_user() { return Psr::M::get(Psr::read()) == Psr::usr; }
/**
* Invalidate all entries of all instruction caches
*/
__attribute__((always_inline))
static void invalidate_instr_caches() {
asm volatile ("mcr p15, 0, %[rd], c7, c5, 0" :: [rd]"r"(0) : ); }
__attribute__((always_inline)) static void invalidate_instr_caches() {
asm volatile ("mcr p15, 0, %0, c7, c5, 0" :: "r" (0) : ); }
/**
* Flush all entries of all data caches
@ -588,14 +436,12 @@ class Genode::Arm
}
/**
* Invalidate all TLB entries of one address space
*
* \param pid ID of the targeted address space
* Invalidate all TLB entries of the address space named 'pid'
*/
static void flush_tlb_by_pid(unsigned const pid)
{
flush_caches();
asm volatile ("mcr p15, 0, %[pid], c8, c7, 2" :: [pid]"r"(pid) : );
asm volatile ("mcr p15, 0, %0, c8, c7, 2" :: "r" (pid) : );
}
/**
@ -604,41 +450,36 @@ class Genode::Arm
static void flush_tlb()
{
flush_caches();
asm volatile ("mcr p15, 0, %[rd], c8, c7, 0" :: [rd]"r"(0) : );
asm volatile ("mcr p15, 0, %0, c8, c7, 0" :: "r" (0) : );
}
static constexpr addr_t line_size = 1 << Board::CACHE_LINE_SIZE_LOG2;
static constexpr addr_t line_align_mask = ~(line_size - 1);
/**
* Clean every data-cache entry within a virtual region
* Flush data-cache entries for virtual region ['base', 'base + size')
*/
static void
flush_data_caches_by_virt_region(addr_t base, size_t const size)
{
enum {
LINE_SIZE = 1 << Board::CACHE_LINE_SIZE_LOG2,
LINE_ALIGNM_MASK = ~(LINE_SIZE - 1),
};
addr_t const top = base + size;
base = base & LINE_ALIGNM_MASK;
for (; base < top; base += LINE_SIZE) { Dccmvac::write(base); }
base &= line_align_mask;
for (; base < top; base += line_size) { Dccmvac::write(base); }
}
/**
* Invalidate every instruction-cache entry within a virtual region
* Bin instr.-cache entries for virtual region ['base', 'base + size')
*/
static void
invalidate_instr_caches_by_virt_region(addr_t base, size_t const size)
{
enum {
LINE_SIZE = 1 << Board::CACHE_LINE_SIZE_LOG2,
LINE_ALIGNM_MASK = ~(LINE_SIZE - 1),
};
addr_t const top = base + size;
base = base & LINE_ALIGNM_MASK;
for (; base < top; base += LINE_SIZE) { Icimvau::write(base); }
base &= line_align_mask;
for (; base < top; base += line_size) { Icimvau::write(base); }
}
/**
* Return true if the processor support multiple cores
* Return true if the CPU supports multiple cores
*/
static bool is_smp() { return PROCESSORS > 1; }
};

View File

@ -29,11 +29,14 @@
namespace Genode
{
/**
* Memory region attributes for the translation descriptor 'T'
* Commons for all translations
*/
template <typename T>
static typename T::access_t
arm_memory_region_attr(Page_flags const & flags);
class Translation;
/**
* Second level translation table
*/
class Page_table;
/**
* First level translation table
@ -41,276 +44,245 @@ namespace Genode
class Translation_table;
}
class Genode::Translation_table
class Genode::Translation
{
private:
/**
* Return permission configuration according to given mapping flags
*
* \param T targeted translation-table-descriptor type
* \param flags mapping flags
*
* \return descriptor value with AP and XN set and the rest left zero
* Return TEX value for device-memory translations
*/
template <typename T>
static typename T::access_t
access_permission_bits(Page_flags const & flags)
static constexpr unsigned _device_tex();
protected:
/**
* Return translation according to flags 'f' and phys. address 'pa'
*/
template <typename T> static typename T::access_t
_create(Page_flags const & f, addr_t const pa)
{
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); }
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:
enum {
SIZE_LOG2 = 10,
SIZE = 1 << SIZE_LOG2,
ALIGNM_LOG2 = SIZE_LOG2,
};
/**
* Common descriptor structure
*/
struct Descriptor : Register<32>, Translation
{
enum Type { FAULT, SMALL_PAGE };
enum {
VIRT_SIZE_LOG2 = 12,
VIRT_SIZE = 1 << VIRT_SIZE_LOG2,
VIRT_OFFSET_MASK = (1 << VIRT_SIZE_LOG2) - 1,
VIRT_BASE_MASK = ~(VIRT_OFFSET_MASK),
};
struct Type_0 : Bitfield<0, 2> { };
struct Type_1 : Bitfield<1, 1> { };
/**
* Get descriptor type of 'v'
*/
static Type type(access_t const v)
{
access_t const t0 = Type_0::get(v);
if (t0 == 0) { return FAULT; }
access_t const t1 = Type_1::get(v);
if (t1 == 1) { return SMALL_PAGE; }
return FAULT;
}
return Xn::bits(!flags.executable) | ap;
/**
* At descriptor value 'v' set type to 't'
*/
static void type(access_t & v, Type const t)
{
switch (t) {
case FAULT: Type_0::set(v, 0); return;
case SMALL_PAGE: Type_1::set(v, 1); return; }
}
static void invalidate(access_t & v) { type(v, FAULT); }
static bool valid(access_t & v) { return type(v) != FAULT; }
};
/**
* Small page descriptor structure
*/
struct Small_page : Descriptor
{
struct Xn : Bitfield<0, 1> { }; /* execute never */
struct B : Bitfield<2, 1> { }; /* mem region attr. */
struct Ap_0 : Bitfield<4, 2> { }; /* access permission */
struct Tex : Bitfield<6, 3> { }; /* mem region attr. */
struct Ap_1 : Bitfield<9, 1> { }; /* access permission */
struct S : Bitfield<10, 1> { }; /* shareable bit */
struct Ng : Bitfield<11, 1> { }; /* not global bit */
struct Pa : Bitfield<12, 20> { }; /* physical base */
struct Ap : Bitset_2<Ap_0, Ap_1> { }; /* access permission */
/**
* Return page descriptor for physical address 'pa' and 'flags'
*/
static access_t create(Page_flags const & flags, addr_t const pa)
{
access_t v = _create<Small_page>(flags, pa);
Descriptor::type(v, Descriptor::SMALL_PAGE);
return v;
}
};
private:
/* table payload that must be the only member of this class */
Descriptor::access_t _entries[SIZE/sizeof(Descriptor::access_t)];
enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 };
/**
* Get entry index by virtual offset
*
* \param i is overridden with the index if call returns 0
* \param vo virtual offset relative to the virtual table base
*
* \retval 0 on success
* \retval <0 translation failed
*/
bool _index_by_vo (unsigned & i, addr_t const vo) const
{
if (vo > max_virt_offset()) return false;
i = vo >> Descriptor::VIRT_SIZE_LOG2;
return true;
}
public:
/**
* Constructor
*/
Page_table()
{
assert(aligned(this, ALIGNM_LOG2));
memset(&_entries, 0, sizeof(_entries));
}
/**
* Second level translation table
* Maximum virtual offset that can be translated by this table
*/
class Page_table
static addr_t max_virt_offset()
{
public:
return (MAX_INDEX << Descriptor::VIRT_SIZE_LOG2)
+ (Descriptor::VIRT_SIZE - 1);
}
enum {
SIZE_LOG2 = 10,
SIZE = 1 << SIZE_LOG2,
ALIGNM_LOG2 = SIZE_LOG2,
};
/**
* Insert one atomic translation into this table
*
* \param vo offset of the virtual region represented
* by the translation within the virtual
* region represented by this table
* \param pa base of the physical backing store
* \param size size of the translated region
* \param flags mapping flags
*/
void insert_translation(addr_t vo,
addr_t pa,
size_t size,
Page_flags const & flags)
{
constexpr size_t sz = Descriptor::VIRT_SIZE;
/**
* Common descriptor structure
*/
struct Descriptor : Register<32>
{
/**
* Descriptor types
*/
enum Type { FAULT, SMALL_PAGE };
for (unsigned i; (size > 0) && _index_by_vo(i, vo);
size = (size < sz) ? 0 : size - sz,
vo += sz, pa += sz)
{
enum {
VIRT_SIZE_LOG2 = 12,
VIRT_SIZE = 1 << VIRT_SIZE_LOG2,
VIRT_OFFSET_MASK = (1 << VIRT_SIZE_LOG2) - 1,
VIRT_BASE_MASK = ~(VIRT_OFFSET_MASK),
};
/* compose new descriptor value */
Small_page::access_t const e =
Small_page::create(flags, pa);
struct Type_0 : Bitfield<0, 2> { };
struct Type_1 : Bitfield<1, 1> { };
/* check if it is a good idea to override the entry */
assert(!Descriptor::valid(_entries[i]) ||
_entries[i] == e);
/**
* Get descriptor type of 'v'
*/
static Type type(access_t const v)
{
access_t const t0 = Type_0::get(v);
if (t0 == 0) { return FAULT; }
access_t const t1 = Type_1::get(v);
if (t1 == 1) return SMALL_PAGE;
return FAULT;
}
/* override entry */
_entries[i] = e;
/**
* Set descriptor type of 'v'
*/
static void type(access_t & v, Type const t)
{
switch (t) {
case FAULT:
Type_0::set(v, 0);
return;
case SMALL_PAGE:
Type_1::set(v, 1);
return;
}
}
/* some CPUs need to act on changed translations */
Cpu::translation_added((addr_t)&_entries[i],
sizeof(Descriptor::access_t));
}
}
/**
* Invalidate descriptor 'v'
*/
static void invalidate(access_t & v) { type(v, FAULT); }
/**
* Remove translations that overlap with a given virtual region
*
* \param vo region offset within the tables virtual region
* \param size region size
*/
void remove_translation(addr_t vo, size_t size)
{
constexpr size_t sz = Descriptor::VIRT_SIZE;
/**
* Return if descriptor 'v' is valid
*/
static bool valid(access_t & v) {
return type(v) != FAULT; }
};
/**
* Small page descriptor structure
*/
struct Small_page : Descriptor
{
struct Xn : Bitfield<0, 1> { }; /* execute never */
struct B : Bitfield<2, 1> { }; /* mem region attr. */
struct C : Bitfield<3, 1> { }; /* mem region attr. */
struct Ap_0 : Bitfield<4, 2> { }; /* access permission */
struct Tex : Bitfield<6, 3> { }; /* mem region attr. */
struct Ap_1 : Bitfield<9, 1> { }; /* access permission */
struct S : Bitfield<10, 1> { }; /* shareable bit */
struct Ng : Bitfield<11, 1> { }; /* not global bit */
struct Pa : Bitfield<12, 20> { }; /* physical base */
struct Ap : Bitset_2<Ap_0, Ap_1> { }; /* access permission */
/**
* Compose descriptor value
*/
static access_t create(Page_flags const & flags,
addr_t const pa)
{
access_t v = access_permission_bits<Small_page>(flags);
v |= arm_memory_region_attr<Small_page>(flags);
v |= Ng::bits(!flags.global);
v |= S::bits(Cpu::is_smp());
v |= Pa::masked(pa);
Descriptor::type(v, Descriptor::SMALL_PAGE);
return v;
}
};
private:
/*
* Table payload
*
* Must be the only member of this class
*/
Descriptor::access_t _entries[SIZE/sizeof(Descriptor::access_t)];
enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 };
/**
* Get entry index by virtual offset
*
* \param i is overridden with the index if call returns 0
* \param vo virtual offset relative to the virtual table base
*
* \retval 0 on success
* \retval <0 translation failed
*/
bool _index_by_vo (unsigned & i, addr_t const vo) const
{
if (vo > max_virt_offset()) return false;
i = vo >> Descriptor::VIRT_SIZE_LOG2;
return true;
for (unsigned i; (size > 0) && _index_by_vo(i, vo);
size = (size < sz) ? 0 : size - sz, vo += sz)
{
switch (Descriptor::type(_entries[i])) {
case Descriptor::SMALL_PAGE:
Descriptor::invalidate(_entries[i]);
default: ;
}
}
}
public:
/**
* Does this table solely contain invalid entries
*/
bool empty()
{
for (unsigned i = 0; i <= MAX_INDEX; i++) {
if (Descriptor::valid(_entries[i])) return false; }
return true;
}
/**
* Constructor
*/
Page_table()
{
assert(aligned(this, ALIGNM_LOG2));
memset(&_entries, 0, sizeof(_entries));
}
/**
* Maximum virtual offset that can be translated by this table
*/
static addr_t max_virt_offset()
{
return (MAX_INDEX << Descriptor::VIRT_SIZE_LOG2)
+ (Descriptor::VIRT_SIZE - 1);
}
/**
* Insert one atomic translation into this table
*
* \param vo offset of the virtual region represented
* by the translation within the virtual
* region represented by this table
* \param pa base of the physical backing store
* \param size size of the translated region
* \param flags mapping flags
*/
void insert_translation(addr_t vo,
addr_t pa,
size_t size,
Page_flags const & flags)
{
constexpr size_t sz = Descriptor::VIRT_SIZE;
for (unsigned i; (size > 0) && _index_by_vo(i, vo);
size = (size < sz) ? 0 : size - sz,
vo += sz, pa += sz)
{
/* compose new descriptor value */
Small_page::access_t const e =
Small_page::create(flags, pa);
/* check if it is a good idea to override the entry */
assert(!Descriptor::valid(_entries[i]) ||
_entries[i] == e);
/* override entry */
_entries[i] = e;
/* some CPUs need to act on changed translations */
Cpu::translation_added((addr_t)&_entries[i],
sizeof(Descriptor::access_t));
}
}
/**
* Remove translations that overlap with a given virtual region
*
* \param vo region offset within the tables virtual region
* \param size region size
*/
void remove_translation(addr_t vo, size_t size)
{
constexpr size_t sz = Descriptor::VIRT_SIZE;
for (unsigned i; (size > 0) && _index_by_vo(i, vo);
size = (size < sz) ? 0 : size - sz, vo += sz) {
switch (Descriptor::type(_entries[i])) {
case Descriptor::SMALL_PAGE:
{
Descriptor::invalidate(_entries[i]);
}
default: ;
}
}
}
/**
* Does this table solely contain invalid entries
*/
bool empty()
{
for (unsigned i = 0; i <= MAX_INDEX; i++)
if (Descriptor::valid(_entries[i])) return false;
return true;
}
} __attribute__((aligned(1<<Page_table::ALIGNM_LOG2)));
enum { DOMAIN = 0 };
} __attribute__((aligned(1<<Page_table::ALIGNM_LOG2)));
class Genode::Translation_table
{
public:
enum {
SIZE_LOG2 = 14,
SIZE = 1 << SIZE_LOG2,
ALIGNM_LOG2 = SIZE_LOG2,
MAX_COSTS_PER_TRANSLATION = sizeof(Page_table),
MAX_PAGE_SIZE_LOG2 = 20,
MIN_PAGE_SIZE_LOG2 = 12,
};
@ -318,11 +290,8 @@ class Genode::Translation_table
/**
* A first level translation descriptor
*/
struct Descriptor : Register<32>
struct Descriptor : Register<32>, Translation
{
/**
* Descriptor types
*/
enum Type { FAULT, PAGE_TABLE, SECTION };
enum {
@ -344,13 +313,9 @@ class Genode::Translation_table
{
switch (Type_0::get(v)) {
case 0: return FAULT;
case 1: return PAGE_TABLE;
}
switch (Type_1::get(v)) {
case 1: return SECTION;
}
case 1: return PAGE_TABLE; }
if (Type_1::get(v) == 1) { return SECTION; }
return FAULT;
}
@ -360,26 +325,13 @@ class Genode::Translation_table
static void type(access_t & v, Type const t)
{
switch (t) {
case FAULT:
Type_0::set(v, 0);
return;
case PAGE_TABLE:
Type_0::set(v, 1);
return;
case SECTION:
Type_1::set(v, 1);
return;
}
case FAULT: Type_0::set(v, 0); return;
case PAGE_TABLE: Type_0::set(v, 1); return;
case SECTION: Type_1::set(v, 1); return; }
}
/**
* Invalidate descriptor 'v'
*/
static void invalidate(access_t & v) { type(v, FAULT); }
/**
* Return if descriptor 'v' is valid
*/
static bool valid(access_t & v) { return type(v) != FAULT; }
static inline Type align(addr_t vo, addr_t pa, size_t size)
@ -398,14 +350,13 @@ class Genode::Translation_table
struct Pa : Bitfield<10, 22> { }; /* physical base */
/**
* Compose descriptor value
* Return descriptor value for page table 'pt
*/
static access_t create(Page_table * const pt)
{
access_t v = Domain::bits(DOMAIN) |
Pa::masked((addr_t)pt);
Descriptor::type(v, Descriptor::PAGE_TABLE);
return v;
access_t v = Pa::masked((addr_t)pt);
Descriptor::type(v, Descriptor::PAGE_TABLE);
return v;
}
};
@ -414,30 +365,22 @@ class Genode::Translation_table
*/
struct Section : Descriptor
{
struct B : Bitfield<2, 1> { }; /* mem. region attr. */
struct C : Bitfield<3, 1> { }; /* mem. region attr. */
struct Xn : Bitfield<4, 1> { }; /* execute never bit */
struct Domain : Bitfield<5, 4> { }; /* domain */
struct Ap_0 : Bitfield<10, 2> { }; /* access permission */
struct Tex : Bitfield<12, 3> { }; /* mem. region attr. */
struct Ap_1 : Bitfield<15, 1> { }; /* access permission */
struct S : Bitfield<16, 1> { }; /* shared */
struct Ng : Bitfield<17, 1> { }; /* not global */
struct Pa : Bitfield<20, 12> { }; /* physical base */
struct Ap : Bitset_2<Ap_0, Ap_1> { }; /* access permission */
struct B : Bitfield<2, 1> { }; /* mem. region attr. */
struct Xn : Bitfield<4, 1> { }; /* execute never bit */
struct Ap_0 : Bitfield<10, 2> { }; /* access permission */
struct Tex : Bitfield<12, 3> { }; /* mem. region attr. */
struct Ap_1 : Bitfield<15, 1> { }; /* access permission */
struct S : Bitfield<16, 1> { }; /* shared */
struct Ng : Bitfield<17, 1> { }; /* not global */
struct Pa : Bitfield<20, 12> { }; /* physical base */
struct Ap : Bitset_2<Ap_0, Ap_1> { }; /* access permission */
/**
* Compose descriptor value
* Return section descriptor for physical address 'pa' and 'flags'
*/
static access_t create(Page_flags const & flags,
addr_t const pa)
static access_t create(Page_flags const & flags, addr_t const pa)
{
access_t v = access_permission_bits<Section>(flags);
v |= arm_memory_region_attr<Section>(flags);
v |= Domain::bits(DOMAIN);
v |= S::bits(Cpu::is_smp());
v |= Ng::bits(!flags.global);
v |= Pa::masked(pa);
access_t v = _create<Section>(flags, pa);
Descriptor::type(v, Descriptor::SECTION);
return v;
}
@ -451,15 +394,9 @@ class Genode::Translation_table
enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 };
/**
* Get entry index by virtual offset
* Try to get entry index in 'i' for virtual offset 'vo!
*
* \param i is overridden with the resulting index
* \param vo offset within the virtual region represented
* by this table
*
* \retval 0 on success
* \retval <0 if virtual offset couldn't be resolved,
* in this case 'i' reside invalid
* \return wether it was successful
*/
bool _index_by_vo(unsigned & i, addr_t const vo) const
{
@ -478,12 +415,9 @@ class Genode::Translation_table
* \param flags mapping flags
* \param slab second level page slab allocator
*/
void _insert_second_level(unsigned i,
addr_t const vo,
addr_t const pa,
size_t const size,
Page_flags const & flags,
Page_slab * slab)
void _insert_second_level(unsigned i, addr_t const vo, addr_t const pa,
size_t const size, Page_flags const & flags,
Page_slab * const slab)
{
Page_table * pt = 0;
switch (Descriptor::type(_entries[i])) {
@ -499,13 +433,13 @@ class Genode::Translation_table
_entries[i] = Page_table_descriptor::create(pt_phys);
/* some processors need to act on changed translations */
Cpu::translation_added((addr_t)&_entries[i],
sizeof(Descriptor::access_t));
size_t const dsize = sizeof(Descriptor::access_t);
Cpu::translation_added((addr_t)&_entries[i], dsize);
}
case Descriptor::PAGE_TABLE:
{
/* use allocator to retrieve virtual address of page table */
/* use allocator to retrieve virtual addr. of page table */
void * pt_phys = (void*)
Page_table_descriptor::Pa::masked(_entries[i]);
pt = (Page_table *) slab->virt_addr(pt_phys);
@ -514,11 +448,11 @@ class Genode::Translation_table
}
default: assert(0);
};
}
/* insert translation */
pt->insert_translation(vo - Section::Pa::masked(vo),
pa, size, flags);
addr_t const pt_vo = vo - Section::Pa::masked(vo);
pt->insert_translation(pt_vo, pa, size, flags);
}
public:
@ -542,26 +476,21 @@ class Genode::Translation_table
*/
static addr_t max_virt_offset()
{
return (MAX_INDEX << Descriptor::VIRT_SIZE_LOG2)
+ (Descriptor::VIRT_SIZE - 1);
constexpr addr_t base = MAX_INDEX << Descriptor::VIRT_SIZE_LOG2;
return base + (Descriptor::VIRT_SIZE - 1);
}
/**
* Insert translations into this table
*
* \param vo offset of the virtual region represented
* by the translation within the virtual
* region represented by this table
* \param pa base of the physical backing store
* \param size size of the translated region
* \param flags mapping flags
* \param slab second level page slab allocator
* \param vo offset of virt. transl. region in virt. table region
* \param pa base of physical backing store
* \param size size of translated region
* \param f mapping flags
* \param s second level page slab allocator
*/
void insert_translation(addr_t vo,
addr_t pa,
size_t size,
Page_flags const & flags,
Page_slab * slab)
void insert_translation(addr_t vo, addr_t pa, size_t size,
Page_flags const & f, Page_slab * const s)
{
/* check sanity */
assert(!(vo & Page_table::Descriptor::VIRT_OFFSET_MASK) &&
@ -569,8 +498,8 @@ class Genode::Translation_table
for (unsigned i; (size > 0) && _index_by_vo (i, vo);) {
addr_t end = (vo + Descriptor::VIRT_SIZE)
& Descriptor::VIRT_BASE_MASK;
addr_t const ve = (vo + Descriptor::VIRT_SIZE);
addr_t const end = ve & Descriptor::VIRT_BASE_MASK;
/* decide granularity of entry that can be inserted */
switch (Descriptor::align(vo, pa, size)) {
@ -578,29 +507,25 @@ class Genode::Translation_table
case Descriptor::SECTION:
{
/* compose new entry */
Section::access_t const e = Section::create(flags, pa);
/* check if it is a good idea to override the entry */
assert(!Descriptor::valid(_entries[i]) ||
_entries[i] == e);
Section::access_t const e = Section::create(f, pa);
/* override entry */
if (_entries[i] == e) { break; }
assert(!Descriptor::valid(_entries[i]));
_entries[i] = e;
/* some CPUs need to act on changed translations */
Cpu::translation_added((addr_t)&_entries[i],
sizeof(Descriptor::access_t));
constexpr size_t ds = sizeof(Descriptor::access_t);
Cpu::translation_added((addr_t)&_entries[i], ds);
break;
}
default:
{
_insert_second_level(i, vo, pa, min(size, end-vo), flags, slab);
}
_insert_second_level(i, vo, pa, min(size, end - vo), f, s);
};
/* check whether we wrap */
if (end < vo) return;
if (end < vo) { return; }
size_t sz = end - vo;
size = (size > sz) ? size - sz : 0;
@ -623,8 +548,8 @@ class Genode::Translation_table
for (unsigned i; (size > 0) && _index_by_vo(i, vo);) {
addr_t end = (vo + Descriptor::VIRT_SIZE)
& Descriptor::VIRT_BASE_MASK;
constexpr addr_t dbm = Descriptor::VIRT_BASE_MASK;
addr_t const end = (vo + Descriptor::VIRT_SIZE) & dbm;
switch (Descriptor::type(_entries[i])) {
@ -647,11 +572,7 @@ class Genode::Translation_table
break;
}
default:
{
Descriptor::invalidate(_entries[i]);
}
}
default: Descriptor::invalidate(_entries[i]); }
/* check whether we wrap */
if (end < vo) return;

View File

@ -39,79 +39,55 @@ class Genode::Arm_gic_distributor : public Mmio
{
public:
enum { NR_OF_IRQ = 1024 };
/**
* Constructor
*/
Arm_gic_distributor(addr_t const base) : Mmio(base) { }
static constexpr unsigned nr_of_irq = 1024;
/**
* Control register
*/
struct Ctlr : Register<0x000, 32>
{
struct Enable : Bitfield<0,1> { };
};
struct Ctlr : Register<0x000, 32> {
struct Enable : Bitfield<0,1> { }; };
/**
* Controller type register
*/
struct Typer : Register<0x004, 32>
{
struct It_lines_number : Bitfield<0,5> { };
struct Cpu_number : Bitfield<5,3> { };
};
struct Typer : Register<0x004, 32> {
struct It_lines_number : Bitfield<0,5> { }; };
/**
* Interrupt group register
*/
struct Igroupr : Register_array<0x80, 32, NR_OF_IRQ, 1>
{
struct Group_status : Bitfield<0, 1> { };
};
struct Igroupr : Register_array<0x80, 32, nr_of_irq, 1> {
struct Group_status : Bitfield<0, 1> { }; };
/**
* Interrupt set enable registers
*/
struct Isenabler : Register_array<0x100, 32, NR_OF_IRQ, 1, true>
{
struct Set_enable : Bitfield<0, 1> { };
};
struct Isenabler : Register_array<0x100, 32, nr_of_irq, 1, true> {
struct Set_enable : Bitfield<0, 1> { }; };
/**
* Interrupt clear enable registers
*/
struct Icenabler : Register_array<0x180, 32, NR_OF_IRQ, 1, true>
{
struct Clear_enable : Bitfield<0, 1> { };
};
struct Icenabler : Register_array<0x180, 32, nr_of_irq, 1, true> {
struct Clear_enable : Bitfield<0, 1> { }; };
/**
* Interrupt priority level registers
*/
struct Ipriorityr : Register_array<0x400, 32, NR_OF_IRQ, 8>
{
enum { GET_MIN = 0xff };
struct Priority : Bitfield<0, 8> { };
};
struct Ipriorityr : Register_array<0x400, 32, nr_of_irq, 8> {
struct Priority : Bitfield<0, 8> { }; };
/**
* Interrupt processor target registers
*/
struct Itargetsr : Register_array<0x800, 32, NR_OF_IRQ, 8>
{
struct Cpu_targets : Bitfield<0, 8> { };
};
struct Itargetsr : Register_array<0x800, 32, nr_of_irq, 8> {
struct Cpu_targets : Bitfield<0, 8> { }; };
/**
* Interrupt configuration registers
*/
struct Icfgr : Register_array<0xc00, 32, NR_OF_IRQ, 2>
{
struct Edge_triggered : Bitfield<1, 1> { };
};
struct Icfgr : Register_array<0xc00, 32, nr_of_irq, 2> {
struct Edge_triggered : Bitfield<1, 1> { }; };
/**
* Software generated interrupt register
@ -123,27 +99,27 @@ class Genode::Arm_gic_distributor : public Mmio
};
/**
* Minimum supported interrupt priority
* Constructor
*/
Ipriorityr::access_t min_priority()
Arm_gic_distributor(addr_t const base) : Mmio(base) { }
/**
* Return minimum IRQ priority
*/
unsigned min_priority()
{
write<Ipriorityr::Priority>(Ipriorityr::GET_MIN, 0);
write<Ipriorityr::Priority>(~0, 0);
return read<Ipriorityr::Priority>(0);
}
/**
* Maximum supported interrupt priority
* Return highest IRQ number
*/
Ipriorityr::access_t max_priority() { return 0; }
/**
* ID of the maximum supported interrupt
*/
Typer::access_t max_interrupt()
unsigned max_irq()
{
enum { LINE_WIDTH_LOG2 = 5 };
Typer::access_t lnr = read<Typer::It_lines_number>();
return ((lnr + 1) << LINE_WIDTH_LOG2) - 1;
constexpr unsigned line_width_log2 = 5;
Typer::access_t const lnr = read<Typer::It_lines_number>();
return ((lnr + 1) << line_width_log2) - 1;
}
};
@ -151,20 +127,12 @@ class Genode::Arm_gic_cpu_interface : public Mmio
{
public:
/**
* Constructor
*/
Arm_gic_cpu_interface(addr_t const base) : Mmio(base) { }
/**
* Control register
*/
struct Ctlr : Register<0x00, 32>
{
/* Without security extension */
struct Enable : Bitfield<0,1> { };
/* In a secure world */
struct Enable : Bitfield<0,1> { };
struct Enable_grp0 : Bitfield<0,1> { };
struct Enable_grp1 : Bitfield<1,1> { };
struct Fiq_en : Bitfield<3,1> { };
@ -173,74 +141,66 @@ class Genode::Arm_gic_cpu_interface : public Mmio
/**
* Priority mask register
*/
struct Pmr : Register<0x04, 32>
{
struct Priority : Bitfield<0,8> { };
};
struct Pmr : Register<0x04, 32> {
struct Priority : Bitfield<0,8> { }; };
/**
* Binary point register
*/
struct Bpr : Register<0x08, 32>
{
enum { NO_PREEMPTION = 7 };
struct Binary_point : Bitfield<0,3> { };
};
struct Bpr : Register<0x08, 32> {
struct Binary_point : Bitfield<0,3> { }; };
/**
* Interrupt acknowledge register
*/
struct Iar : Register<0x0c, 32, true>
{
struct Irq_id : Bitfield<0,10> { };
};
struct Iar : Register<0x0c, 32, true> {
struct Irq_id : Bitfield<0,10> { }; };
/**
* End of interrupt register
*/
struct Eoir : Register<0x10, 32, true>
{
struct Irq_id : Bitfield<0,10> { };
struct Cpu_id : Bitfield<10,3> { };
};
struct Eoir : Register<0x10, 32, true> {
struct Irq_id : Bitfield<0,10> { }; };
/**
* Constructor
*/
Arm_gic_cpu_interface(addr_t const base) : Mmio(base) { }
};
class Genode::Arm_gic
{
protected:
enum {
MIN_SPI = 32,
SPURIOUS_ID = 1023,
};
typedef Arm_gic_cpu_interface Cpui;
typedef Arm_gic_distributor Distr;
static constexpr unsigned min_spi = 32;
static constexpr unsigned spurious_id = 1023;
Distr _distr;
Cpui _cpui;
unsigned const _max_interrupt;
unsigned const _max_irq;
unsigned _last_request;
/**
* Return inter-processor interrupt of a specific processor
*
* \param processor_id kernel name of targeted processor
* Return inter-processor IRQ of the CPU with kernel name 'cpu_id'
*/
unsigned _ip_interrupt(unsigned const processor_id) const
{
return processor_id + 1;
}
unsigned _ipi(unsigned const cpu_id) const { return cpu_id + 1; }
/**
* Platform specific initialization
*/
void _init();
/**
* Return wether kernel name 'irq_id' addresses a valid IRQ
*/
bool _valid(unsigned const irq_id) const { return irq_id <= _max_irq; }
public:
enum { NR_OF_IRQ = Distr::NR_OF_IRQ };
enum { NR_OF_IRQ = Distr::nr_of_irq };
/**
* Constructor
@ -248,124 +208,83 @@ class Genode::Arm_gic
Arm_gic(addr_t const distr_base, addr_t const cpu_base)
:
_distr(distr_base), _cpui(cpu_base),
_max_interrupt(_distr.max_interrupt()),
_last_request(SPURIOUS_ID)
{
_init();
}
_max_irq(_distr.max_irq()),
_last_request(spurious_id) { _init(); }
/**
* Initialize processor local interface of the controller
* Initialize CPU local interface of the controller
*/
void init_processor_local()
{
/* disable the priority filter */
_cpui.write<Cpui::Pmr::Priority>(_distr.min_priority());
/* disable preemption of interrupt handling by interrupts */
_cpui.write<Cpui::Bpr::Binary_point>(Cpui::Bpr::NO_PREEMPTION);
/* disable preemption of IRQ handling by other IRQs */
_cpui.write<Cpui::Bpr::Binary_point>(~0);
/* enable device */
_cpui.write<Cpui::Ctlr::Enable>(1);
}
/**
* Get the ID of the last interrupt request
* Try to take an IRQ and return wether it was successful
*
* \return True if the request with ID 'i' is treated as accepted
* by the CPU and awaits an subsequently 'finish_request'
* call. Otherwise this returns false and the value of 'i'
* remains useless.
* \param irq_id contains kernel name of taken IRQ on success
*/
bool take_request(unsigned & i)
bool take_request(unsigned & irq_id)
{
_last_request = _cpui.read<Cpui::Iar::Irq_id>();
i = _last_request;
return valid(i);
irq_id = _last_request;
return _valid(irq_id);
}
/**
* Complete the last request that was taken via 'take_request'
* End the last taken IRQ
*/
void finish_request()
{
if (!valid(_last_request)) return;
_cpui.write<Cpui::Eoir>(Cpui::Eoir::Irq_id::bits(_last_request) |
Cpui::Eoir::Cpu_id::bits(0) );
_last_request = SPURIOUS_ID;
if (!_valid(_last_request)) { return; }
_cpui.write<Cpui::Eoir::Irq_id>(_last_request);
_last_request = spurious_id;
}
/**
* Check if 'i' is a valid interrupt request ID at the device
*/
bool valid(unsigned const i) const { return i <= _max_interrupt; }
/**
* Unmask all interrupts
*/
void unmask()
{
for (unsigned i=0; i <= _max_interrupt; i++) {
_distr.write<Distr::Isenabler::Set_enable>(1, i);
}
}
/**
* Unmask interrupt and assign it to a specific processor
* Unmask IRQ and assign it to one CPU
*
* \param interrupt_id kernel name of targeted interrupt
* \param processor_id kernel name of targeted processor
* \param irq_id kernel name of targeted IRQ
* \param cpu_id kernel name of targeted CPU
*/
void unmask(unsigned const interrupt_id, unsigned const processor_id)
void unmask(unsigned const irq_id, unsigned const cpu_id)
{
unsigned const targets = 1 << processor_id;
_distr.write<Distr::Itargetsr::Cpu_targets>(targets, interrupt_id);
_distr.write<Distr::Isenabler::Set_enable>(1, interrupt_id);
unsigned const targets = 1 << cpu_id;
_distr.write<Distr::Itargetsr::Cpu_targets>(targets, irq_id);
_distr.write<Distr::Isenabler::Set_enable>(1, irq_id);
}
/**
* Mask all interrupts
* Mask IRQ with kernel name 'irq_id'
*/
void mask()
{
for (unsigned i=0; i <= _max_interrupt; i++) {
_distr.write<Distr::Icenabler::Clear_enable>(1, i);
}
}
void mask(unsigned const irq_id) {
_distr.write<Distr::Icenabler::Clear_enable>(1, irq_id); }
/**
* Mask specific interrupt
* Return wether an IRQ is inter-processor IRQ of a CPU
*
* \param interrupt_id kernel name of targeted interrupt
* \param irq_id kernel name of the IRQ
* \param cpu_id kernel name of the CPU
*/
void mask(unsigned const interrupt_id)
{
_distr.write<Distr::Icenabler::Clear_enable>(1, interrupt_id);
}
bool is_ip_interrupt(unsigned const irq_id, unsigned const cpu_id) {
return irq_id == _ipi(cpu_id); }
/**
* Wether an interrupt is inter-processor interrupt of a processor
*
* \param interrupt_id kernel name of the interrupt
* \param processor_id kernel name of the processor
* Raise inter-processor IRQ of the CPU with kernel name 'cpu_id'
*/
bool is_ip_interrupt(unsigned const interrupt_id,
unsigned const processor_id)
{
return interrupt_id == _ip_interrupt(processor_id);
}
/**
* Trigger the inter-processor interrupt of a processor
*
* \param processor_id kernel name of the processor
*/
void trigger_ip_interrupt(unsigned const processor_id)
void trigger_ip_interrupt(unsigned const cpu_id)
{
typedef Distr::Sgir Sgir;
Sgir::access_t sgir = 0;
Sgir::Sgi_int_id::set(sgir, _ip_interrupt(processor_id));
Sgir::Cpu_target_list::set(sgir, 1 << processor_id);
Sgir::Sgi_int_id::set(sgir, _ipi(cpu_id));
Sgir::Cpu_target_list::set(sgir, 1 << cpu_id);
_distr.write<Sgir>(sgir);
}
};

View File

@ -146,7 +146,7 @@ class Genode::Cpu : public Arm
Cidr::write(process_id);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init(table));
Ttbcr::write(Ttbcr::init_virt_kernel());
Ttbcr::write(0);
Sctlr::write(Sctlr::init_virt_kernel());
}

View File

@ -18,21 +18,6 @@
/* core includes */
#include <spec/arm/short_translation_table.h>
template <typename T>
static typename T::access_t
Genode::arm_memory_region_attr(Page_flags const & flags)
{
typedef typename T::Tex Tex;
typedef typename T::C C;
typedef typename T::B B;
if (flags.device) { return 0; }
switch (flags.cacheable) {
case CACHED: return Tex::bits(5) | B::bits(1);
case WRITE_COMBINED: return B::bits(1);
case UNCACHED: return Tex::bits(1);
}
return 0;
}
constexpr unsigned Genode::Translation::_device_tex() { return 0; }
#endif /* _TRANSLATION_TABLE_H_ */

View File

@ -166,33 +166,10 @@ class Genode::Arm_v7 : public Arm
*/
struct Nsacr : Register<32>
{
/************************************************
** Coprocessor 0-13 non-secure acccess enable **
************************************************/
struct Cpnsae10 : Bitfield<10, 1> { };
struct Cpnsae11 : Bitfield<11, 1> { };
};
/**
* Translation table base control register
*/
struct Ttbcr : Arm::Ttbcr
{
struct Pd0 : Bitfield<4,1> { }; /* disable walk for TTBR0 */
struct Pd1 : Bitfield<5,1> { }; /* disable walk for TTBR1 */
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return Arm::Ttbcr::init_virt_kernel() |
Pd0::bits(0) |
Pd1::bits(0);
}
};
/**
* System control register
*/
@ -252,9 +229,7 @@ class Genode::Arm_v7 : public Arm
struct Irgn : Bitset_2<Irgn_0, Irgn_1> { }; /* inner cache attr */
/**
* Return initialized value
*
* \param table base of targeted translation table
* Return value initialized with translation table 'table'
*/
static access_t init(addr_t const table)
{
@ -283,7 +258,7 @@ class Genode::Arm_v7 : public Arm
Cidr::write(process_id);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init(table));
Ttbcr::write(Ttbcr::init_virt_kernel());
Ttbcr::write(0);
Sctlr::write(Sctlr::init_virt_kernel());
inval_branch_predicts();
}
@ -317,32 +292,20 @@ class Genode::Arm_v7 : public Arm
******************************/
/**
* Set the exception-vector's base-address for the monitor mode
* software stack.
*
* \param addr address of the exception vector's base
* Set exception-vector's address for monitor mode to 'a'
*/
static inline void mon_exception_entry_at(addr_t const addr)
{
asm volatile ("mcr p15, 0, %[rd], c12, c0, 1" : : [rd] "r" (addr));
}
static void mon_exception_entry_at(addr_t const a) {
asm volatile ("mcr p15, 0, %[rd], c12, c0, 1" : : [rd] "r" (a)); }
/**
* Enable access of co-processors cp10 and cp11 from non-secure mode.
*/
static inline void allow_coprocessor_nonsecure()
{
Nsacr::access_t rd = Nsacr::Cpnsae10::bits(1) |
Nsacr::Cpnsae11::bits(1);
asm volatile ("mcr p15, 0, %[rd], c1, c1, 2" : : [rd] "r" (rd));
}
/**
* Invalidate all predictions about the future control-flow
*/
static void invalidate_control_flow_predictions()
{
asm volatile ("mcr p15, 0, r0, c7, c5, 6");
Nsacr::access_t v = 0;
Nsacr::Cpnsae10::set(v, 1);
Nsacr::Cpnsae11::set(v, 1);
asm volatile ("mcr p15, 0, %[v], c1, c1, 2" : : [v] "r" (v));
}
/**
@ -351,17 +314,14 @@ class Genode::Arm_v7 : public Arm
static void data_synchronization_barrier() { asm volatile ("dsb"); }
/**
* Enable secondary processors that loop on wait-for-event
*
* \param ip initial instruction pointer for secondary processors
* Enable secondary processors with instr. pointer 'ip'
*/
static void start_secondary_processors(void * const ip)
{
if (is_smp()) {
Board::secondary_processors_ip(ip);
data_synchronization_barrier();
asm volatile ("sev\n");
}
if (!is_smp()) { return; }
Board::secondary_processors_ip(ip);
data_synchronization_barrier();
asm volatile ("sev\n");
}
/**
@ -391,18 +351,13 @@ void Genode::Arm::invalidate_data_caches()
}
Genode::Arm::Psr::access_t
Genode::Arm::Psr::init_user_with_trustzone()
Genode::Arm::Psr::access_t Genode::Arm::Psr::init_user_with_trustzone()
{
return M::bits(M::USER) |
T::bits(T::ARM) |
F::bits(0) |
I::bits(1) |
A::bits(1) |
E::bits(E::LITTLE) |
J::bits(J::ARM);
access_t v = 0;
M::set(v, usr);
I::set(v, 1);
A::set(v, 1);
return v;
}
#endif /* _SPEC__ARM_V7__CPU_SUPPORT_H_ */

View File

@ -18,21 +18,6 @@
/* core includes */
#include <spec/arm/short_translation_table.h>
template <typename T>
static typename T::access_t
Genode::arm_memory_region_attr(Page_flags const & flags)
{
typedef typename T::Tex Tex;
typedef typename T::C C;
typedef typename T::B B;
if (flags.device) { return Tex::bits(2); }
switch (flags.cacheable) {
case CACHED: return Tex::bits(5) | B::bits(1);
case WRITE_COMBINED: return B::bits(1);
case UNCACHED: return Tex::bits(1);
}
return 0;
}
constexpr unsigned Genode::Translation::_device_tex() { return 2; }
#endif /* _TRANSLATION_TABLE_H_ */

View File

@ -24,189 +24,90 @@ namespace Genode
class Genode::Pic : public Mmio
{
/**
* Interrupt control register
*/
struct Intcntl : Register<0x0, 32>
{
struct Nm : Bitfield<18,1> /* IRQ mode */
private:
struct Intcntl : Register<0x0, 32> { }; /* IRQ control register */
struct Nimask : Register<0x4, 32> { }; /* normal IRQ mask reg. */
struct Intennum : Register<0x8, 32> { }; /* IRQ enable nr. reg. */
struct Intdisnum : Register<0xc, 32> { }; /* IRQ disable nr. reg. */
struct Intenableh : Register<0x10, 32> { }; /* IRQ enable register */
struct Intenablel : Register<0x14, 32> { }; /* IRQ enable register */
struct Inttypeh : Register<0x18, 32> { }; /* IRQ type register */
struct Inttypel : Register<0x1c, 32> { }; /* IRQ type register */
struct Intsrch : Register<0x48, 32> { }; /* IRQ source register */
struct Intsrcl : Register<0x4c, 32> { }; /* IRQ source register */
struct Nipndh : Register<0x58, 32> { }; /* normal IRQ pending */
struct Nipndl : Register<0x5c, 32> { }; /* normal IRQ pending */
/**
* Normal interrupt priority registers
*/
struct Nipriority : Register_array<0x20, 32, 8, 32> { };
/**
* Normal interrupt vector and status register
*/
struct Nivecsr : Register<0x40, 32>
{
enum { SW_CONTROL = 0 };
struct Nvector : Bitfield<16, 16> { };
};
struct Fiad : Bitfield<19,1> { }; /* FIQ rises prio in arbiter */
struct Niad : Bitfield<20,1> { }; /* IRQ rises prio in arbiter */
struct Fidis : Bitfield<21,1> { }; /* FIQ disable */
struct Nidis : Bitfield<22,1> { }; /* IRQ disable */
struct Abfen : Bitfield<24,1> { }; /* if ABFLAG is sticky */
struct Abflag : Bitfield<25,1> { }; /* rise prio in bus arbiter */
static access_t init_value()
{
return Nm::bits(Nm::SW_CONTROL) |
Fiad::bits(0) |
Niad::bits(0) |
Fidis::bits(0) |
Nidis::bits(0) |
Abfen::bits(0) |
Abflag::bits(0);
}
};
/**
* Normal interrupt mask register
*/
struct Nimask : Register<0x4, 32>
{
enum { NONE_MASKED = ~0 };
};
/**
* Interrupt enable number register
*/
struct Intennum : Register<0x8, 32>
{
struct Enable : Bitfield<0,6> { };
};
/**
* Interrupt disable number register
*/
struct Intdisnum : Register<0xc, 32>
{
struct Disable : Bitfield<0,6> { };
};
/**
* Interrupt enable register
*/
struct Intenableh : Register<0x10, 32> { };
struct Intenablel : Register<0x14, 32> { };
/**
* Interrupt type register
*/
struct Inttype { enum { ALL_IRQS = 0 }; };
struct Inttypeh : Register<0x18, 32> { };
struct Inttypel : Register<0x1c, 32> { };
/**
* Normal interrupt priority registers
*/
struct Nipriority : Register_array<0x20, 32, 8, 32>
{
enum { ALL_LOWEST = 0 };
};
/**
* Interrupt source registers
*/
struct Intsrch : Register<0x48, 32> { };
struct Intsrcl : Register<0x4c, 32> { };
/**
* Normal interrupt pending registers
*/
struct Nipndh : Register<0x58, 32> { };
struct Nipndl : Register<0x5c, 32> { };
/**
* Normal interrupt vector and status register
*/
struct Nivecsr : Register<0x40, 32>
{
struct Nvector : Bitfield<16, 16> { };
};
/**
* Validate request number 'i'
*/
bool _valid(unsigned const i) const { return i < NR_OF_IRQ; }
public:
enum { NR_OF_IRQ = 64 };
/**
* Constructor, enables all interrupts
* Constructor
*/
Pic() : Mmio(Board::AVIC_MMIO_BASE)
{
mask();
write<Nimask>(Nimask::NONE_MASKED);
write<Intcntl>(Intcntl::init_value());
write<Inttypeh>(Inttype::ALL_IRQS);
write<Inttypel>(Inttype::ALL_IRQS);
for (unsigned i = 0; i < Nipriority::ITEMS; i++)
write<Nipriority>(Nipriority::ALL_LOWEST, i);
write<Intenablel>(0);
write<Intenableh>(0);
write<Nimask>(~0);
write<Intcntl>(0);
write<Inttypeh>(0);
write<Inttypel>(0);
for (unsigned i = 0; i < Nipriority::ITEMS; i++) {
write<Nipriority>(0, i); }
}
/**
* Initialize processor local interface of the controller
*/
void init_processor_local() { }
/**
* Receive a pending request number 'i'
* Try to receive an IRQ in 'i' and return wether it was successful
*/
bool take_request(unsigned & i)
{
i = read<Nivecsr::Nvector>();
return valid(i) ? true : false;
return _valid(i);
}
/**
* Finish the last taken request
* Unmask IRQ 'i'
*/
void finish_request() {
/* requests disappear by source retraction or masking */ }
void unmask(unsigned const i, unsigned) {
if (_valid(i)) { write<Intennum>(i); } }
/**
* Validate request number 'i'
* Mask IRQ 'i'
*/
bool valid(unsigned const i) const {
return i < NR_OF_IRQ; }
void mask(unsigned const i) { if (i < NR_OF_IRQ) write<Intdisnum>(i); }
/**
* Mask all interrupts
* Return wether IRQ 'irq_id' is inter-processor IRQ of CPU 'cpu_id'
*/
void mask()
{
write<Intenablel>(0);
write<Intenableh>(0);
}
bool is_ip_interrupt(unsigned, unsigned) { return false; }
/**
* Unmask interrupt
*
* \param interrupt_id kernel name of targeted interrupt
*/
void unmask(unsigned const interrupt_id, unsigned)
{
if (interrupt_id < NR_OF_IRQ) {
write<Intennum>(interrupt_id);
}
}
/*************
** Dummies **
*************/
/**
* Mask interrupt 'i'
*/
void mask(unsigned const i) {
if (i < NR_OF_IRQ) write<Intdisnum>(i); }
/**
* Wether an interrupt is inter-processor interrupt of a processor
*
* \param interrupt_id kernel name of the interrupt
* \param processor_id kernel name of the processor
*/
bool is_ip_interrupt(unsigned const interrupt_id,
unsigned const processor_id)
{
return false;
}
/**
* Trigger the inter-processor interrupt of a processor
*
* \param processor_id kernel name of the processor
*/
void trigger_ip_interrupt(unsigned const processor_id) { }
void init_processor_local() { }
void trigger_ip_interrupt(unsigned) { }
void finish_request() { /* done by source retraction or masking */ }
};
namespace Kernel { class Pic : public Genode::Pic { }; }

View File

@ -46,73 +46,40 @@ class Genode::Pic : public Mmio
struct Nsen_mask : Bitfield<31,1> { };
};
struct Priomask : Register<0xc, 32>
{
struct Mask : Bitfield<0,8> { };
};
struct Syncctrl : Register<0x10, 32>
{
struct Syncmode : Bitfield<0,2> { };
};
struct Dsmint : Register<0x14, 32>
{
struct Dsm : Bitfield<0,1> { };
};
/**
* Priority mask register
*/
struct Priomask : Register<0xc, 32> {
struct Mask : Bitfield<0,8> { }; };
/**
* Interrupt security registers
*/
struct Intsec : Register_array<0x80, 32, NR_OF_IRQ, 1>
{
struct Nonsecure : Bitfield<0, 1> { };
};
struct Intsec : Register_array<0x80, 32, NR_OF_IRQ, 1> {
struct Nonsecure : Bitfield<0, 1> { }; };
/**
* Interrupt set enable registers
*/
struct Enset : Register_array<0x100, 32, NR_OF_IRQ, 1, true>
{
struct Set_enable : Bitfield<0, 1> { };
};
struct Enset : Register_array<0x100, 32, NR_OF_IRQ, 1, true> {
struct Set_enable : Bitfield<0, 1> { }; };
/**
* Interrupt clear enable registers
*/
struct Enclear : Register_array<0x180, 32, NR_OF_IRQ, 1, true>
{
struct Clear_enable : Bitfield<0, 1> { };
};
struct Enclear : Register_array<0x180, 32, NR_OF_IRQ, 1, true> {
struct Clear_enable : Bitfield<0, 1> { }; };
/**
* Interrupt priority level registers
*/
struct Priority : Register_array<0x400, 32, NR_OF_IRQ, 8>
{
enum { MIN_PRIO = 0xff };
};
/**
* Pending registers
*/
struct Pndr : Register_array<0xd00, 32, NR_OF_IRQ, 1>
{
struct Pending : Bitfield<0, 1> { };
};
struct Priority : Register_array<0x400, 32, NR_OF_IRQ, 8> { };
/**
* Highest interrupt pending registers
*/
struct Hipndr : Register_array<0xd80, 32, NR_OF_IRQ, 1, true>
{
struct Pending : Bitfield<0, 1> { };
};
/**
* Maximum supported interrupt priority
*/
unsigned _max_priority() { return 255; }
struct Hipndr : Register_array<0xd80, 32, NR_OF_IRQ, 1, true> {
struct Pending : Bitfield<0, 1> { }; };
/**
* Initializes security extension if needed
@ -131,104 +98,66 @@ class Genode::Pic : public Mmio
write<Enclear::Clear_enable>(1, i);
}
write<Priomask::Mask>(0x1f);
write<Intctrl>(Intctrl::Enable::bits(1) |
Intctrl::Nsen::bits(1) |
Intctrl::Nsen_mask::bits(1));
Intctrl::access_t v = 0;
Intctrl::Enable::set(v, 1);
Intctrl::Nsen::set(v, 1);
Intctrl::Nsen_mask::set(v, 1);
write<Intctrl>(v);
_init_security_ext();
}
/**
* Mark interrupt unsecure
*
* \param i targeted interrupt
* Mark interrupt 'i' unsecure
*/
void unsecure(unsigned const i);
/**
* Mark interrupt secure
*
* \param i targeted interrupt
* Mark interrupt 'i' secure
*/
void secure(unsigned const i);
/**
* Initialize processor local interface of the controller
*/
void init_processor_local() { }
/**
* Receive a pending request number 'i'
*/
bool take_request(unsigned & i)
{
for (unsigned j = 0; j < NR_OF_IRQ; j++) {
if (read<Hipndr::Pending>(j)) {
i = j;
return true;
}
if (!read<Hipndr::Pending>(j)) { continue; }
i = j;
return true;
}
return false;
}
/**
* Finish the last taken request
*/
void finish_request() { }
/**
* Validate request number 'i'
*/
bool valid(unsigned const i) const {
return i < NR_OF_IRQ; }
bool valid(unsigned const i) const { return i < NR_OF_IRQ; }
/**
* Mask all interrupts
* Unmask interrupt 'i'
*/
void mask()
{
for (unsigned i=0; i < NR_OF_IRQ; i++)
write<Enclear::Clear_enable>(1, i);
}
/**
* Unmask interrupt
*
* \param interrupt_id kernel name of targeted interrupt
*/
void unmask(unsigned const interrupt_id, unsigned)
{
if (interrupt_id < NR_OF_IRQ) {
write<Enset::Set_enable>(1, interrupt_id);
}
}
void unmask(unsigned const i, unsigned) {
if (valid(i)) { write<Enset::Set_enable>(1, i); } }
/**
* Mask interrupt 'i'
*/
void mask(unsigned const i)
{
if (i < NR_OF_IRQ)
write<Enclear::Clear_enable>(1, i);
}
void mask(unsigned const i) {
if (valid(i)) { write<Enclear::Clear_enable>(1, i); } }
/**
* Wether an interrupt is inter-processor interrupt of a processor
*
* \param interrupt_id kernel name of the interrupt
* \param processor_id kernel name of the processor
*/
bool is_ip_interrupt(unsigned const interrupt_id,
unsigned const processor_id)
{
return false;
}
bool is_ip_interrupt(unsigned, unsigned) { return false; }
/**
* Trigger the inter-processor interrupt of a processor
*
* \param processor_id kernel name of the processor
*/
void trigger_ip_interrupt(unsigned const processor_id) { }
/*************
** Dummies **
*************/
void trigger_ip_interrupt(unsigned) { }
void init_processor_local() { }
void finish_request() { }
};
namespace Kernel { class Pic : public Genode::Pic { }; }

View File

@ -50,29 +50,29 @@ namespace Genode
struct Aux : Register<0x104, 32>
{
struct Associativity : Bitfield<16,1> {
enum { WAY_8, WAY_16 }; };
struct Way_size : Bitfield<17,3> {
enum { SZ_64KB = 0x3 }; };
struct Share_override : Bitfield<22,1> {};
struct Reserved : Bitfield<25,1> {};
struct Ns_lockdown : Bitfield<26,1> {};
struct Ns_irq_ctrl : Bitfield<27,1> {};
struct Data_prefetch : Bitfield<28,1> {};
struct Inst_prefetch : Bitfield<29,1> {};
struct Early_bresp : Bitfield<30,1> {};
struct Associativity : Bitfield<16,1> { };
struct Way_size : Bitfield<17,3> { };
struct Share_override : Bitfield<22,1> { };
struct Reserved : Bitfield<25,1> { };
struct Ns_lockdown : Bitfield<26,1> { };
struct Ns_irq_ctrl : Bitfield<27,1> { };
struct Data_prefetch : Bitfield<28,1> { };
struct Inst_prefetch : Bitfield<29,1> { };
struct Early_bresp : Bitfield<30,1> { };
static access_t init_value()
{
return Associativity::bits(Associativity::WAY_16) |
Way_size::bits(Way_size::SZ_64KB) |
Share_override::bits(1) |
Reserved::bits(1) |
Ns_lockdown::bits(1) |
Ns_irq_ctrl::bits(1) |
Data_prefetch::bits(1) |
Inst_prefetch::bits(1) |
Early_bresp::bits(1);
access_t v = 0;
Associativity::set(v, 1);
Way_size::set(v, 3);
Share_override::set(v, 1);
Reserved::set(v, 1);
Ns_lockdown::set(v, 1);
Ns_irq_ctrl::set(v, 1);
Data_prefetch::set(v, 1);
Inst_prefetch::set(v, 1);
Early_bresp::set(v, 1);
return v;
}
};

View File

@ -38,7 +38,7 @@ class Genode::Pic : public Arm_gic
Cpu::PL390_CPU_MMIO_BASE)
{
/* configure every shared peripheral interrupt */
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++) {
for (unsigned i = min_spi; i <= _max_interrupt; i++) {
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
_distr.write<Distr::Ipriorityr::Priority>(0, i);
_distr.write<Distr::Itargetsr::Cpu_targets>(0xff, i);
@ -55,7 +55,7 @@ class Genode::Pic : public Arm_gic
_cpui.write<Cpui::Ctlr>(ctlr);
/* use whole band of prios */
_cpui.write<Cpui::Bpr::Binary_point>(Cpui::Bpr::NO_PREEMPTION);
_cpui.write<Cpui::Bpr::Binary_point>(~0);
/* enable device */
_distr.write<Distr::Ctlr>(Distr::Ctlr::Enable::bits(1));

View File

@ -246,7 +246,6 @@ extern "C" void init_kernel_multiprocessor()
/* synchronize data view of all processors */
Processor::invalidate_data_caches();
Processor::invalidate_instr_caches();
Processor::invalidate_control_flow_predictions();
Processor::data_synchronization_barrier();
/* initialize processor in physical mode */

View File

@ -22,10 +22,9 @@ void Arm_gic::_init()
_distr.write<Distr::Ctlr::Enable>(0);
/* configure every shared peripheral interrupt */
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++)
{
for (unsigned i = min_spi; i <= _max_irq; i++) {
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
_distr.write<Distr::Ipriorityr::Priority>(_distr.max_priority(), i);
_distr.write<Distr::Ipriorityr::Priority>(0, i);
}
/* enable device */
_distr.write<Distr::Ctlr::Enable>(1);

View File

@ -33,9 +33,11 @@ struct Pmcr : Register<32>
static access_t enable_and_reset()
{
return E::bits(1) |
P::bits(1) |
C::bits(1);
access_t v = 0;
E::set(v, 1);
P::set(v, 1);
C::set(v, 1);
return v;
}
static access_t read()
@ -45,10 +47,8 @@ struct Pmcr : Register<32>
return v;
}
static void write(access_t const v)
{
asm volatile("mcr p15, 0, %[v], c15, c12, 0" :: [v]"r"(v) : );
}
static void write(access_t const v) {
asm volatile("mcr p15, 0, %[v], c15, c12, 0" :: [v]"r"(v) : ); }
};
@ -57,12 +57,7 @@ struct Pmcr : Register<32>
*/
struct Sysvalcntrr : Register<32>
{
struct Resetcntr : Bitfield<0,1> { }; /* reset all counter */
static access_t reset_counter()
{
return Resetcntr::bits(0);
}
static access_t reset_counter() { return 0; }
static access_t read()
{
@ -71,10 +66,8 @@ struct Sysvalcntrr : Register<32>
return v;
}
static void write(access_t const v)
{
asm volatile("mcr p15, 0, %[v], c15, c12, 1" :: [v]"r"(v) : );
}
static void write(access_t const v) {
asm volatile("mcr p15, 0, %[v], c15, c12, 1" :: [v]"r"(v) : ); }
};
@ -85,10 +78,7 @@ struct Accvalctlr : Register<32>
{
struct V : Bitfield<0,1> { }; /* enable access in user-mode */
static access_t enable_user_access()
{
return V::bits(1);
}
static access_t enable_user_access() { return V::bits(1); }
static access_t read()
{
@ -97,18 +87,16 @@ struct Accvalctlr : Register<32>
return v;
}
static void write(access_t const v)
{
asm volatile("mcr p15, 0, %[v], c15, c9, 0" :: [v]"r"(v) : );
}
static void write(access_t const v) {
asm volatile("mcr p15, 0, %[v], c15, c9, 0" :: [v]"r"(v) : ); }
};
void Kernel::Perf_counter::enable()
{
/* enable counters and disable overflow interrupt. */
Pmcr::access_t v = Pmcr::enable_and_reset() |
Pmcr::D::bits(1); /* count every 64 cycles */
Pmcr::access_t v = Pmcr::enable_and_reset();
Pmcr::D::set(v, 1); /* count every 64 cycles */
Pmcr::write(v);
Sysvalcntrr::write(Sysvalcntrr::reset_counter());

View File

@ -33,9 +33,11 @@ struct Pmcr : Register<32>
static access_t enable_and_reset()
{
return E::bits(1) |
P::bits(1) |
C::bits(1);
access_t v = 0;
E::set(v, 1);
P::set(v, 1);
C::set(v, 1);
return v;
}
static access_t read()
@ -45,10 +47,8 @@ struct Pmcr : Register<32>
return v;
}
static void write(access_t const v)
{
asm volatile("mcr p15, 0, %[v], c9, c12, 0" :: [v]"r"(v) : );
}
static void write(access_t const v) {
asm volatile("mcr p15, 0, %[v], c9, c12, 0" :: [v]"r"(v) : ); }
};
@ -57,15 +57,17 @@ struct Pmcr : Register<32>
*/
struct Pmintenclr : Register<32>
{
struct C : Bitfield<31,1> { }; /* disable cycle counter overflow interrupt request */
struct P0 : Bitfield<0,1> { }; /* disable pmc0 overflow interrupt request */
struct P1 : Bitfield<1,1> { }; /* disable pmc1 overflow interrupt reuqest */
struct C : Bitfield<31,1> { }; /* disable cycle counter overflow IRQ */
struct P0 : Bitfield<0,1> { }; /* disable pmc0 overflow IRQ */
struct P1 : Bitfield<1,1> { }; /* disable pmc1 overflow IRQ */
static access_t disable_overflow_intr()
{
return C::bits(1) |
P0::bits(1) |
P1::bits(1);
access_t v = 0;
C::set(v, 1) ;
P0::set(v, 1);
P1::set(v, 1);
return v;
}
static access_t read()
@ -75,10 +77,8 @@ struct Pmintenclr : Register<32>
return v;
}
static void write(access_t const v)
{
asm volatile("mcr p15, 0, %[v], c9, c14, 2" :: [v]"r"(v) : );
}
static void write(access_t const v) {
asm volatile("mcr p15, 0, %[v], c9, c14, 2" :: [v]"r"(v) : ); }
};
@ -95,11 +95,13 @@ struct Pmcntenset : Register<32>
static access_t enable_counter()
{
return C::bits(1) |
P0::bits(1) |
P1::bits(1) |
P2::bits(1) |
P3::bits(1);
access_t v = 0;
C::set(v, 1);
P0::set(v, 1);
P1::set(v, 1);
P2::set(v, 1);
P3::set(v, 1);
return v;
}
static access_t read()
@ -109,10 +111,8 @@ struct Pmcntenset : Register<32>
return v;
}
static void write(access_t const v)
{
asm volatile("mcr p15, 0, %0, c9, c12, 1" :: [v]"r"(v) : );
}
static void write(access_t const v) {
asm volatile("mcr p15, 0, %0, c9, c12, 1" :: [v]"r"(v) : ); }
};
@ -127,9 +127,11 @@ struct Pmovsr : Register<32>
static access_t clear_overflow_flags()
{
return C::bits(1) |
P0::bits(1) |
P1::bits(1);
access_t v = 0;
C::set(v, 1);
P0::set(v, 1);
P1::set(v, 1);
return v;
}
static access_t read()
@ -139,10 +141,8 @@ struct Pmovsr : Register<32>
return v;
}
static void write(access_t const v)
{
asm volatile("mcr p15, 0, %0, c9, c12, 3" :: [v]"r"(v) : );
}
static void write(access_t const v) {
asm volatile("mcr p15, 0, %0, c9, c12, 3" :: [v]"r"(v) : ); }
};
@ -151,12 +151,9 @@ struct Pmovsr : Register<32>
*/
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()
{
return En::bits(1);
}
static access_t enable() { return En::bits(1); }
static access_t read()
{
@ -165,10 +162,8 @@ struct Pmuseren : Register<32>
return v;
}
static void write(access_t const v)
{
asm volatile("mcr p15, 0, %0, c9, c14, 0" :: [v]"r"(v) : );
}
static void write(access_t const v) {
asm volatile("mcr p15, 0, %0, c9, c14, 0" :: [v]"r"(v) : ); }
};

View File

@ -1,6 +1,7 @@
/*
* \brief Programmable interrupt controller for core
* \author Martin stein
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2011-10-26
*/
@ -19,22 +20,25 @@ using namespace Genode;
void Arm_gic::_init()
{
/* configure every shared peripheral interrupt */
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++) {
for (unsigned i = min_spi; i <= _max_irq; i++) {
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
_distr.write<Distr::Ipriorityr::Priority>(0, i);
_distr.write<Distr::Itargetsr::Cpu_targets>(0xff, i);
_distr.write<Distr::Itargetsr::Cpu_targets>(~0, i);
}
/* disable the priority filter */
_cpui.write<Cpui::Pmr::Priority>(0xff);
_cpui.write<Cpui::Pmr::Priority>(~0);
/* signal secure IRQ via FIQ interface */
_cpui.write<Cpui::Ctlr>(Cpui::Ctlr::Enable_grp0::bits(1) |
Cpui::Ctlr::Enable_grp1::bits(1) |
Cpui::Ctlr::Fiq_en::bits(1));
typedef Cpui::Ctlr Ctlr;
Ctlr::access_t v = 0;
Ctlr::Enable_grp0::set(v, 1);
Ctlr::Enable_grp1::set(v, 1);
Ctlr::Fiq_en::set(v, 1);
_cpui.write<Ctlr>(v);
/* use whole band of prios */
_cpui.write<Cpui::Bpr::Binary_point>(Cpui::Bpr::NO_PREEMPTION);
_cpui.write<Cpui::Bpr::Binary_point>(~0);
/* enable device */
_distr.write<Distr::Ctlr>(Distr::Ctlr::Enable::bits(1));