hw: enable SMP for ARM Cortex A9

This commit enables multi-processing for all Cortex A9 SoCs we currently
support. Moreover, it thereby enables the L2 cache for i.MX6 that was not
enabled until now. However, the QEMU variants hw_pbxa9 and hw_zynq still
only use 1 core, because the busy cpu synchronization used when initializing
multiple Cortex A9 cores leads to horrible boot times on QEMU.

During this work the CPU initialization in general was reworked. From now
on lots of hardware specifics were put into the 'spec' specific files, some
generic hook functions and abstractions thereby were eliminated. This
results to more lean implementations for instance on non-SMP platforms,
or in the x86 case where cache maintainance is a non-issue.

Due to the fact that memory/cache coherency and SMP are closely coupled
on ARM Cortex A9 this commit combines so different aspects.

Fix #1312
Fix #1807
This commit is contained in:
Stefan Kalkowski 2016-01-11 11:02:52 +01:00 committed by Christian Helmuth
parent 2b2007bc3f
commit 7aff1895bf
86 changed files with 1590 additions and 1028 deletions

View File

@ -1,6 +1,7 @@
#
# \brief Build config for Genodes core process
# \author Martin Stein
# \author Stefan Kalkowski
# \date 2012-10-04
#
@ -8,11 +9,11 @@
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_v6
# add C++ sources
SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/arm_v6/cpu.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += spec/arm/kernel/thread_update_pd.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += kernel/kernel.cc
# add assembly sources

View File

@ -8,7 +8,7 @@
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_v7/virtualization
# add C++ sources
SRC_CC += spec/arndale/board.cc
SRC_CC += spec/arndale/cpu.cc
SRC_CC += spec/arndale/pic.cc
SRC_CC += spec/arndale/platform_services.cc
SRC_CC += spec/arm_v7/kernel/vm_thread.cc

View File

@ -7,15 +7,16 @@
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a15
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_gic
INC_DIR += $(REP_DIR)/src/core/include/spec/smp
# add C++ sources
SRC_CC += spec/cortex_a15/cpu.cc
SRC_CC += spec/arm_v7/smp/kernel/cpu.cc
SRC_CC += spec/smp/kernel/kernel.cc
SRC_CC += spec/cortex_a15/kernel/cpu.cc
SRC_CC += spec/arm/smp/kernel/thread_update_pd.cc
SRC_CC += spec/arm/smp/kernel/cpu.cc
# add assembler sources
SRC_S += spec/arm/smp/kernel/crt0.s
# include less specific configuration
include $(REP_DIR)/lib/mk/spec/smp/core.inc
include $(REP_DIR)/lib/mk/spec/arm_v7/core.inc

View File

@ -8,9 +8,10 @@
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a8
# add C++ sources
SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/cortex_a8/cpu.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += spec/arm/kernel/thread_update_pd.cc
SRC_CC += kernel/kernel.cc
# include less specific configuration

View File

@ -9,12 +9,17 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a9
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_gic
# add C++ sources
SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += spec/cortex_a9/kernel/cpu.cc
SRC_CC += spec/cortex_a9/cpu.cc
SRC_CC += spec/arm/smp/kernel/thread_update_pd.cc
SRC_CC += spec/arm/smp/kernel/cpu.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += kernel/kernel.cc
# add Assembler sources
SRC_S += spec/arm/smp/kernel/crt0.s
# include less specific configuration
include $(REP_DIR)/lib/mk/spec/smp/core.inc
include $(REP_DIR)/lib/mk/spec/arm_v7/core.inc

View File

@ -5,11 +5,11 @@
#
# add C++ sources
SRC_CC += spec/exynos5/board.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += platform_services.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/cortex_a15/cpu_init.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += platform_services.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/spec/exynos5/core.inc

View File

@ -12,6 +12,7 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/pl011
# add C++ sources
SRC_CC += platform_services.cc
SRC_CC += spec/pbxa9/platform_support.cc
SRC_CC += spec/pbxa9/board.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/spec/cortex_a9/core.inc

View File

@ -0,0 +1,12 @@
#
# \brief Build config for Genodes core process
# \author Stefan Kalkowski
# \date 2016-01-04
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/smp
# add C++ sources
SRC_CC += spec/smp/kernel/kernel.cc
SRC_CC += spec/smp/kernel/cpu.cc

View File

@ -11,8 +11,10 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/x86
# add C++ sources
SRC_CC += kernel/kernel.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/x86/platform_support.cc
SRC_CC += spec/x86/kernel/pd.cc
SRC_CC += spec/x86/kernel/cpu.cc
SRC_CC += spec/x86/kernel/thread.cc
SRC_CC += spec/x86/platform_support.cc
SRC_CC += spec/x86/cpu.cc
SRC_CC += spec/x86/bios_data_area.cc
SRC_CC += spec/x86/io_port_session_component.cc

View File

@ -8,9 +8,9 @@
SRC_S += spec/x86_64/kernel/crt0_translation_table.s
# add C++ sources
SRC_CC += spec/x86/kernel/thread.cc
SRC_CC += spec/x86/kernel/cpu.cc
SRC_CC += spec/x86/pic.cc
SRC_CC += spec/x86/kernel/cpu_exception.cc
SRC_CC += spec/x86/kernel/thread_exception.cc
SRC_CC += spec/x86_64/platform_support.cc
# include less specific configuration

View File

@ -11,8 +11,8 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/x86_64/muen
SRC_S += spec/x86_64/muen/kernel/crt0_translation_table.s
# add C++ sources
SRC_CC += spec/x86_64/muen/kernel/thread.cc
SRC_CC += spec/x86_64/muen/kernel/cpu.cc
SRC_CC += spec/x86_64/muen/kernel/cpu_exception.cc
SRC_CC += spec/x86_64/muen/kernel/thread_exception.cc
SRC_CC += spec/x86_64/muen/platform_support.cc
SRC_CC += spec/x86_64/muen/sinfo.cc

View File

@ -8,7 +8,7 @@
SPECS += hw panda
# configure multiprocessor mode
NR_OF_CPUS = 1
NR_OF_CPUS = 2
# set address where to link the text segment at
LD_TEXT_ADDR ?= 0x81000000

View File

@ -287,8 +287,9 @@ class Kernel::Cpu : public Genode::Cpu,
*
* \param pic interrupt controller object
* \param core_pd core's pd object
* \param board object encapsulating board specifics
*/
void init(Pic &pic, Kernel::Pd &core_pd);
void init(Pic &pic, Kernel::Pd &core_pd, Genode::Board & board);
/**
* Raise the IPI of the CPU

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
* Copyright (C) 2013-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -16,6 +16,7 @@
#define _KERNEL__KERNEL_H_
#include <pic.h>
#include <board.h>
/**
* Main routine of every kernel pass
@ -26,11 +27,10 @@ extern "C" void kernel();
namespace Kernel {
class Pd;
class Mode_transition_control;
Pd * core_pd();
Mode_transition_control * mtc();
Pic * pic();
Pd * core_pd();
Pic * pic();
Genode::Board & board();
}
#endif /* _KERNEL__KERNEL_H_ */

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -20,9 +20,12 @@
#include <cpu/cpu_state.h>
/* local includes */
#include <kernel/kernel.h>
#include <board.h>
#include <util.h>
namespace Kernel { class Pd; }
namespace Genode
{
/**
@ -30,6 +33,8 @@ namespace Genode
*/
class Arm;
class Cpu_lazy_state;
typedef Genode::uint64_t sizet_arithm_t;
}
@ -75,6 +80,7 @@ class Genode::Arm
struct Sctlr : Register<32>
{
struct M : Bitfield<0,1> { }; /* enable MMU */
struct A : Bitfield<1,1> { }; /* enable alignment checks */
struct C : Bitfield<2,1> { }; /* enable data cache */
struct I : Bitfield<12,1> { }; /* enable instruction caches */
struct V : Bitfield<13,1> { }; /* select exception entry */
@ -89,20 +95,26 @@ class Genode::Arm
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %0, c1, c0, 0" :: "r" (v) : ); }
/**
* Do initialization that is common on value 'v'
*/
static void init_common(access_t & v)
static void init()
{
C::set(v, 1);
I::set(v, 1);
access_t v = read();
/* disable alignment checks */
A::set(v, 0);
/* set exception vector to 0xffff0000 */
V::set(v, 1);
write(v);
}
/**
* Do initialization for virtual mode in kernel on value 'v'
*/
static void init_virt_kernel(access_t & v) { M::set(v, 1); }
static void enable_mmu_and_caches()
{
access_t v = read();
C::set(v, 1);
I::set(v, 1);
M::set(v, 1);
write(v);
}
};
/**
@ -162,8 +174,8 @@ class Genode::Arm
{
access_t v = Ba::masked((addr_t)table);
Rgn::set(v, CACHEABLE);
S::set(v, Board::is_smp() ? 1 : 0);
if (Board::is_smp()) Irgn::set(v, CACHEABLE);
S::set(v, Kernel::board().is_smp() ? 1 : 0);
if (Kernel::board().is_smp()) Irgn::set(v, CACHEABLE);
else C::set(v, 1);
return v;
}
@ -473,54 +485,42 @@ class Genode::Arm
/**
* Invalidate all entries of all instruction caches
*/
__attribute__((always_inline)) static void invalidate_instr_caches() {
void invalidate_instr_cache() {
asm volatile ("mcr p15, 0, %0, c7, c5, 0" :: "r" (0) : ); }
/**
* Flush all entries of all data caches
*/
static void flush_data_caches();
void clean_invalidate_data_cache();
/**
* Invalidate all entries of all data caches
* Switch on MMU and caches
*
* \param pd kernel's pd object
*/
static void invalidate_data_caches();
/**
* Flush all caches
*/
static void flush_caches()
{
flush_data_caches();
invalidate_instr_caches();
}
void enable_mmu_and_caches(Kernel::Pd & pd);
/**
* 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, %0, c8, c7, 2" :: "r" (pid) : );
}
void invalidate_tlb_by_pid(unsigned const pid) {
asm volatile ("mcr p15, 0, %0, c8, c7, 2" :: "r" (pid) : ); }
/**
* Invalidate all TLB entries
*/
static void flush_tlb()
{
flush_caches();
asm volatile ("mcr p15, 0, %0, c8, c7, 0" :: "r" (0) : );
}
void invalidate_tlb() {
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);
/**
* Flush data-cache entries for virtual region ['base', 'base + size')
* Clean and invalidate data-cache for virtual region
* 'base' - 'base + size'
*/
static void
flush_data_caches_by_virt_region(addr_t base, size_t const size)
void clean_invalidate_data_cache_by_virt_region(addr_t base,
size_t const size)
{
addr_t const top = base + size;
base &= line_align_mask;
@ -528,15 +528,34 @@ class Genode::Arm
}
/**
* Bin instr.-cache entries for virtual region ['base', 'base + size')
* Invalidate instruction-cache for virtual region
* 'base' - 'base + size'
*/
static void
invalidate_instr_caches_by_virt_region(addr_t base, size_t const size)
void invalidate_instr_cache_by_virt_region(addr_t base,
size_t const size)
{
addr_t const top = base + size;
base &= line_align_mask;
for (; base < top; base += line_size) { Icimvau::write(base); }
}
/*************
** Dummies **
*************/
void prepare_proceeding(Cpu_lazy_state *, Cpu_lazy_state *) { }
bool retry_undefined_instr(Cpu_lazy_state *) { return false; }
/**
* Return kernel name of the executing CPU
*/
static unsigned executing_id() { return 0; }
/**
* Return kernel name of the primary CPU
*/
static unsigned primary_id() { return 0; }
};
#endif /* _SPEC__ARM__CPU_SUPPORT_H_ */

View File

@ -7,7 +7,7 @@
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
* Copyright (C) 2014-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -24,62 +24,69 @@ namespace Arm
struct Pl310;
}
/**
* L2 outer cache controller
*/
struct Arm::Pl310 : Genode::Mmio
class Arm::Pl310 : public Genode::Mmio
{
struct Control : Register <0x100, 32>
{
struct Enable : Bitfield<0,1> { };
};
protected:
struct Aux : Register<0x104, 32>
{
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> { };
};
struct Control : Register <0x100, 32>
{
struct Enable : Bitfield<0,1> { };
};
struct Irq_mask : Register <0x214, 32> { };
struct Irq_clear : Register <0x220, 32> { };
struct Cache_sync : Register <0x730, 32> { };
struct Invalidate_by_way : Register <0x77c, 32> { };
struct Clean_invalidate_by_way : Register <0x7fc, 32> { };
struct Aux : Register<0x104, 32>
{
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> { };
};
struct Debug : Register<0xf40, 32>
{
struct Dcl : Bitfield<0,1> { };
struct Dwb : Bitfield<1,1> { };
};
struct Irq_mask : Register <0x214, 32> { };
struct Irq_clear : Register <0x220, 32> { };
struct Cache_sync : Register <0x730, 32> { };
struct Invalidate_by_way : Register <0x77c, 32> { };
struct Clean_invalidate_by_way : Register <0x7fc, 32> { };
Pl310(Genode::addr_t const base) : Mmio(base) { }
struct Debug : Register<0xf40, 32>
{
struct Dcl : Bitfield<0,1> { };
struct Dwb : Bitfield<1,1> { };
};
inline void sync() { while (read<Cache_sync>()) ; }
void _sync() { while (read<Cache_sync>()) ; }
void flush()
{
write<Clean_invalidate_by_way>((1UL << 16) - 1);
sync();
}
public:
void invalidate()
{
write<Invalidate_by_way>((1UL << 16) - 1);
sync();
}
Pl310(Genode::addr_t const base) : Mmio(base) { }
void mask_interrupts()
{
write<Irq_mask>(0);
write<Irq_clear>(~0UL);
}
void enable() {}
void clean_invalidate()
{
write<Clean_invalidate_by_way>((1UL << 16) - 1);
_sync();
}
void invalidate()
{
write<Invalidate_by_way>((1UL << 16) - 1);
_sync();
}
void mask_interrupts()
{
write<Irq_mask>(0);
write<Irq_clear>(~0UL);
}
};
#endif /* _SPEC__ARM__PL310_H_ */

View File

@ -62,7 +62,7 @@ class Genode::Translation
_create(Page_flags const & f, addr_t const pa)
{
typename T::access_t v = T::Pa::masked(pa);
T::S::set(v, Board::is_smp());
T::S::set(v, Kernel::board().is_smp());
T::Ng::set(v, !f.global);
T::Xn::set(v, !f.executable);
if (f.device) { T::Tex::set(v, _device_tex()); }

View File

@ -107,6 +107,10 @@ class Genode::Arm_gic_distributor : public Mmio
{
struct Sgi_int_id : Bitfield<0, 4> { };
struct Cpu_target_list : Bitfield<16, 8> { };
struct Target_list_filter : Bitfield<24, 2>
{
enum Target { TARGET_LIST, ALL_OTHER, MYSELF };
};
};
/**
@ -266,7 +270,7 @@ class Genode::Pic
/**
* Raise inter-processor IRQ of the CPU with kernel name 'cpu_id'
*/
void trigger_ip_interrupt(unsigned const cpu_id)
void send_ipi(unsigned const cpu_id)
{
typedef Distr::Sgir Sgir;
Sgir::access_t sgir = 0;
@ -274,6 +278,19 @@ class Genode::Pic
Sgir::Cpu_target_list::set(sgir, 1 << cpu_id);
_distr.write<Sgir>(sgir);
}
/**
* Raise inter-processor interrupt on all other cores
*/
void send_ipi()
{
typedef Distr::Sgir Sgir;
Sgir::access_t sgir = 0;
Sgir::Sgi_int_id::set(sgir, IPI);
Sgir::Target_list_filter::set(sgir,
Sgir::Target_list_filter::ALL_OTHER);
_distr.write<Sgir>(sgir);
}
};
#endif /* _SPEC__ARM_GIC__PIC_SUPPORT_H_ */

View File

@ -35,8 +35,6 @@ namespace Genode
namespace Kernel {
using Genode::Cpu_lazy_state;
class Pd;
}
class Genode::Cpu : public Arm
@ -61,43 +59,18 @@ class Genode::Cpu : public Arm
struct It : Bitfield<18,1> { }; /* global instruction TCM enable */
struct U : Bitfield<22,1> { }; /* enable unaligned data access */
struct Xp : Bitfield<23,1> { }; /* disable subpage AP bits */
struct Unnamed_0 : Bitfield<4,3> { }; /* shall be ones */
struct Unnamed_1 : Bitfield<26,6> { }; /* shall not be modified */
/**
* Initialization that is common
*/
static void init_common(access_t & v)
static void init()
{
Arm::Sctlr::init_common(v);
access_t v = read();
A::set(v, 0);
V::set(v, 1);
W::set(v, 1);
Dt::set(v, 1);
It::set(v, 1);
U::set(v, 1);
Xp::set(v, 1);
Unnamed_0::set(v, ~0);
Unnamed_1::set(v, Unnamed_1::masked(read()));
}
/**
* Initialization for physical kernel stage
*/
static access_t init_virt_kernel()
{
access_t v = 0;
init_common(v);
Arm::Sctlr::init_virt_kernel(v);
return v;
}
/**
* Initialization for physical kernel stage
*/
static access_t init_phys_kernel()
{
access_t v = 0;
init_common(v);
return v;
write(v);
}
};
@ -107,30 +80,15 @@ class Genode::Cpu : public Arm
static bool restricted_page_mappings() {
return Ctr::P::get(Ctr::read()); }
/**
* Configure this module appropriately for the first kernel run
*/
static void init_phys_kernel()
{
Board::prepare_kernel();
Sctlr::write(Sctlr::init_phys_kernel());
flush_tlb();
/* check for mapping restrictions */
assert(!restricted_page_mappings());
}
/**
* Switch to the virtual mode in kernel
*
* \param pd kernel's pd object
*/
static void init_virt_kernel(Kernel::Pd& pd);
/**
* Ensure that TLB insertions get applied
*/
static void tlb_insertions() { flush_tlb(); }
void translation_table_insertions()
{
clean_invalidate_data_cache();
invalidate_instr_cache();
invalidate_tlb();
}
/**
* Return wether to retry an undefined user instruction after this call
@ -143,28 +101,8 @@ class Genode::Cpu : public Arm
* \param addr virtual address of the translation
* \param size size of the translation
*/
static void translation_added(addr_t const addr, size_t const size)
{
/*
* The Cortex-A8 CPU can't use the L1 cache on page-table
* walks. Therefore, as the page-tables lie in write-back cacheable
* memory we've to clean the corresponding cache-lines even when a
* page table entry is added. We only do this as core as the kernel
* adds translations solely before MMU and caches are enabled.
*/
if (is_user()) Kernel::update_data_region(addr, size);
else flush_data_caches();
}
static void translation_added(addr_t const addr, size_t const size);
/**
* Return kernel name of the executing CPU
*/
static unsigned executing_id();
/**
* Return kernel name of the primary CPU
*/
static unsigned primary_id();
/*************
** Dummies **

View File

@ -17,6 +17,7 @@
/* core includes */
#include <spec/arm/cpu_support.h>
#include <board.h>
#include <pic.h>
namespace Genode
{
@ -26,8 +27,6 @@ namespace Genode
class Arm_v7;
}
namespace Kernel { class Pd; }
class Genode::Arm_v7 : public Arm
{
@ -88,44 +87,21 @@ class Genode::Arm_v7 : public Arm
struct Sctlr : Arm::Sctlr
{
struct Z : Bitfield<11,1> { }; /* enable program flow prediction */
struct Unnamed_0 : Bitfield<3,4> { }; /* shall be ones */
struct Unnamed_1 : Bitfield<16,1> { }; /* shall be ones */
struct Unnamed_2 : Bitfield<18,1> { }; /* shall be ones */
struct Unnamed_3 : Bitfield<22,2> { }; /* shall be ones */
/**
* Initialization that is common
*/
static void init_common(access_t & v)
static access_t init_value()
{
Arm::Sctlr::init_common(v);
Unnamed_0::set(v, ~0);
Unnamed_1::set(v, ~0);
Unnamed_2::set(v, ~0);
Unnamed_3::set(v, ~0);
}
/**
* Initialization for virtual kernel stage
*/
static access_t init_virt_kernel()
{
access_t v = 0;
init_common(v);
Arm::Sctlr::init_virt_kernel(v);
access_t v = read();
C::set(v, 1);
I::set(v, 1);
V::set(v, 1);
A::set(v, 0);
M::set(v, 1);
Z::set(v, 1);
return v;
}
/**
* Initialization for physical kernel stage
*/
static access_t init_phys_kernel()
{
access_t v = 0;
init_common(v);
return v;
}
static void enable_mmu_and_caches() {
write(init_value()); }
};
@ -143,33 +119,19 @@ class Genode::Arm_v7 : public Arm
asm volatile ("mcr p15, 0, %[v], c10, c2, 0" :: [v]"r"(v) : ); }
};
/**
* Invalidate all branch predictions
*/
static void inval_branch_predicts() {
static void invalidate_branch_predicts() {
asm volatile ("mcr p15, 0, r0, c7, c5, 6" ::: "r0"); };
/**
* Switch to the virtual mode in kernel
* Switch on MMU and caches
*
* \param pd kernel's pd object
*/
static void init_virt_kernel(Kernel::Pd& pd);
void enable_mmu_and_caches(Kernel::Pd& pd);
inline static void finish_init_phys_kernel();
/**
* Configure this module appropriately for the first kernel run
*/
static void init_phys_kernel()
{
Board::prepare_kernel();
Sctlr::write(Sctlr::init_phys_kernel());
Psr::write(Psr::init_kernel());
flush_tlb();
finish_init_phys_kernel();
}
/**
* Finish all previous data transfers
@ -181,6 +143,22 @@ class Genode::Arm_v7 : public Arm
*/
static void wait_for_interrupt() { asm volatile ("wfi"); }
/**
* Write back dirty lines of inner data cache and invalidate all
*/
void clean_invalidate_inner_data_cache();
/**
* Invalidate all lines of the inner data cache
*/
void invalidate_inner_data_cache();
/**
* Invalidate all lines of the instruction cache
*/
void invalidate_instruction_cache() {
asm volatile("mcr p15, 0, r0, c7, c5, 0"); }
/******************************
** Trustzone specific API **

View File

@ -1,11 +1,12 @@
/*
* \brief CPU driver for core
* \author Martin stein
* \author Stefan Kalkowski
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-2012 Genode Labs GmbH
* Copyright (C) 2011-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -415,7 +416,7 @@ class Genode::Cpu : public Arm_v7
/**
* Return kernel name of the executing CPU
*/
static unsigned executing_id();
static unsigned executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); }
/**
* Return kernel name of the primary CPU
@ -429,16 +430,32 @@ class Genode::Cpu : public Arm_v7
*/
static void init_virt_kernel(Kernel::Pd & pd);
/**
* Write back dirty cache lines and invalidate all cache lines
*/
void clean_invalidate_data_cache() {
clean_invalidate_inner_data_cache(); }
/**
* Invalidate all cache lines
*/
void invalidate_data_cache() {
invalidate_inner_data_cache(); }
void translation_table_insertions() { invalidate_branch_predicts(); }
/**
* Hook function called at the very beginning
* of the local cpu initialization
*/
void init();
/*************
** Dummies **
*************/
static void tlb_insertions() { inval_branch_predicts(); }
static void translation_added(addr_t, size_t) { }
static void prepare_proceeding(Cpu_lazy_state *, Cpu_lazy_state *) { }
};
void Genode::Arm_v7::finish_init_phys_kernel() { }
#endif /* _CPU_H_ */

View File

@ -1,11 +1,12 @@
/*
* \brief CPU driver for core
* \brief ARM Cortex A8 CPU driver for core
* \author Martin stein
* \author Stefan Kalkowski
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -37,14 +38,21 @@ class Genode::Cpu : public Arm_v7
public:
/**
* Ensure that TLB insertions get applied
* Write back dirty cache lines and invalidate the whole cache
*/
static void tlb_insertions() { flush_tlb(); }
void clean_invalidate_data_cache() {
clean_invalidate_inner_data_cache(); }
/**
* Return wether to retry an undefined user instruction after this call
* Invalidate all cache lines
*/
bool retry_undefined_instr(Cpu_lazy_state *) { return false; }
void invalidate_data_cache() {
invalidate_inner_data_cache(); }
/**
* Ensure that TLB insertions get applied
*/
void translation_table_insertions();
/**
* Post processing after a translation was added to a translation table
@ -52,36 +60,7 @@ class Genode::Cpu : public Arm_v7
* \param addr virtual address of the translation
* \param size size of the translation
*/
static void translation_added(addr_t const addr, size_t const size)
{
/*
* The Cortex-A8 CPU can't use the L1 cache on page-table
* walks. Therefore, as the page-tables lie in write-back cacheable
* memory we've to clean the corresponding cache-lines even when a
* page table entry is added. We only do this as core as the kernel
* adds translations solely before MMU and caches are enabled.
*/
if (is_user()) Kernel::update_data_region(addr, size);
else flush_data_caches();
}
/**
* Return kernel name of the executing CPU
*/
static unsigned executing_id();
/**
* Return kernel name of the primary CPU
*/
static unsigned primary_id();
/*************
** Dummies **
*************/
static void prepare_proceeding(Cpu_lazy_state *, Cpu_lazy_state *) { }
static void translation_added(addr_t const addr, size_t const size);
};
void Genode::Arm_v7::finish_init_phys_kernel() { }
#endif /* _CPU_H_ */

View File

@ -16,6 +16,7 @@
/* core includes */
#include <drivers/board_base.h>
#include <spec/arm/pl310.h>
namespace Cortex_a9
{
@ -27,9 +28,27 @@ namespace Cortex_a9
class Cortex_a9::Board : public Genode::Board_base
{
protected:
using L2_cache = Arm::Pl310;
L2_cache _l2_cache;
public:
enum Errata {
ARM_754322,
ARM_764369,
ARM_775420,
PL310_588369,
PL310_727915,
PL310_769419,
};
enum {
/* snoop control unit */
SCU_MMIO_BASE = CORTEX_A9_PRIVATE_MEM_BASE,
/* interrupt controller */
IRQ_CONTROLLER_DISTR_BASE = CORTEX_A9_PRIVATE_MEM_BASE + 0x1000,
IRQ_CONTROLLER_DISTR_SIZE = 0x1000,
@ -41,6 +60,15 @@ class Cortex_a9::Board : public Genode::Board_base
PRIVATE_TIMER_MMIO_SIZE = 0x10,
PRIVATE_TIMER_IRQ = 29,
};
Board() : _l2_cache(Genode::Board_base::PL310_MMIO_BASE) {}
L2_cache & l2_cache() { return _l2_cache; }
void init() { }
void wake_up_all_cpus(void * const ip);
bool is_smp() { return true; }
bool errata(Errata);
};
#endif /* _SPEC__CORTEX_A9__BOARD_SUPPORT_H_ */

View File

@ -1,18 +1,19 @@
/*
* \brief CPU driver for core
* \author Martin stein
* \author Stefan Kalkowski
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CPU_H_
#define _CPU_H_
#ifndef _SPEC__CORTEX_A9__CPU_SUPPORT_H_
#define _SPEC__CORTEX_A9__CPU_SUPPORT_H_
/* core includes */
#include <spec/arm_v7/cpu_support.h>
@ -28,14 +29,14 @@ namespace Genode
/**
* CPU driver for core
*/
class Cpu;
class Cortex_a9;
}
namespace Kernel { using Genode::Cpu_lazy_state; }
class Genode::Cpu_lazy_state
{
friend class Cpu;
friend class Cortex_a9;
private:
@ -55,7 +56,7 @@ class Genode::Cpu_lazy_state
inline Cpu_lazy_state();
};
class Genode::Cpu : public Arm_v7
class Genode::Cortex_a9 : public Arm_v7
{
friend class Cpu_lazy_state;
@ -229,12 +230,19 @@ class Genode::Cpu : public Arm_v7
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %0, c1, c0, 1" :: "r" (v) : ); }
static void enable_smp()
{
access_t v = read();
Smp::set(v, 1);
write(v);
}
};
/**
* Constructor
*/
Cpu() : _advanced_fp_simd_state(0) { }
Cortex_a9() : _advanced_fp_simd_state(0) { }
/**
* Initialize advanced FP/SIMD extension
@ -281,26 +289,47 @@ class Genode::Cpu : public Arm_v7
}
/**
* Return kernel name of the executing CPU
* Write back dirty cache lines and invalidate whole data cache
*/
static unsigned executing_id();
void clean_invalidate_data_cache()
{
clean_invalidate_inner_data_cache();
Kernel::board().l2_cache().clean_invalidate();
}
/**
* Return kernel name of the primary CPU
* Invalidate whole data cache
*/
static unsigned primary_id();
void invalidate_data_cache()
{
invalidate_inner_data_cache();
Kernel::board().l2_cache().invalidate();
}
/**
* Clean and invalidate data-cache for virtual region
* 'base' - 'base + size'
*/
void clean_invalidate_data_cache_by_virt_region(addr_t base,
size_t const size)
{
Arm::clean_invalidate_data_cache_by_virt_region(base, size);
Kernel::board().l2_cache().clean_invalidate();
}
void translation_table_insertions() { invalidate_branch_predicts(); }
static unsigned executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); }
/*************
** Dummies **
*************/
static void translation_added(addr_t, size_t) { }
static void tlb_insertions() { inval_branch_predicts(); }
};
void Genode::Arm_v7::finish_init_phys_kernel() { Cpu::init_advanced_fp_simd(); }
Genode::Cpu_lazy_state::Cpu_lazy_state() { fpexc = Cpu::Fpexc::En::bits(1); }
Genode::Cpu_lazy_state::Cpu_lazy_state() { fpexc = Cortex_a9::Fpexc::En::bits(1); }
/*
* Annotation 1
@ -322,4 +351,4 @@ Genode::Cpu_lazy_state::Cpu_lazy_state() { fpexc = Cpu::Fpexc::En::bits(1); }
* head branch as from 2014.04.17.
*/
#endif /* _CPU_H_ */
#endif /* _SPEC__CORTEX_A9__CPU_SUPPORT_H_ */

View File

@ -0,0 +1,71 @@
/*
* \brief Snoop control unit
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2015-12-15
*/
/*
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <util/mmio.h>
/* local includes */
#include <board.h>
namespace Genode {
class Scu;
}
class Genode::Scu : Genode::Mmio
{
private:
struct Cr : Register<0x0, 32>
{
struct Enable : Bitfield<0, 1> { };
};
struct Dcr : Register<0x30, 32>
{
struct Bit_0 : Bitfield<0, 1> { };
};
struct Iassr : Register<0xc, 32>
{
struct Cpu0_way : Bitfield<0, 4> { };
struct Cpu1_way : Bitfield<4, 4> { };
struct Cpu2_way : Bitfield<8, 4> { };
struct Cpu3_way : Bitfield<12, 4> { };
};
Board &_board;
public:
Scu(Board & board) : Mmio(Board::SCU_MMIO_BASE), _board(board) { }
void invalidate()
{
Iassr::access_t iassr = 0;
for (Iassr::access_t way = 0; way <= Iassr::Cpu0_way::mask();
way++) {
Iassr::Cpu0_way::set(iassr, way);
Iassr::Cpu1_way::set(iassr, way);
Iassr::Cpu2_way::set(iassr, way);
Iassr::Cpu3_way::set(iassr, way);
write<Iassr>(iassr);
}
}
void enable()
{
if (_board.errata(Board::ARM_764369)) write<Dcr::Bit_0>(1);
write<Cr>(Cr::Enable::bits(1));
}
};

View File

@ -1,11 +1,12 @@
/*
* \brief Board driver for core
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2012-04-23
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -23,15 +24,17 @@ namespace Genode
{
public:
static void outer_cache_invalidate() { }
static void outer_cache_flush() { }
static void prepare_kernel();
static void init() { }
/**
* Tell secondary CPUs to start execution from instr. pointer 'ip'
*/
static void secondary_cpus_ip(void * const ip) {
*(void * volatile *)IRAM_BASE = ip; }
static void wake_up_all_cpus(void * const ip)
{
*(void * volatile *)IRAM_BASE = ip;
asm volatile("dsb\n"
"sev\n");
}
static bool is_smp() { return true; }
};

View File

@ -37,45 +37,44 @@ namespace Imx
class Imx::Aipstz : public Genode::Mmio
{
/*
* Configuration of the masters
*/
private:
struct Mpr { enum { ALL_UNBUFFERED_AND_FULLY_TRUSTED = 0x77777777 }; };
struct Mpr1 : Register<0x0, 32>, Mpr { };
struct Mpr2 : Register<0x4, 32>, Mpr { };
/*
* Configuration of the masters
*/
/*
* Configuration of the platform peripherals
*/
struct Mpr { enum { ALL_UNBUFFERED_AND_FULLY_TRUSTED = 0x77777777 }; };
struct Mpr1 : Register<0x0, 32>, Mpr { };
struct Mpr2 : Register<0x4, 32>, Mpr { };
struct Pacr { enum { ALL_UNBUFFERED_AND_FULLY_UNPROTECTED = 0 }; };
struct Pacr1 : Register<0x20, 32>, Pacr { };
struct Pacr2 : Register<0x24, 32>, Pacr { };
struct Pacr3 : Register<0x28, 32>, Pacr { };
struct Pacr4 : Register<0x2c, 32>, Pacr { };
/*
* Configuration of the platform peripherals
*/
/*
* Configuration of the off-platform peripherals
*/
struct Pacr { enum { ALL_UNBUFFERED_AND_FULLY_UNPROTECTED = 0 }; };
struct Pacr1 : Register<0x20, 32>, Pacr { };
struct Pacr2 : Register<0x24, 32>, Pacr { };
struct Pacr3 : Register<0x28, 32>, Pacr { };
struct Pacr4 : Register<0x2c, 32>, Pacr { };
struct Opacr1 : Register<0x40, 32>, Pacr { };
struct Opacr2 : Register<0x44, 32>, Pacr { };
struct Opacr3 : Register<0x48, 32>, Pacr { };
struct Opacr4 : Register<0x4c, 32>, Pacr { };
struct Opacr5 : Register<0x50, 32>, Pacr { };
/*
* Configuration of the off-platform peripherals
*/
struct Opacr1 : Register<0x40, 32>, Pacr { };
struct Opacr2 : Register<0x44, 32>, Pacr { };
struct Opacr3 : Register<0x48, 32>, Pacr { };
struct Opacr4 : Register<0x4c, 32>, Pacr { };
struct Opacr5 : Register<0x50, 32>, Pacr { };
public:
/**
* Constructor
*/
Aipstz(Genode::addr_t const base) : Genode::Mmio(base) { }
/**
* Configure this module appropriately for the first kernel run
*/
void prepare_kernel()
void init()
{
/* avoid AIPS intervention at any memory access */
write<Mpr1>(Mpr::ALL_UNBUFFERED_AND_FULLY_TRUSTED);
@ -94,45 +93,18 @@ class Imx::Aipstz : public Genode::Mmio
class Imx::Board : public Genode::Board_base
{
/*
* static AIPSTZ instances
*/
static Aipstz * _aipstz_1()
{
static Aipstz a(AIPS_1_MMIO_BASE);
return &a;
}
static Aipstz * _aipstz_2()
{
static Aipstz a(AIPS_2_MMIO_BASE);
return &a;
}
public:
/**
* Configure this module appropriately for the first kernel run
*/
static void prepare_kernel()
void init()
{
_aipstz_1()->prepare_kernel();
_aipstz_2()->prepare_kernel();
Aipstz _aipstz_1(AIPS_1_MMIO_BASE);
Aipstz _aipstz_2(AIPS_2_MMIO_BASE);
_aipstz_1.init();
_aipstz_2.init();
}
/**
* Return wether the board has SMP extensions
*/
static bool is_smp();
/*
* Dummies
*/
static void outer_cache_invalidate() { }
static void outer_cache_flush() { }
static void secondary_cpus_ip(void *) { }
};
#endif /* _SPEC__IMX__BOARD_SUPPORT_H_ */

View File

@ -23,7 +23,12 @@ namespace Genode
/**
* Board driver
*/
class Board : public Imx::Board { };
class Board : public Imx::Board
{
public:
bool is_smp() { return false; }
};
}
#endif /* _BOARD_H_ */

View File

@ -24,7 +24,16 @@ namespace Genode
/**
* Board driver
*/
class Board : public Imx::Board, public Cortex_a9::Board { };
class Board : public Imx::Board, public Cortex_a9::Board
{
public:
void init()
{
Imx::Board::init();
Cortex_a9::Board::init();
}
};
}
#endif /* _BOARD_H_ */

View File

@ -0,0 +1,26 @@
/*
* \brief CPU driver for core
* \author Stefan Kalkowski
* \date 2015-12-15
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CPU_H_
#define _CPU_H_
/* core includes */
#include <spec/cortex_a9/cpu_support.h>
namespace Genode
{
using Cpu = Genode::Cortex_a9;
}
#endif /* _CPU_H_ */

View File

@ -16,77 +16,14 @@
#define _BOARD_H_
/* core includes */
#include <spec/cortex_a9/board_support.h>
#include <spec/arm/pl310.h>
#include <spec/cortex_a9/board_support.h>
namespace Genode
{
class L2_cache;
class Board;
}
/**
* L2 outer cache controller
*/
class Genode::L2_cache
{
private:
struct Secure_monitor
{
enum Syscalls
{
L2_CACHE_SET_DEBUG_REG = 0x100,
L2_CACHE_ENABLE_REG = 0x102,
L2_CACHE_AUX_REG = 0x109,
};
void call(addr_t func, addr_t val)
{
register addr_t _func asm("r12") = func;
register addr_t _val asm("r0") = val;
asm volatile(
"dsb; smc #0" ::
"r" (_func), "r" (_val) :
"memory", "cc", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11");
}
} _secure_monitor;
Arm::Pl310 _pl310;
public:
L2_cache() : _pl310(Cortex_a9::Board::PL310_MMIO_BASE)
{
Arm::Pl310::Aux::access_t v = 0;
Arm::Pl310::Aux::Associativity::set(v, 1);
Arm::Pl310::Aux::Way_size::set(v, 3);
Arm::Pl310::Aux::Share_override::set(v, 1);
Arm::Pl310::Aux::Reserved::set(v, 1);
Arm::Pl310::Aux::Ns_lockdown::set(v, 1);
Arm::Pl310::Aux::Ns_irq_ctrl::set(v, 1);
Arm::Pl310::Aux::Data_prefetch::set(v, 1);
Arm::Pl310::Aux::Inst_prefetch::set(v, 1);
Arm::Pl310::Aux::Early_bresp::set(v, 1);
_secure_monitor.call(Secure_monitor::L2_CACHE_AUX_REG, v);
_secure_monitor.call(Secure_monitor::L2_CACHE_ENABLE_REG, 1);
_pl310.mask_interrupts();
}
void flush()
{
Arm::Pl310::Debug::access_t v = 0;
Arm::Pl310::Debug::Dwb::set(v, 1);
Arm::Pl310::Debug::Dcl::set(v, 1);
_secure_monitor.call(Secure_monitor::L2_CACHE_SET_DEBUG_REG, v);
_pl310.flush();
_secure_monitor.call(Secure_monitor::L2_CACHE_SET_DEBUG_REG, 0);
}
void invalidate() { _pl310.invalidate(); }
};
/**
* Board driver for core
@ -95,11 +32,103 @@ class Genode::Board : public Cortex_a9::Board
{
public:
static void outer_cache_invalidate();
static void outer_cache_flush();
static void prepare_kernel();
static void secondary_cpus_ip(void * const ip) { }
static bool is_smp() { return true; }
using Base = Cortex_a9::Board;
/**
* Frontend to monitor firmware running in the secure world
*/
struct Secure_monitor
{
enum Syscalls
{
CPU_ACTLR_SMP_BIT_RAISE = 0x25,
L2_CACHE_SET_DEBUG_REG = 0x100,
L2_CACHE_ENABLE_REG = 0x102,
L2_CACHE_AUX_REG = 0x109,
};
void call(addr_t func, addr_t val)
{
register addr_t _func asm("r12") = func;
register addr_t _val asm("r0") = val;
asm volatile("dsb; smc #0" ::
"r" (_func), "r" (_val) :
"memory", "cc", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11");
}
};
class L2_cache : public Base::L2_cache
{
private:
Secure_monitor & _monitor;
unsigned long _init_value()
{
Aux::access_t v = 0;
Aux::Associativity::set(v, 1);
Aux::Way_size::set(v, 3);
Aux::Share_override::set(v, 1);
Aux::Reserved::set(v, 1);
Aux::Ns_lockdown::set(v, 1);
Aux::Ns_irq_ctrl::set(v, 1);
Aux::Data_prefetch::set(v, 1);
Aux::Inst_prefetch::set(v, 1);
Aux::Early_bresp::set(v, 1);
return v;
}
unsigned long _debug_value()
{
Debug::access_t v = 0;
Debug::Dwb::set(v, 1);
Debug::Dcl::set(v, 1);
return v;
}
public:
L2_cache(Secure_monitor & monitor)
: Base::L2_cache(Genode::Board_base::PL310_MMIO_BASE),
_monitor(monitor)
{
_monitor.call(Secure_monitor::L2_CACHE_AUX_REG,
_init_value());
}
void clean_invalidate()
{
_monitor.call(Secure_monitor::L2_CACHE_SET_DEBUG_REG,
_debug_value());
Base::L2_cache::clean_invalidate();
_monitor.call(Secure_monitor::L2_CACHE_SET_DEBUG_REG, 0);
}
void invalidate() { Base::L2_cache::invalidate(); }
void enable()
{
_monitor.call(Secure_monitor::L2_CACHE_ENABLE_REG, 1);
Base::L2_cache::mask_interrupts();
}
void disable() {
_monitor.call(Secure_monitor::L2_CACHE_ENABLE_REG, 0); }
};
private:
Secure_monitor _monitor;
L2_cache _l2_cache;
public:
Board() : _l2_cache(_monitor) { _l2_cache.disable(); }
L2_cache & l2_cache() { return _l2_cache; }
Secure_monitor & monitor() { return _monitor; }
};
#endif /* _BOARD_H_ */

View File

@ -14,9 +14,6 @@
#ifndef CORTEX_A9_WUGEN_H
#define CORTEX_A9_WUGEN_H
/* base includes */
#include <unmanaged_singleton.h>
/* Genode includes */
#include <drivers/board_base.h>
@ -27,8 +24,6 @@ namespace Genode { class Cortex_a9_wugen; }
*/
class Genode::Cortex_a9_wugen : Mmio
{
friend Unmanaged_singleton_constructor;
private:
struct Aux_core_boot_0 : Register<0x800, 32> {
@ -36,12 +31,9 @@ class Genode::Cortex_a9_wugen : Mmio
struct Aux_core_boot_1 : Register<0x804, 32> { };
Cortex_a9_wugen() : Mmio(Board_base::CORTEX_A9_WUGEN_MMIO_BASE) { }
public:
static Cortex_a9_wugen * singleton() {
return unmanaged_singleton<Cortex_a9_wugen>(); }
Cortex_a9_wugen() : Mmio(Board_base::CORTEX_A9_WUGEN_MMIO_BASE) { }
/**
* Start CPU 1 with instruction pointer 'ip'

View File

@ -0,0 +1,41 @@
/*
* \brief CPU driver for core
* \author Stefan Kalkowski
* \date 2015-12-15
*/
/*
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CPU_H_
#define _CPU_H_
/* core includes */
#include <spec/cortex_a9/cpu_support.h>
namespace Genode
{
class Cpu;
}
/**
* Override the Cortex A9 Cpu driver, because some registers can be accessed
* via the firmware running in TrustZone's secure world only
*/
class Genode::Cpu : public Genode::Cortex_a9
{
public:
struct Actlr : Cortex_a9::Actlr
{
static void enable_smp();
};
};
#endif /* _CPU_H_ */

View File

@ -19,16 +19,7 @@
namespace Genode
{
class Board : public Cortex_a9::Board
{
public:
static void outer_cache_invalidate() { }
static void outer_cache_flush() { }
static void prepare_kernel() { }
static void secondary_cpus_ip(void * const ip) { }
static bool is_smp() { return false; }
};
using Board = Cortex_a9::Board;
}
#endif /* _SPEC__PBXA9__BOARD_H_ */

View File

@ -1,7 +1,7 @@
/*
* \brief Board-specific code for Exynos5 boards
* \brief CPU driver for core
* \author Stefan Kalkowski
* \date 2015-02-09
* \date 2015-12-15
*/
/*
@ -11,7 +11,15 @@
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <board.h>
#ifndef _CPU_H_
#define _CPU_H_
void Genode::Board::prepare_kernel() { }
/* core includes */
#include <spec/cortex_a9/cpu_support.h>
namespace Genode
{
using Cpu = Cortex_a9;
}
#endif /* _CPU_H_ */

View File

@ -1,11 +1,12 @@
/*
* \brief Board driver for core
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2012-04-23
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -23,10 +24,8 @@ namespace Genode
{
public:
static void outer_cache_invalidate() { }
static void outer_cache_flush() { }
static void prepare_kernel() { }
static void secondary_cpus_ip(void * const ip) { }
void init() { }
static bool is_smp() { return false; }
};
}

View File

@ -136,12 +136,13 @@ class Genode::Pic : Mmio
public:
enum {
/*
* FIXME: dummy ipi value on non-SMP platform, should be removed
* when SMP is an aspect of CPUs only compiled where necessary
*/
IPI = 63,
NR_OF_IRQ = 64,
/*
* dummy IPI value on non-SMP platform,
* only used in interrupt reservation within generic code
*/
IPI,
};
private:
@ -241,13 +242,6 @@ class Genode::Pic : Mmio
else
write<Irq_disable_gpu_2>(1 << (i - 8 - 32));
}
/*
* Dummies
*/
bool is_ip_interrupt(unsigned) { return false; }
void trigger_ip_interrupt(unsigned) { }
};
namespace Kernel { class Pic : public Genode::Pic { }; }

View File

@ -29,6 +29,8 @@ namespace Genode
TIMER_VECTOR_USER = 50,
ISA_IRQ_END = 15,
};
void init() { }
};
}

View File

@ -364,23 +364,6 @@ class Genode::Cpu
_disable_fpu();
}
/*********************************************
** Dummy implementations not needed on x86 **
*********************************************/
static void tlb_insertions() { }
static void translation_added(addr_t, size_t) { }
static void flush_data_caches() { }
static void flush_caches() { }
static void flush_tlb_by_pid(unsigned const pid) { }
static void flush_data_caches_by_virt_region(addr_t base,
size_t const size) { }
static void invalidate_instr_caches() { }
static void invalidate_data_caches() { }
static void invalidate_instr_caches_by_virt_region(addr_t base,
size_t const size) {}
};
struct Genode::Cpu::Cr0 : Register<64>

View File

@ -18,36 +18,10 @@
/* core includes */
#include <spec/cortex_a9/board_support.h>
#include <spec/arm/pl310.h>
namespace Genode
{
class Pl310;
class Board;
using Board = Cortex_a9::Board;
}
/**
* L2 outer cache controller
*/
class Genode::Pl310 : public Arm::Pl310
{
public:
Pl310(addr_t const base) : Arm::Pl310(base) { mask_interrupts(); }
};
/**
* Board driver for core
*/
class Genode::Board : public Cortex_a9::Board
{
public:
static void outer_cache_invalidate();
static void outer_cache_flush();
static void prepare_kernel();
static void secondary_cpus_ip(void * const ip) { }
static bool is_smp() { return true; }
};
#endif /* _BOARD_H_ */

View File

@ -0,0 +1,25 @@
/*
* \brief CPU driver for core
* \author Stefan Kalkowski
* \date 2015-12-15
*/
/*
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CPU_H_
#define _CPU_H_
/* core includes */
#include <spec/cortex_a9/cpu_support.h>
namespace Genode
{
using Cpu = Genode::Cortex_a9;
}
#endif /* _CPU_H_ */

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -29,38 +29,9 @@ using namespace Kernel;
namespace Kernel
{
/**
* Lists all pending domain updates
*/
class Cpu_domain_update_list;
Timer * timer();
Cpu_pool * cpu_pool() { return unmanaged_singleton<Cpu_pool>(); }
}
class Kernel::Cpu_domain_update_list
: public Double_list_typed<Cpu_domain_update>
{
typedef Cpu_domain_update Update;
public:
/**
* Perform all pending domain updates on the executing CPU
*/
void do_each() { for_each([] (Update * const u) { u->_do(); }); }
};
namespace Kernel
{
/**
* Return singleton of the CPU domain-udpate list
*/
Cpu_domain_update_list * cpu_domain_update_list() {
return unmanaged_singleton<Cpu_domain_update_list>(); }
}
/*************
** Cpu_job **
@ -149,25 +120,6 @@ void Cpu::schedule(Job * const job)
}
void Cpu::Ipi::occurred()
{
cpu_domain_update_list()->do_each();
pending = false;
}
void Cpu::Ipi::trigger(unsigned const cpu_id)
{
if (pending) return;
pic()->trigger_ip_interrupt(cpu_id);
pending = true;
}
Cpu::Ipi::Ipi(Irq::Pool &p) : Irq(Pic::IPI, p) { }
bool Cpu::interrupt(unsigned const irq_id)
{
Irq * const irq = object(irq_id);
@ -211,56 +163,6 @@ Cpu::Cpu(unsigned const id, Timer * const timer)
_timer_irq(_timer->interrupt_id(_id), *this) { }
/***********************
** Cpu_domain_update **
***********************/
void Cpu_domain_update::_do()
{
/* perform domain update locally and get pending bit */
unsigned const id = Cpu::executing_id();
if (!_pending[id]) { return; }
_domain_update();
_pending[id] = false;
/* check wether there are still CPUs pending */
unsigned i = 0;
for (; i < NR_OF_CPUS && !_pending[i]; i++) { }
if (i < NR_OF_CPUS) { return; }
/* as no CPU is pending anymore, end the domain update */
cpu_domain_update_list()->remove(this);
_cpu_domain_update_unblocks();
}
bool Cpu_domain_update::_do_global(unsigned const domain_id)
{
/* perform locally and leave it at that if in uniprocessor mode */
_domain_id = domain_id;
_domain_update();
if (NR_OF_CPUS == 1) { return false; }
/* inform other CPUs and block until they are done */
cpu_domain_update_list()->insert_tail(this);
unsigned const cpu_id = Cpu::executing_id();
for (unsigned i = 0; i < NR_OF_CPUS; i++) {
if (i == cpu_id) { continue; }
_pending[i] = true;
cpu_pool()->cpu(i)->trigger_ip_interrupt();
}
return true;
}
void Cpu_domain_update::_domain_update() {
Genode::Cpu::flush_tlb_by_pid(_domain_id); }
Cpu_domain_update::Cpu_domain_update() {
for (unsigned i = 0; i < NR_OF_CPUS; i++) { _pending[i] = false; } }
/**************
** Cpu_pool **
**************/
@ -280,6 +182,14 @@ Cpu_pool::Cpu_pool()
}
/***********************
** Cpu_domain_update **
***********************/
Cpu_domain_update::Cpu_domain_update() {
for (unsigned i = 0; i < NR_OF_CPUS; i++) { _pending[i] = false; } }
/*****************
** Cpu_context **
*****************/

View File

@ -2,11 +2,11 @@
* \brief Common kernel initialization
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-20
* \date 2015-12-20
*/
/*
* Copyright (C) 2011-2015 Genode Labs GmbH
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -18,6 +18,7 @@
#include <kernel/test.h>
#include <platform_pd.h>
#include <pic.h>
#include <board.h>
#include <platform_thread.h>
/* base includes */
@ -35,6 +36,9 @@ Pd * Kernel::core_pd() {
Pic * Kernel::pic() { return unmanaged_singleton<Pic>(); }
Genode::Board & Kernel::board() {
return *unmanaged_singleton<Genode::Board>(); }
/**
* Setup kernel environment
@ -47,17 +51,13 @@ extern "C" void init_kernel()
* local static objects.
*/
/* calculate in advance as needed later when data writes aren't allowed */
core_pd();
board().init();
/* initialize cpu pool */
cpu_pool();
/* initialize PIC */
pic();
/* initialize current cpu */
cpu_pool()->cpu(Cpu::executing_id())->init(*pic(), *core_pd());
cpu_pool()->cpu(Cpu::executing_id())->init(*pic(), *core_pd(), board());
Core_thread::singleton();

View File

@ -1,5 +1,5 @@
/*
* \brief Kernel entrypoint
* \brief Kernel entrypoint for non-SMP systems
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-20
@ -20,7 +20,16 @@ extern "C" void kernel()
{
using namespace Kernel;
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
cpu->scheduled_job().exception(cpu->id());
cpu->schedule().proceed(cpu->id());
}
void Kernel::Cpu::Ipi::occurred() { }
void Kernel::Cpu::Ipi::trigger(unsigned const cpu_id) { }
Kernel::Cpu::Ipi::Ipi(Kernel::Irq::Pool &p) : Kernel::Irq(Kernel::Pic::IPI, p) { }

View File

@ -269,13 +269,6 @@ void Thread::_call_resume_local_thread()
}
void Thread_event::_signal_acknowledged()
{
Cpu::tlb_insertions();
_thread->_resume();
}
Thread_event::Thread_event(Thread * const t)
: _thread(t), _signal_context(0) { }
@ -362,51 +355,6 @@ Signal_context * const Thread_event::signal_context() const {
return _signal_context; }
void Thread::_call_update_data_region()
{
/*
* FIXME: If the caller is not a core thread, the kernel operates in a
* different address space than the caller. Combined with the fact
* that at least ARMv7 doesn't provide cache operations by physical
* address, this prevents us from selectively maintaining caches.
* The future solution will be a kernel that is mapped to every
* address space so we can use virtual addresses of the caller. Up
* until then we apply operations to caches as a whole instead.
*/
if (!_core()) {
Cpu::flush_data_caches();
return;
}
auto base = (addr_t)user_arg_1();
auto const size = (size_t)user_arg_2();
Cpu::flush_data_caches_by_virt_region(base, size);
Cpu::invalidate_instr_caches();
}
void Thread::_call_update_instr_region()
{
/*
* FIXME: If the caller is not a core thread, the kernel operates in a
* different address space than the caller. Combined with the fact
* that at least ARMv7 doesn't provide cache operations by physical
* address, this prevents us from selectively maintaining caches.
* The future solution will be a kernel that is mapped to every
* address space so we can use virtual addresses of the caller. Up
* until then we apply operations to caches as a whole instead.
*/
if (!_core()) {
Cpu::flush_data_caches();
Cpu::invalidate_instr_caches();
return;
}
auto base = (addr_t)user_arg_1();
auto const size = (size_t)user_arg_2();
Cpu::flush_data_caches_by_virt_region(base, size);
Cpu::invalidate_instr_caches_by_virt_region(base, size);
}
void Thread::_print_activity(bool const printing_thread)
{
Genode::printf("\033[33m%s -> %s:\033[0m", pd_label(), label());

View File

@ -1,22 +0,0 @@
/*
* \brief CPU driver for core
* \author Martin stein
* \date 2014-07-14
*/
/*
* Copyright (C) 2011-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <cpu.h>
using namespace Genode;
unsigned Cpu::primary_id() { return 0; }
unsigned Cpu::executing_id() { return primary_id(); }

View File

@ -1,12 +1,12 @@
/*
* \brief Class for kernel data that is needed to manage a specific CPU
* \brief Kernel cpu driver implementations specific to ARM
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2014-01-14
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -19,33 +19,31 @@
#include <pic.h>
#include <trustzone.h>
void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd)
void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd,
Genode::Board & board)
{
/* locally initialize interrupt controller */
pic.init_cpu_local();
/* initialize CPU in physical mode */
Cpu::init_phys_kernel();
Sctlr::init();
/* switch to core address space */
Cpu::init_virt_kernel(core_pd);
Cpu::enable_mmu_and_caches(core_pd);
/*
* TrustZone initialization code
*
* FIXME This is a plattform specific feature
*/
init_trustzone(pic);
/*
* Enable performance counter
*
* FIXME This is an optional CPU specific feature
*/
perf_counter()->enable();
/* locally initialize interrupt controller */
pic.init_cpu_local();
/* enable timer interrupt */
unsigned const cpu = Cpu::executing_id();
pic.unmask(Timer::interrupt_id(cpu), cpu);
pic.unmask(Timer::interrupt_id(id()), id());
}
void Kernel::Cpu_domain_update::_domain_update() {
cpu_pool()->cpu(Cpu::executing_id())->invalidate_tlb_by_pid(_domain_id); }

View File

@ -40,7 +40,10 @@ Kernel::Pd::~Pd() {
oir->~Object_identity_reference();
/* clean up buffers of memory management */
Cpu::flush_tlb_by_pid(asid);
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
cpu->clean_invalidate_data_cache();
cpu->invalidate_instr_cache();
cpu->invalidate_tlb_by_pid(asid);
alloc().free(asid);
}

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
* Copyright (C) 2013-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -30,14 +30,10 @@ void Thread::exception(unsigned const cpu)
_call();
return;
case PREFETCH_ABORT:
_mmu_exception();
return;
case DATA_ABORT:
_mmu_exception();
return;
case INTERRUPT_REQUEST:
_interrupt(cpu);
return;
case FAST_INTERRUPT_REQUEST:
_interrupt(cpu);
return;
@ -76,12 +72,72 @@ void Thread::_mmu_exception()
_fault.submit();
return;
}
PERR("unknown MMU exception");
PERR("%s -> %s: raised unhandled %s DFSR=0x%08x ISFR=0x%08x "
"DFAR=0x%08x ip=0x%08lx sp=0x%08lx", pd_label(), label(),
cpu_exception == DATA_ABORT ? "data abort" : "prefetch abort",
Cpu::Dfsr::read(), Cpu::Ifsr::read(), Cpu::Dfar::read(), ip, sp);
}
void Thread::_call_update_pd()
void Kernel::Thread::_call_update_data_region()
{
Pd * const pd = (Pd *) user_arg_1();
if (Cpu_domain_update::_do_global(pd->asid)) { _pause(); }
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
/*
* FIXME: If the caller is not a core thread, the kernel operates in a
* different address space than the caller. Combined with the fact
* that at least ARMv7 doesn't provide cache operations by physical
* address, this prevents us from selectively maintaining caches.
* The future solution will be a kernel that is mapped to every
* address space so we can use virtual addresses of the caller. Up
* until then we apply operations to caches as a whole instead.
*/
if (!_core()) {
cpu->clean_invalidate_data_cache();
return;
}
auto base = (addr_t)user_arg_1();
auto const size = (size_t)user_arg_2();
cpu->clean_invalidate_data_cache_by_virt_region(base, size);
cpu->invalidate_instr_cache();
}
void Kernel::Thread::_call_update_instr_region()
{
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
/*
* FIXME: If the caller is not a core thread, the kernel operates in a
* different address space than the caller. Combined with the fact
* that at least ARMv7 doesn't provide cache operations by physical
* address, this prevents us from selectively maintaining caches.
* The future solution will be a kernel that is mapped to every
* address space so we can use virtual addresses of the caller. Up
* until then we apply operations to caches as a whole instead.
*/
if (!_core()) {
cpu->clean_invalidate_data_cache();
cpu->invalidate_instr_cache();
return;
}
auto base = (addr_t)user_arg_1();
auto const size = (size_t)user_arg_2();
cpu->clean_invalidate_data_cache_by_virt_region(base, size);
cpu->invalidate_instr_cache_by_virt_region(base, size);
}
void Thread_event::_signal_acknowledged()
{
/*
* FIXME: this is currently only called as reply to a page-fault resolution.
* On some ARM platforms, we have to do maintainance operations
* after new page table entries where added. If core runs completely
* in privileged mode, we should move this hook to the mappings
* functions.
*/
cpu_pool()->cpu(Cpu::executing_id())->translation_table_insertions();
_thread->_resume();
}

View File

@ -0,0 +1,24 @@
/*
* \brief ARM non-SMP specific kernel thread implementations
* \author Stefan Kalkowski
* \date 2015-12-20
*/
/*
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/pd.h>
#include <kernel/thread.h>
void Kernel::Thread::_call_update_pd()
{
Pd * const pd = (Pd *) user_arg_1();
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
cpu->invalidate_instr_cache();
cpu->clean_invalidate_data_cache();
cpu->invalidate_tlb_by_pid(pd->asid);
}

View File

@ -0,0 +1,42 @@
/*
* \brief Cpu class implementation specific to ARM SMP
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/kernel.h>
#include <kernel/cpu.h>
/* base includes */
#include <unmanaged_singleton.h>
/* spin-lock used to synchronize kernel access of different cpus */
Kernel::Lock & Kernel::data_lock() {
return *unmanaged_singleton<Kernel::Lock>(); }
/**
* Setup non-boot CPUs
*/
extern "C" void init_kernel_mp()
{
using namespace Kernel;
cpu_pool()->cpu(Genode::Cpu::executing_id())->init(*pic(), *core_pd(), board());
kernel();
}
void Kernel::Cpu_domain_update::_domain_update() {
cpu_pool()->cpu(Cpu::executing_id())->invalidate_tlb_by_pid(_domain_id); }

View File

@ -35,8 +35,5 @@ _init_kernel_sp r0, r1
/* do multiprocessor kernel-initialization */
bl init_kernel_mp
/* call the kernel main-routine */
bl kernel
/* catch erroneous return of the kernel main-routine */
1: b 1b

View File

@ -0,0 +1,22 @@
/*
* \brief ARM SMP specific kernel thread implementations
* \author Stefan Kalkowski
* \date 2015-12-20
*/
/*
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/pd.h>
#include <kernel/thread.h>
void Kernel::Thread::_call_update_pd()
{
Pd * const pd = (Pd *) user_arg_1();
if (Cpu_domain_update::_do_global(pd->asid)) { _pause(); }
}

View File

@ -7,7 +7,7 @@
*/
/*
* Copyright (C) 2012-2015 Genode Labs GmbH
* Copyright (C) 2012-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -15,19 +15,41 @@
#include <cpu.h>
#include <kernel/pd.h>
#include <kernel/kernel.h>
void Genode::Arm::flush_data_caches() {
void Genode::Arm::clean_invalidate_data_cache() {
asm volatile ("mcr p15, 0, %[rd], c7, c14, 0" :: [rd]"r"(0) : ); }
void Genode::Arm::invalidate_data_caches() {
asm volatile ("mcr p15, 0, %[rd], c7, c6, 0" :: [rd]"r"(0) : ); }
void Genode::Cpu::init_virt_kernel(Kernel::Pd& pd)
void Genode::Arm::enable_mmu_and_caches(Kernel::Pd& pd)
{
/* check for mapping restrictions */
assert(!Cpu::restricted_page_mappings());
invalidate_tlb();
Cidr::write(pd.asid);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init((Genode::addr_t)pd.translation_table()));
Ttbcr::write(0);
Sctlr::write(Sctlr::init_virt_kernel());
Sctlr::enable_mmu_and_caches();
}
void Genode::Cpu::translation_added(Genode::addr_t const addr,
Genode::size_t const size)
{
using namespace Kernel;
/*
* The Cortex-A8 CPU can't use the L1 cache on page-table
* walks. Therefore, as the page-tables lie in write-back cacheable
* memory we've to clean the corresponding cache-lines even when a
* page table entry is added. We only do this as core as the kernel
* adds translations solely before MMU and caches are enabled.
*/
if (is_user()) update_data_region(addr, size);
else {
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
cpu->clean_invalidate_data_cache();
}
}

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2011-2015 Genode Labs GmbH
* Copyright (C) 2011-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -30,7 +30,7 @@
* Must be inserted directly before the targeted operation. Returns operand
* for targeted operation in R6.
*/
#define FOR_ALL_SET_WAY_OF_ALL_DATA_CACHES_0 \
#define FOR_ALL_SET_WAY_IN_R6_0 \
\
/* get the cache level value (Clidr::Loc) */ \
READ_CLIDR(r0) \
@ -97,7 +97,7 @@
*
* Must be inserted directly after the targeted operation.
*/
#define FOR_ALL_SET_WAY_OF_ALL_DATA_CACHES_1 \
#define FOR_ALL_SET_WAY_IN_R6_1 \
\
/* decrement the index */ \
"subs r7, r7, #1\n" \
@ -129,23 +129,25 @@
::: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9"
void Genode::Arm::flush_data_caches()
void Genode::Arm_v7::invalidate_inner_data_cache()
{
asm volatile (
FOR_ALL_SET_WAY_OF_ALL_DATA_CACHES_0
WRITE_DCCSW(r6)
FOR_ALL_SET_WAY_OF_ALL_DATA_CACHES_1);
Board::outer_cache_flush();
/**
* Data Cache Invalidate by Set/Way for all Set/Way
*/
asm volatile (FOR_ALL_SET_WAY_IN_R6_0
WRITE_DCISW(r6)
FOR_ALL_SET_WAY_IN_R6_1);
}
void Genode::Arm::invalidate_data_caches()
void Genode::Arm_v7::clean_invalidate_inner_data_cache()
{
asm volatile (
FOR_ALL_SET_WAY_OF_ALL_DATA_CACHES_0
WRITE_DCISW(r6)
FOR_ALL_SET_WAY_OF_ALL_DATA_CACHES_1);
Board::outer_cache_invalidate();
/**
* Data Cache Clean by Set/Way for all Set/Way
*/
asm volatile (FOR_ALL_SET_WAY_IN_R6_0
WRITE_DCCSW(r6)
FOR_ALL_SET_WAY_IN_R6_1);
}
@ -157,14 +159,3 @@ Genode::Arm::Psr::access_t Genode::Arm::Psr::init_user_with_trustzone()
A::set(v, 1);
return v;
}
void Genode::Arm_v7::init_virt_kernel(Kernel::Pd & pd)
{
Cidr::write(pd.asid);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init((Genode::addr_t)pd.translation_table()));
Ttbcr::write(0);
Sctlr::write(Sctlr::init_virt_kernel());
inval_branch_predicts();
}

View File

@ -1,99 +0,0 @@
/*
* \brief Cpu class implementation specific to Armv7 SMP
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/pd.h>
#include <kernel/kernel.h>
#include <kernel/test.h>
#include <platform_pd.h>
#include <trustzone.h>
#include <timer.h>
#include <pic.h>
#include <board.h>
#include <platform_thread.h>
/* base includes */
#include <unmanaged_singleton.h>
#include <base/native_types.h>
/* base-hw includes */
#include <kernel/perf_counter.h>
using namespace Kernel;
extern "C" void * _start_secondary_cpus;
Lock & Kernel::data_lock() { return *unmanaged_singleton<Kernel::Lock>(); }
/**
* Setup kernel enviroment after activating secondary CPUs
*/
extern "C" void init_kernel_mp()
{
/*
* As updates on a cached kernel lock might not be visible to CPUs that
* have not enabled caches, we can't synchronize the activation of MMU and
* caches. Hence we must avoid write access to kernel data by now.
*/
/* synchronize data view of all CPUs */
Cpu::invalidate_data_caches();
Cpu::invalidate_instr_caches();
Cpu::data_synchronization_barrier();
/* locally initialize interrupt controller */
pic()->init_cpu_local();
/* initialize CPU in physical mode */
Cpu::init_phys_kernel();
/* switch to core address space */
Cpu::init_virt_kernel(*core_pd());
/*
* Now it's safe to use 'cmpxchg'
*/
{
Lock::Guard guard(data_lock());
/*
* Now it's save to write to kernel data
*/
/* TrustZone initialization code */
init_trustzone(*pic());
/* enable performance counter */
perf_counter()->enable();
/* enable timer interrupt */
unsigned const cpu = Cpu::executing_id();
pic()->unmask(Timer::interrupt_id(cpu), cpu);
PINF("ok CPU awake");
}
}
void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd)
{
if (NR_OF_CPUS > 1) {
Genode::Board::secondary_cpus_ip(&_start_secondary_cpus);
data_synchronization_barrier();
asm volatile ("sev\n");
}
init_kernel_mp();
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -18,7 +18,7 @@ void Kernel::Cpu_context::_init(size_t const stack_size, addr_t const table)
{
r12 = stack_size;
cpu_exception = Genode::Cpu::Ttbr0::init(table);
sctlr = Cpu::Sctlr::init_virt_kernel();
sctlr = Cpu::Sctlr::init_value();
ttbrc = Cpu::Ttbcr::init_virt_kernel();
mair0 = Cpu::Mair0::init_virt_kernel();
}

View File

@ -193,7 +193,7 @@ void Kernel::prepare_hypervisor()
Cpu::Hcptr::write(Cpu::Hcptr::init());
Cpu::Hmair0::write(Cpu::Mair0::init_virt_kernel());
Cpu::Vtcr::write(Cpu::Vtcr::init());
Cpu::Hsctlr::write(Cpu::Sctlr::init_virt_kernel());
Cpu::Hsctlr::write(Cpu::Sctlr::init_value());
/* initialize host context used in virtualization world switch */
*((void**)&_vt_host_context_ptr) = &_mt_master_context_begin;

View File

@ -1,31 +1,24 @@
/*
* \brief Board-specific code for Arndale
* \brief CPU-specific initialization code for Arndale
* \author Stefan Kalkowski
* \date 2015-02-09
* \date 2016-01-07
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <board.h>
#include <cpu.h>
#include <kernel/kernel.h>
#include <kernel/cpu.h>
#include <kernel/vm.h>
#include <unmanaged_singleton.h>
#include <long_translation_table.h>
namespace Kernel {
void prepare_hypervisor(void);
}
namespace Kernel { void prepare_hypervisor(void); }
static unsigned char hyp_mode_stack[1024];
static inline void prepare_nonsecure_world()
{
using Nsacr = Genode::Cpu::Nsacr;
@ -89,7 +82,7 @@ static inline void switch_to_supervisor_mode()
}
void Genode::Board::prepare_kernel()
void Genode::Cpu::init()
{
prepare_nonsecure_world();
Kernel::prepare_hypervisor();

View File

@ -1,11 +1,11 @@
/*
* \brief Kernel backend for protection domains
* \brief Cpu driver implementations specific to ARM Cortex A15
* \author Stefan Kalkowski
* \date 2015-03-20
* \date 2016-01-07
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -15,13 +15,12 @@
#include <kernel/pd.h>
#include <cpu.h>
void Genode::Cpu::init_virt_kernel(Kernel::Pd & pd)
void Genode::Arm_v7::enable_mmu_and_caches(Kernel::Pd & pd)
{
Mair0::write(Mair0::init_virt_kernel());
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init((Genode::addr_t)pd.translation_table(),
pd.asid));
Ttbcr::write(Ttbcr::init_virt_kernel());
Sctlr::write(Sctlr::init_virt_kernel());
inval_branch_predicts();
Cpu::Mair0::write(Cpu::Mair0::init_virt_kernel());
Cpu::Dacr::write(Cpu::Dacr::init_virt_kernel());
Cpu::Ttbr0::write(Cpu::Ttbr0::init((Genode::addr_t)pd.translation_table(), pd.asid));
Cpu::Ttbcr::write(Cpu::Ttbcr::init_virt_kernel());
Cpu::Sctlr::enable_mmu_and_caches();
invalidate_branch_predicts();
}

View File

@ -0,0 +1,16 @@
/*
* \brief Cpu-specific code for Cortex A15
* \author Stefan Kalkowski
* \date 2016-01-07
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <cpu.h>
void Genode::Cpu::init() {}

View File

@ -0,0 +1,65 @@
/*
* \brief Cpu class implementation specific to Cortex A15 SMP
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/pd.h>
#include <pic.h>
#include <board.h>
/* base-hw includes */
#include <kernel/perf_counter.h>
using namespace Kernel;
/* entrypoint for non-boot CPUs */
extern "C" void * _start_secondary_cpus;
/* indicates boot cpu status */
static volatile bool primary_cpu = true;
void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd, Genode::Board & board)
{
/*
* local interrupt controller interface needs to be initialized that early,
* because it potentially sets the SGI interrupts to be non-secure before
* entering the normal world in Genode::Cpu::init()
*/
pic.init_cpu_local();
Genode::Cpu::init();
Sctlr::init();
Psr::write(Psr::init_kernel());
invalidate_inner_data_cache();
/* primary cpu wakes up all others */
if (primary_cpu && NR_OF_CPUS > 1) {
primary_cpu = false;
board.wake_up_all_cpus(&_start_secondary_cpus);
}
enable_mmu_and_caches(core_pd);
{
Lock::Guard guard(data_lock());
/* enable performance counter */
perf_counter()->enable();
/* enable timer interrupt */
pic.unmask(Timer::interrupt_id(id()), id());
}
}

View File

@ -0,0 +1,56 @@
/*
* \brief CPU driver for core Arm Cortex A8 specific implementation
* \author Martin stein
* \author Stefan Kalkowski
* \date 2015-12-14
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <cpu.h>
#include <kernel/kernel.h>
#include <kernel/cpu.h>
#include <kernel/pd.h>
void Genode::Cpu::translation_table_insertions()
{
clean_invalidate_data_cache();
invalidate_tlb();
}
void Genode::Cpu::translation_added(Genode::addr_t const addr,
Genode::size_t const size)
{
using namespace Kernel;
/*
* The Cortex-A8 CPU can't use the L1 cache on page-table
* walks. Therefore, as the page-tables lie in write-back cacheable
* memory we've to clean the corresponding cache-lines even when a
* page table entry is added. We only do this as core as the kernel
* adds translations solely before MMU and caches are enabled.
*/
if (is_user()) update_data_region(addr, size);
else {
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
cpu->clean_invalidate_data_cache();
}
}
void Genode::Arm_v7::enable_mmu_and_caches(Kernel::Pd & pd)
{
invalidate_tlb();
Cpu::Cidr::write(pd.asid);
Cpu::Dacr::write(Dacr::init_virt_kernel());
Cpu::Ttbr0::write(Ttbr0::init((Genode::addr_t)pd.translation_table()));
Cpu::Ttbcr::write(0);
Cpu::Sctlr::enable_mmu_and_caches();
invalidate_branch_predicts();
}

View File

@ -0,0 +1,28 @@
/*
* \brief CPU driver for core
* \author Martin stein
* \author Stefan Kalkowski
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <kernel/pd.h>
#include <cpu.h>
void Genode::Arm_v7::enable_mmu_and_caches(Kernel::Pd & pd)
{
invalidate_tlb();
Cpu::Cidr::write(pd.asid);
Cpu::Dacr::write(Dacr::init_virt_kernel());
Cpu::Ttbr0::write(Ttbr0::init((Genode::addr_t)pd.translation_table()));
Cpu::Ttbcr::write(0);
Cpu::Sctlr::enable_mmu_and_caches();
invalidate_branch_predicts();
}

View File

@ -0,0 +1,128 @@
/*
* \brief Cpu class implementation specific to Cortex A9 SMP
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/pd.h>
#include <pic.h>
#include <scu.h>
#include <board.h>
/* base-hw includes */
#include <kernel/perf_counter.h>
using namespace Kernel;
/* entrypoint for non-boot CPUs */
extern "C" void * _start_secondary_cpus;
/**
* SMP-safe simple counter
*/
class Counter
{
private:
Kernel::Lock _lock;
volatile int _value = 0;
public:
void inc()
{
Kernel::Lock::Guard guard(_lock);
Genode::memory_barrier();
_value++;
}
void wait_for(int const v) {
while (_value < v) ; }
};
static volatile bool primary_cpu = true; /* indicates boot cpu status */
static Counter data_cache_invalidated; /* counts cpus that invalidated
their data cache */
static Counter data_cache_enabled; /* counts cpus that enabled
their data cache */
static Counter smp_coherency_enabled; /* counts cpus that enabled
their SCU */
/*
* The initialization of Cortex A9 multicore systems implies a sophisticated
* algorithm in early revisions of this cpu.
*
* See ARM's Cortex-A9 MPCore TRM r2p0 in section 5.3.5 for more details
*/
void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd, Genode::Board & board)
{
bool primary = primary_cpu;
if (primary) primary_cpu = false;
Sctlr::init();
Psr::write(Psr::init_kernel());
/* locally initialize interrupt controller */
pic.init_cpu_local();
invalidate_inner_data_cache();
data_cache_invalidated.inc();
/* primary cpu wakes up all others */
if (primary && NR_OF_CPUS > 1)
board.wake_up_all_cpus(&_start_secondary_cpus);
/* wait for other cores' data cache invalidation */
data_cache_invalidated.wait_for(NR_OF_CPUS);
if (primary) {
Genode::Scu scu(board);
scu.invalidate();
board.l2_cache().invalidate();
scu.enable();
}
/* secondary cpus wait for the primary's cache activation */
if (!primary) data_cache_enabled.wait_for(1);
enable_mmu_and_caches(core_pd);
data_cache_enabled.inc();
clean_invalidate_inner_data_cache();
/* wait for other cores' data cache activation */
data_cache_enabled.wait_for(NR_OF_CPUS);
if (primary) board.l2_cache().enable();
/* secondary cpus wait for the primary's coherency activation */
if (!primary) smp_coherency_enabled.wait_for(1);
Actlr::enable_smp();
smp_coherency_enabled.inc();
/* wait for other cores' coherency activation */
smp_coherency_enabled.wait_for(NR_OF_CPUS);
init_advanced_fp_simd();
{
Lock::Guard guard(data_lock());
/* enable performance counter */
perf_counter()->enable();
/* enable timer interrupt */
pic.unmask(Timer::interrupt_id(id()), id());
}
}

View File

@ -18,7 +18,4 @@
using namespace Genode;
unsigned Cpu::executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); }
unsigned Cpu::primary_id() { return Board::PRIMARY_MPIDR_AFF_0; }

View File

@ -59,6 +59,4 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
}
bool Imx::Board::is_smp() { return false; }
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }

View File

@ -40,15 +40,10 @@ bool secure_irq(unsigned const i)
}
void Kernel::init_trustzone(Pic * pic)
void Kernel::init_trustzone(Pic & pic)
{
using namespace Genode;
/* check for compatibility */
if (NR_OF_CPUS > 1) {
PERR("trustzone not supported with multiprocessing");
return;
}
/* set exception vector entry */
Cpu::mon_exception_entry_at((Genode::addr_t)&_mon_kernel_entry);
@ -60,7 +55,7 @@ void Kernel::init_trustzone(Pic * pic)
/* configure non-secure interrupts */
for (unsigned i = 0; i < Pic::NR_OF_IRQ; i++) {
if (!secure_irq(i)) { pic->unsecure(i); } }
if (!secure_irq(i)) { pic.unsecure(i); } }
/* configure central security unit */
Genode::Csu csu(Board::CSU_BASE);
@ -110,6 +105,4 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
}
bool Imx::Board::is_smp() { return false; }
Cpu::User_context::User_context() { cpsr = Psr::init_user_with_trustzone(); }

View File

@ -7,7 +7,7 @@
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
* Copyright (C) 2014-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -49,11 +49,26 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
/* CPU-local core MMIO like interrupt controller and timer */
{ Board::CORTEX_A9_PRIVATE_MEM_BASE, Board::CORTEX_A9_PRIVATE_MEM_SIZE },
/* l2 cache controller */
{ Board::PL310_MMIO_BASE, Board::PL310_MMIO_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
bool Imx::Board::is_smp() { return true; }
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }
bool Cortex_a9::Board::errata(Cortex_a9::Board::Errata err)
{
switch (err) {
case Cortex_a9::Board::ARM_754322:
case Cortex_a9::Board::ARM_764369:
case Cortex_a9::Board::ARM_775420:
case Cortex_a9::Board::PL310_588369:
case Cortex_a9::Board::PL310_727915:
case Cortex_a9::Board::PL310_769419:
return true;
};
return false;
}

View File

@ -16,6 +16,7 @@
#include <board.h>
#include <cpu.h>
#include <pic.h>
#include <cortex_a9_wugen.h>
#include <unmanaged_singleton.h>
using namespace Genode;
@ -62,13 +63,27 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
}
static Genode::L2_cache * l2_cache() {
return unmanaged_singleton<Genode::L2_cache>(); }
void Board::outer_cache_invalidate() { l2_cache()->invalidate(); }
void Board::outer_cache_flush() { l2_cache()->flush(); }
void Board::prepare_kernel() { l2_cache()->invalidate(); }
void Cortex_a9::Board::wake_up_all_cpus(void * const ip)
{
Cortex_a9_wugen wugen;
wugen.init_cpu_1(ip);
asm volatile("dsb\n"
"sev\n");
}
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }
void Cpu::Actlr::enable_smp() {
Kernel::board().monitor().call(Board::Secure_monitor::CPU_ACTLR_SMP_BIT_RAISE, 0); }
bool Cortex_a9::Board::errata(Cortex_a9::Board::Errata err)
{
switch (err) {
case Cortex_a9::Board::PL310_588369:
case Cortex_a9::Board::PL310_727915: return true;
default: ;
};
return false;
}

View File

@ -0,0 +1,45 @@
/*
* \brief Board implementation specific to PBXA9
* \author Stefan Kalkowski
* \date 2016-01-07
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <util/mmio.h>
#include <board.h>
#include <kernel/kernel.h>
bool Cortex_a9::Board::errata(Cortex_a9::Board::Errata err) {
return false; }
void Cortex_a9::Board::wake_up_all_cpus(void * const ip)
{
/**
* set the entrypoint for the other CPUs via the flags register
* of the system control registers. ARMs boot monitor code will
* read out this register and jump to it after the cpu received
* an interrupt
*/
struct System_control : Genode::Mmio
{
struct Flagsset : Register<0x30, 32> { };
struct Flagsclr : Register<0x34, 32> { };
System_control(void * const ip)
: Mmio(SYSTEM_CONTROL_MMIO_BASE)
{
write<Flagsclr>(~0UL);
write<Flagsset>(reinterpret_cast<Flagsset::access_t>(ip));
}
} sc(ip);
/* send an IPI to all other cpus */
Kernel::pic()->send_ipi();
}

View File

@ -50,7 +50,10 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
{ Board::CORTEX_A9_PRIVATE_MEM_BASE, Board::CORTEX_A9_PRIVATE_MEM_SIZE },
/* core UART */
{ Board::PL011_0_MMIO_BASE, Board::PL011_0_MMIO_SIZE }
{ Board::PL011_0_MMIO_BASE, Board::PL011_0_MMIO_SIZE },
/* L2 Cache Controller */
{ Board::PL310_MMIO_BASE, Board::PL310_MMIO_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

@ -0,0 +1,108 @@
/*
* \brief ARM with SMP support specific aspects of the kernel cpu objects
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2016-01-07
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/cpu.h>
namespace Kernel
{
/**
* Lists all pending domain updates
*/
class Cpu_domain_update_list;
}
class Kernel::Cpu_domain_update_list
: public Double_list_typed<Cpu_domain_update>
{
public:
/**
* Perform all pending domain updates on the executing CPU
*/
void do_each() {
for_each([] (Cpu_domain_update * const u) { u->_do(); }); }
};
using namespace Kernel;
/**
* Return singleton of the CPU domain-udpate list
*/
Cpu_domain_update_list & cpu_domain_update_list() {
return *unmanaged_singleton<Cpu_domain_update_list>(); }
void Cpu::Ipi::occurred()
{
cpu_domain_update_list().do_each();
pending = false;
}
void Cpu::Ipi::trigger(unsigned const cpu_id)
{
if (pending) return;
pic()->send_ipi(cpu_id);
pending = true;
}
Cpu::Ipi::Ipi(Irq::Pool &p) : Irq(Pic::IPI, p) { }
/***********************
** Cpu_domain_update **
***********************/
void Cpu_domain_update::_do()
{
/* perform domain update locally and get pending bit */
unsigned const id = Cpu::executing_id();
if (!_pending[id]) return;
_domain_update();
_pending[id] = false;
/* check wether there are still CPUs pending */
for (unsigned i = 0; i < NR_OF_CPUS; i++)
if (_pending[i]) return;
/* as no CPU is pending anymore, end the domain update */
cpu_domain_update_list().remove(this);
_cpu_domain_update_unblocks();
}
bool Cpu_domain_update::_do_global(unsigned const domain_id)
{
/* perform locally and leave it at that if in uniprocessor mode */
_domain_id = domain_id;
_domain_update();
if (NR_OF_CPUS == 1) return false;
/* inform other CPUs and block until they are done */
cpu_domain_update_list().insert_tail(this);
unsigned const cpu_id = Cpu::executing_id();
for (unsigned i = 0; i < NR_OF_CPUS; i++) {
if (i == cpu_id) continue;
_pending[i] = true;
cpu_pool()->cpu(i)->trigger_ip_interrupt();
}
return true;
}

View File

@ -1,12 +1,12 @@
/*
* \brief Kernel entrypoint
* \brief Kernel entrypoint for SMP systems
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-20
*/
/*
* Copyright (C) 2011-2015 Genode Labs GmbH
* Copyright (C) 2011-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.

View File

@ -1,11 +1,12 @@
/*
* \brief Class for kernel data that is needed to manage a specific CPU
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2015-02-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -28,21 +29,7 @@ Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::MIN, 0)
}
void Cpu_idle::exception(unsigned const cpu)
{
if (trapno == RESET) {
return;
} else if (trapno >= INTERRUPTS_START && trapno <= INTERRUPTS_END) {
_interrupt(cpu);
return;
}
PWRN("Unknown exception %lu with error code %lu at ip=%p", trapno,
errcode, (void *)ip);
assert(0);
}
void Kernel::Cpu::init(Pic &pic, Kernel::Pd &core_pd)
void Kernel::Cpu::init(Pic &pic, Kernel::Pd &core_pd, Genode::Board&)
{
Timer::disable_pit();
@ -62,3 +49,6 @@ void Kernel::Cpu::init(Pic &pic, Kernel::Pd &core_pd)
unsigned const cpu = Cpu::executing_id();
pic.unmask(Timer::interrupt_id(cpu), cpu);
}
void Cpu_domain_update::_domain_update() { }

View File

@ -0,0 +1,30 @@
/*
* \brief Kernel backend for protection domains
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2016-01-11
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <assert.h>
#include <kernel/cpu.h>
void Kernel::Cpu_idle::exception(unsigned const cpu)
{
if (trapno == RESET) return;
if (trapno >= INTERRUPTS_START && trapno <= INTERRUPTS_END) {
_interrupt(cpu);
return;
}
PWRN("Unknown exception %lu with error code %lu at ip=%p", trapno,
errcode, (void *)ip);
assert(0);
}

View File

@ -2,11 +2,12 @@
* \brief Kernel backend for execution contexts in userland
* \author Adrian-Ken Rueegsegger
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2015-02-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -17,31 +18,11 @@
using namespace Kernel;
void Thread::exception(unsigned const cpu)
{
switch (trapno) {
case PAGE_FAULT:
_mmu_exception();
return;
case NO_MATH_COPROC:
if (_cpu->retry_fpu_instr(&_lazy_state)) { return; }
PWRN("%s -> %s: FPU error", pd_label(), label());
_stop();
return;
case UNDEFINED_INSTRUCTION:
PWRN("%s -> %s: undefined instruction at ip=%p",
pd_label(), label(), (void*)ip);
_stop();
return;
case SUPERVISOR_CALL:
_call();
return;
}
if (trapno >= INTERRUPTS_START && trapno <= INTERRUPTS_END) {
_interrupt(cpu);
return;
}
PWRN("%s -> %s: triggered unknown exception %lu with error code %lu"
" at ip=%p", pd_label(), label(), trapno, errcode, (void*)ip);
_stop();
}
void Thread::_call_update_data_region() { }
void Thread::_call_update_instr_region() { }
void Thread_event::_signal_acknowledged() { _thread->_resume(); }

View File

@ -0,0 +1,48 @@
/*
* \brief Kernel backend for execution contexts in userland
* \author Adrian-Ken Rueegsegger
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2015-02-09
*/
/*
* Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/thread.h>
using namespace Kernel;
void Thread::exception(unsigned const cpu)
{
switch (trapno) {
case PAGE_FAULT:
_mmu_exception();
return;
case NO_MATH_COPROC:
if (_cpu->retry_fpu_instr(&_lazy_state)) { return; }
PWRN("%s -> %s: FPU error", pd_label(), label());
_stop();
return;
case UNDEFINED_INSTRUCTION:
PWRN("%s -> %s: undefined instruction at ip=%p",
pd_label(), label(), (void*)ip);
_stop();
return;
case SUPERVISOR_CALL:
_call();
return;
}
if (trapno >= INTERRUPTS_START && trapno <= INTERRUPTS_END) {
_interrupt(cpu);
return;
}
PWRN("%s -> %s: triggered unknown exception %lu with error code %lu"
" at ip=%p", pd_label(), label(), trapno, errcode, (void*)ip);
_stop();
}

View File

@ -1,44 +0,0 @@
/*
* \brief Class for kernel data that is needed to manage a specific CPU
* \author Reto Buerki
* \date 2015-04-28
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/cpu.h>
#include <kernel/kernel.h>
#include <kernel/pd.h>
using namespace Kernel;
Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::MIN, 0)
{
Cpu_job::cpu(cpu);
ip = (addr_t)&_main;
sp = (addr_t)&_stack[stack_size];
init((addr_t)core_pd()->translation_table(), true);
}
void Cpu_idle::exception(unsigned const cpu)
{
if (trapno == RESET) return;
if (trapno >= INTERRUPTS_START && trapno <= INTERRUPTS_END) {
pic()->irq_occurred(trapno);
_interrupt(cpu);
return;
}
PWRN("Unknown exception %lu with error code %lu at ip=%p", trapno,
errcode, (void *)ip);
assert(0);
}

View File

@ -0,0 +1,31 @@
/*
* \brief Kernel backend for protection domains
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2016-01-11
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <assert.h>
#include <kernel/cpu.h>
void Kernel::Cpu_idle::exception(unsigned const cpu)
{
if (trapno == RESET) return;
if (trapno >= INTERRUPTS_START && trapno <= INTERRUPTS_END) {
pic()->irq_occurred(trapno);
_interrupt(cpu);
return;
}
PWRN("Unknown exception %lu with error code %lu at ip=%p", trapno,
errcode, (void *)ip);
assert(0);
}

View File

@ -33,6 +33,7 @@ void Thread::exception(unsigned const cpu)
PWRN("%s -> %s: undefined instruction at ip=%p",
pd_label(), label(), (void*)ip);
_stop();
return;
case SUPERVISOR_CALL:
_call();
return;

View File

@ -1,11 +1,12 @@
/*
* \brief Platform implementations specific for base-hw and Zynq
* \author Johannes Schlatow
* \author Stefan Kalkowski
* \date 2014-12-15
*/
/*
* Copyright (C) 2012-2014 Genode Labs GmbH
* Copyright (C) 2014-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -66,10 +67,5 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }
static Genode::Pl310 * l2_cache() {
return unmanaged_singleton<Genode::Pl310>(Board::PL310_MMIO_BASE); }
void Genode::Board::outer_cache_invalidate() { l2_cache()->invalidate(); }
void Genode::Board::outer_cache_flush() { l2_cache()->flush(); }
void Genode::Board::prepare_kernel() { l2_cache()->invalidate(); }
bool Cortex_a9::Board::errata(Cortex_a9::Board::Errata err) {
return false; }

View File

@ -7,8 +7,8 @@
*/
/*
* Copyright (C) 2014-2015 Ksys Labs LLC
* Copyright (C) 2014-2015 Genode Labs GmbH
* Copyright (C) 2014-2016 Ksys Labs LLC
* Copyright (C) 2014-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -56,6 +56,10 @@ struct Genode::Board_base
CORTEX_A9_PRIVATE_MEM_SIZE = 0x00002000,
CORTEX_A9_PRIVATE_TIMER_CLK = 395037500,
/* L2 cache controller */
PL310_MMIO_BASE = 0x00a02000,
PL310_MMIO_SIZE = 0x00001000,
/* CPU cache */
CACHE_LINE_SIZE_LOG2 = 5,

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -46,10 +46,17 @@ struct Genode::Board_base
/* clocks */
OSC_6_CLOCK = 24*1000*1000,
/* system controller */
SYSTEM_CONTROL_MMIO_BASE = 0x10000000,
/* CPU */
CORTEX_A9_PRIVATE_TIMER_CLK = 100000000,
CORTEX_A9_PRIVATE_MEM_BASE = 0x1f000000,
CORTEX_A9_PRIVATE_MEM_SIZE = 0x01000000,
CORTEX_A9_PRIVATE_MEM_SIZE = 0x2000,
/* L2 cache controller */
PL310_MMIO_BASE = 0x1f002000,
PL310_MMIO_SIZE = 0x00001000,
/* UART */
PL011_0_MMIO_BASE = 0x10009000,

View File

@ -5,11 +5,13 @@
#
if {
![have_spec hw_arndale] &&
![have_spec foc_x86_32] &&
![have_spec foc_x86_64] &&
![have_spec foc_panda] &&
![have_spec foc_arndale] &&
![have_spec hw_arndale] &&
![have_spec hw_wand_quad] &&
![have_spec hw_panda] &&
![have_spec foc_x86_32] &&
![have_spec foc_x86_64] &&
![have_spec foc_panda] &&
![have_spec foc_arndale] &&
![have_spec foc_odroid_x2] &&
![have_spec nova]
} {

View File

@ -4,10 +4,6 @@
# \author Alexander Boettcher
#
if {[have_spec hw_panda]} {
puts "Platform is unsupported."
exit 0
}
build "core init test/mp_server"