hw: adjust core bootstrap to fit generic process

* Introduce hw-specific crt0 for core that calls e.g.: init_main_thread
* re-map core's main thread UTCB to fit the right context area location
* switch core's main thread's stack to fit the right context area location

Fix #1440
This commit is contained in:
Stefan Kalkowski 2015-03-09 15:00:58 +01:00 committed by Christian Helmuth
parent 2ad6a3b934
commit 657646e76e
17 changed files with 344 additions and 272 deletions

View File

@ -13,6 +13,7 @@ SRC_CC += spec/arm/kernel/thread.cc
SRC_CC += spec/arm/kernel/cpu.cc
# add assembly sources
SRC_S += spec/arm/kernel/crt0.s
SRC_S += spec/arm/crt0.s
# include less specific configuration

View File

@ -11,6 +11,7 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/arm_v6
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
# add assembly sources
SRC_S += spec/arm_v6/mode_transition.s

View File

@ -7,6 +7,9 @@
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_v7
# add C++ sources
SRC_CC += spec/arm_v7/cpu.cc
# add assembly sources
SRC_S += spec/arm_v7/mode_transition.s

View File

@ -7,9 +7,6 @@
# add library dependencies
LIBS += core-perf_counter
# set entry point of core's first thread
CC_OPT += -DCORE_MAIN=_main
# add library dependencies
LIBS += base-common
@ -54,6 +51,7 @@ SRC_CC += kernel/signal_receiver.cc
SRC_CC += kernel/irq.cc
SRC_CC += kernel/pd.cc
SRC_CC += kernel/cpu.cc
SRC_CC += init_main_thread.cc
# add assembly sources
SRC_S += boot_modules.s

View File

@ -63,12 +63,10 @@ void prepare_reinit_main_thread() { prepare_init_main_thread(); }
** Thread_base **
*****************/
extern Native_utcb* main_thread_utcb();
Native_utcb * Thread_base::utcb()
{
if (this) { return &_context->utcb; }
return main_thread_utcb();
return UTCB_MAIN_THREAD;
}

View File

@ -26,12 +26,6 @@ extern Ram_dataspace_capability _main_thread_utcb_ds;
extern Native_thread_id _main_thread_id;
/**
* Return virtual UTCB location of main threads
*/
Native_utcb * main_thread_utcb() { return UTCB_MAIN_THREAD; }
/*****************
** Thread_base **
*****************/

View File

@ -252,7 +252,7 @@ class Genode::Arm
/**
* Return value initialized for user execution with trustzone
*/
inline static access_t init_user_with_trustzone();
static access_t init_user_with_trustzone();
/**
* Do common initialization on register value 'v'
@ -467,12 +467,12 @@ class Genode::Arm
/**
* Flush all entries of all data caches
*/
inline static void flush_data_caches();
static void flush_data_caches();
/**
* Invalidate all entries of all data caches
*/
inline static void invalidate_data_caches();
static void invalidate_data_caches();
/**
* Flush all caches

View File

@ -160,6 +160,7 @@ class Genode::Cpu : public Arm
* adds translations solely before MMU and caches are enabled.
*/
if (is_user()) Kernel::update_data_region(addr, size);
else flush_data_caches();
}
/**
@ -182,16 +183,4 @@ class Genode::Cpu : public Arm
static void invalidate_control_flow_predictions() { /* FIXME */ }
};
void Genode::Arm::flush_data_caches()
{
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) : );
}
#endif /* _CPU_H_ */

View File

@ -18,119 +18,6 @@
#include <spec/arm/cpu_support.h>
#include <board.h>
/**
* Helpers that increase readability of MCR and MRC commands
*/
#define READ_CLIDR(rd) "mrc p15, 1, " #rd ", c0, c0, 1\n"
#define READ_CCSIDR(rd) "mrc p15, 1, " #rd ", c0, c0, 0\n"
#define WRITE_CSSELR(rs) "mcr p15, 2, " #rs ", c0, c0, 0\n"
#define WRITE_DCISW(rs) "mcr p15, 0, " #rs ", c7, c6, 2\n"
#define WRITE_DCCSW(rs) "mcr p15, 0, " #rs ", c7, c10, 2\n"
/**
* First macro to do a set/way operation on all entries of all data caches
*
* 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 \
\
/* get the cache level value (Clidr::Loc) */ \
READ_CLIDR(r0) \
"ands r3, r0, #0x7000000\n" \
"mov r3, r3, lsr #23\n" \
\
/* skip all if cache level value is zero */ \
"beq 5f\n" \
"mov r9, #0\n" \
\
/* begin loop over cache numbers */ \
"1:\n" \
\
/* work out 3 x cache level */ \
"add r2, r9, r9, lsr #1\n" \
\
/* get the cache type of current cache number (Clidr::CtypeX) */ \
"mov r1, r0, lsr r2\n" \
"and r1, r1, #7\n" \
"cmp r1, #2\n" \
\
/* skip cache number if there's no data cache at this level */ \
"blt 4f\n" \
\
/* select the appropriate CCSIDR according to cache level and type */ \
WRITE_CSSELR(r9) \
"isb\n" \
\
/* get the line length of current cache (Ccsidr::LineSize) */ \
READ_CCSIDR(r1) \
"and r2, r1, #0x7\n" \
\
/* add 4 for the line-length offset (log2 of 16 bytes) */ \
"add r2, r2, #4\n" \
\
/* get the associativity or max way size (Ccsidr::Associativity) */ \
"ldr r4, =0x3ff\n" \
"ands r4, r4, r1, lsr #3\n" \
\
/* get the bit position of the way-size increment */ \
"clz r5, r4\n" \
\
/* get a working copy of the max way size */ \
"mov r8, r4\n" \
\
/* begin loop over way numbers */ \
"2:\n" \
\
/* get the number of sets or the max index size (Ccsidr::NumSets) */ \
"ldr r7, =0x00007fff\n" \
"ands r7, r7, r1, lsr #13\n" \
\
/* begin loop over indices */ \
"3:\n" \
\
/* factor in the way number and cache number into write value */ \
"orr r6, r9, r8, lsl r5\n" \
\
/* factor in the index number into write value */ \
"orr r6, r6, r7, lsl r2\n"
/**
* Second macro to do a set/way operation on all entries of all data caches
*
* Must be inserted directly after the targeted operation.
*/
#define FOR_ALL_SET_WAY_OF_ALL_DATA_CACHES_1 \
\
/* decrement the index */ \
"subs r7, r7, #1\n" \
\
/* end loop over indices */ \
"bge 3b\n" \
\
/* decrement the way number */ \
"subs r8, r8, #1\n" \
\
/* end loop over way numbers */ \
"bge 2b\n" \
\
/* label to skip a cache number */ \
"4:\n" \
\
/* increment the cache number */ \
"add r9, r9, #2\n" \
"cmp r3, r9\n" \
\
/* end loop over cache numbers */ \
"bgt 1b\n" \
\
/* synchronize data */ \
"dsb\n" \
\
/* label to skip all */ \
"5:\n" \
::: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9"
namespace Genode
{
/**
@ -344,34 +231,4 @@ class Genode::Arm_v7 : public Arm
asm volatile ("mcr p15, 4, %[rd], c12, c0, 0" :: [rd] "r" (a)); }
};
void Genode::Arm::flush_data_caches()
{
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();
}
void Genode::Arm::invalidate_data_caches()
{
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();
}
Genode::Arm::Psr::access_t Genode::Arm::Psr::init_user_with_trustzone()
{
access_t v = 0;
M::set(v, M::USR);
I::set(v, 1);
A::set(v, 1);
return v;
}
#endif /* _SPEC__ARM_V7__CPU_SUPPORT_H_ */

View File

@ -62,6 +62,7 @@ class Genode::Cpu : public Arm_v7
* adds translations solely before MMU and caches are enabled.
*/
if (is_user()) Kernel::update_data_region(addr, size);
else flush_data_caches();
}
/**

View File

@ -40,14 +40,12 @@
#include <kernel/perf_counter.h>
using namespace Kernel;
extern "C" void _core_start(void);
extern Genode::Native_thread_id _main_thread_id;
extern "C" void CORE_MAIN();
extern void * _start_secondary_cpus;
extern int _prog_img_beg;
extern int _prog_img_end;
Genode::Native_utcb * _main_thread_utcb;
namespace Kernel
{
/* import Genode types */
@ -231,9 +229,11 @@ extern "C" void init_kernel_up()
*/
void init_kernel_mp_primary()
{
using namespace Genode;
/* get stack memory that fullfills the constraints for core stacks */
enum {
STACK_ALIGNM = 1 << Genode::CORE_STACK_ALIGNM_LOG2,
STACK_ALIGNM = 1 << CORE_STACK_ALIGNM_LOG2,
STACK_SIZE = DEFAULT_STACK_SIZE,
};
static_assert(STACK_SIZE <= STACK_ALIGNM - sizeof(Core_thread_id),
@ -243,19 +243,27 @@ void init_kernel_mp_primary()
/* provide thread ident at the aligned base of the stack */
*(Core_thread_id *)s = 0;
/* initialize UTCB and map it */
static Native_utcb utcb __attribute__((aligned(get_page_size())));
static Dataspace_component main_utcb_ds(sizeof(Native_utcb),
(addr_t)UTCB_MAIN_THREAD,
(addr_t)&utcb, CACHED, true, 0);
Genode::map_local((addr_t)&utcb, (addr_t)UTCB_MAIN_THREAD,
sizeof(Native_utcb) / get_page_size());
static Kernel::Thread t(Cpu_priority::max, 0, "core");
/* start thread with stack pointer at the top of stack */
static Native_utcb utcb;
static Thread t(Cpu_priority::max, 0, "core");
_main_thread_id = t.id();
_main_thread_utcb = &utcb;
_main_thread_utcb->start_info()->init(t.id(), Genode::Native_capability());
t.ip = (addr_t)CORE_MAIN;;
utcb.start_info()->init(t.id(),
Dataspace_capability::local_cap(&main_utcb_ds));
t.ip = (addr_t)&_core_start;
t.sp = (addr_t)s + STACK_SIZE;
t.init(cpu_pool()->primary_cpu(), core_pd(), &utcb, 1);
t.init(cpu_pool()->primary_cpu(), core_pd(),
(Native_utcb*)Genode::UTCB_MAIN_THREAD, 1);
/* initialize user interrupt objects */
static Genode::uint8_t _irqs[Pic::NR_OF_IRQ * sizeof(User_irq)];
for (unsigned i = 0; i < Pic::NR_OF_IRQ; i++) {
static Genode::uint8_t _irqs[Kernel::Pic::NR_OF_IRQ * sizeof(User_irq)];
for (unsigned i = 0; i < Kernel::Pic::NR_OF_IRQ; i++) {
if (private_interrupt(i)) { continue; }
new (&_irqs[i * sizeof(User_irq)]) User_irq(i);
}

View File

@ -1,93 +1,33 @@
/*
* \brief Startup code for core
* \author Martin Stein
/**
* \brief Startup code for core on ARM
* \author Stefan Kalkowski
* \date 2011-10-01
* \date 2015-03-06
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* 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.
*/
/************
** Macros **
************/
/* core includes */
.include "macros.s"
/**************************
** .text (program code) **
**************************/
.section ".text"
/**
* Get base of the first kernel-stack and the common kernel-stack size
*
* \param base_dst_reg register that shall receive the stack-area base
* \param size_dst_reg register that shall receive the size of a kernel stack
*/
.macro _get_constraints_of_kernel_stacks base_dst_reg, size_dst_reg
/* program entry-point */
.global _core_start
_core_start:
ldr \base_dst_reg, =kernel_stack
ldr \size_dst_reg, =kernel_stack_size
ldr \size_dst_reg, [\size_dst_reg]
.endm
/* create proper environment for main thread */
bl init_main_thread
/* apply environment that was created by init_main_thread */
ldr sp, =init_main_thread_result
ldr sp, [sp]
.section ".text.crt0"
/**********************************
** Startup code for primary CPU **
**********************************/
.global _start
_start:
/* idle a little initially because U-Boot likes it this way */
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
/* zero-fill BSS segment */
ldr r0, =_bss_start
ldr r1, =_bss_end
mov r2, #0
1:
cmp r1, r0
ble 2f
str r2, [r0]
add r0, r0, #4
b 1b
2:
/* setup temporary stack pointer for uniprocessor mode */
_get_constraints_of_kernel_stacks r0, r1
add sp, r0, r1
/* uniprocessor kernel-initialization which activates multiprocessor */
bl init_kernel_up
/*********************************************
** Startup code that is common to all CPUs **
*********************************************/
.global _start_secondary_cpus
_start_secondary_cpus:
/* setup multiprocessor-aware kernel stack-pointer */
_get_constraints_of_kernel_stacks r0, r1
_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
/* jump into init C code instead of calling it as it should never return */
b _main

View File

@ -0,0 +1,93 @@
/*
* \brief Startup code for core
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-01
*/
/*
* Copyright (C) 2011-2013 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.
*/
/************
** Macros **
************/
/* core includes */
.include "macros.s"
/**
* Get base of the first kernel-stack and the common kernel-stack size
*
* \param base_dst_reg register that shall receive the stack-area base
* \param size_dst_reg register that shall receive the size of a kernel stack
*/
.macro _get_constraints_of_kernel_stacks base_dst_reg, size_dst_reg
ldr \base_dst_reg, =kernel_stack
ldr \size_dst_reg, =kernel_stack_size
ldr \size_dst_reg, [\size_dst_reg]
.endm
.section ".text.crt0"
/**********************************
** Startup code for primary CPU **
**********************************/
.global _start
_start:
/* idle a little initially because U-Boot likes it this way */
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
/* zero-fill BSS segment */
ldr r0, =_bss_start
ldr r1, =_bss_end
mov r2, #0
1:
cmp r1, r0
ble 2f
str r2, [r0]
add r0, r0, #4
b 1b
2:
/* setup temporary stack pointer for uniprocessor mode */
_get_constraints_of_kernel_stacks r0, r1
add sp, r0, r1
/* uniprocessor kernel-initialization which activates multiprocessor */
bl init_kernel_up
/*********************************************
** Startup code that is common to all CPUs **
*********************************************/
.global _start_secondary_cpus
_start_secondary_cpus:
/* setup multiprocessor-aware kernel stack-pointer */
_get_constraints_of_kernel_stacks r0, r1
_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 CPU driver for core
* \author Norman Feske
* \author Martin stein
* \author Stefan Kalkowski
* \date 2012-08-30
*/
/*
* Copyright (C) 2012-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>
void Genode::Arm::flush_data_caches() {
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) : ); }

View File

@ -0,0 +1,158 @@
/*
* \brief CPU driver for core
* \author Martin stein
* \author Stefan Kalkowski
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-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>
/**
* Helpers that increase readability of MCR and MRC commands
*/
#define READ_CLIDR(rd) "mrc p15, 1, " #rd ", c0, c0, 1\n"
#define READ_CCSIDR(rd) "mrc p15, 1, " #rd ", c0, c0, 0\n"
#define WRITE_CSSELR(rs) "mcr p15, 2, " #rs ", c0, c0, 0\n"
#define WRITE_DCISW(rs) "mcr p15, 0, " #rs ", c7, c6, 2\n"
#define WRITE_DCCSW(rs) "mcr p15, 0, " #rs ", c7, c10, 2\n"
/**
* First macro to do a set/way operation on all entries of all data caches
*
* 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 \
\
/* get the cache level value (Clidr::Loc) */ \
READ_CLIDR(r0) \
"ands r3, r0, #0x7000000\n" \
"mov r3, r3, lsr #23\n" \
\
/* skip all if cache level value is zero */ \
"beq 5f\n" \
"mov r9, #0\n" \
\
/* begin loop over cache numbers */ \
"1:\n" \
\
/* work out 3 x cache level */ \
"add r2, r9, r9, lsr #1\n" \
\
/* get the cache type of current cache number (Clidr::CtypeX) */ \
"mov r1, r0, lsr r2\n" \
"and r1, r1, #7\n" \
"cmp r1, #2\n" \
\
/* skip cache number if there's no data cache at this level */ \
"blt 4f\n" \
\
/* select the appropriate CCSIDR according to cache level and type */ \
WRITE_CSSELR(r9) \
"isb\n" \
\
/* get the line length of current cache (Ccsidr::LineSize) */ \
READ_CCSIDR(r1) \
"and r2, r1, #0x7\n" \
\
/* add 4 for the line-length offset (log2 of 16 bytes) */ \
"add r2, r2, #4\n" \
\
/* get the associativity or max way size (Ccsidr::Associativity) */ \
"ldr r4, =0x3ff\n" \
"ands r4, r4, r1, lsr #3\n" \
\
/* get the bit position of the way-size increment */ \
"clz r5, r4\n" \
\
/* get a working copy of the max way size */ \
"mov r8, r4\n" \
\
/* begin loop over way numbers */ \
"2:\n" \
\
/* get the number of sets or the max index size (Ccsidr::NumSets) */ \
"ldr r7, =0x00007fff\n" \
"ands r7, r7, r1, lsr #13\n" \
\
/* begin loop over indices */ \
"3:\n" \
\
/* factor in the way number and cache number into write value */ \
"orr r6, r9, r8, lsl r5\n" \
\
/* factor in the index number into write value */ \
"orr r6, r6, r7, lsl r2\n"
/**
* Second macro to do a set/way operation on all entries of all data caches
*
* Must be inserted directly after the targeted operation.
*/
#define FOR_ALL_SET_WAY_OF_ALL_DATA_CACHES_1 \
\
/* decrement the index */ \
"subs r7, r7, #1\n" \
\
/* end loop over indices */ \
"bge 3b\n" \
\
/* decrement the way number */ \
"subs r8, r8, #1\n" \
\
/* end loop over way numbers */ \
"bge 2b\n" \
\
/* label to skip a cache number */ \
"4:\n" \
\
/* increment the cache number */ \
"add r9, r9, #2\n" \
"cmp r3, r9\n" \
\
/* end loop over cache numbers */ \
"bgt 1b\n" \
\
/* synchronize data */ \
"dsb\n" \
\
/* label to skip all */ \
"5:\n" \
::: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9"
void Genode::Arm::flush_data_caches()
{
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();
}
void Genode::Arm::invalidate_data_caches()
{
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();
}
Genode::Arm::Psr::access_t Genode::Arm::Psr::init_user_with_trustzone()
{
access_t v = 0;
M::set(v, M::USR);
I::set(v, 1);
A::set(v, 1);
return v;
}

View File

@ -23,11 +23,10 @@
using namespace Genode;
extern Genode::Native_utcb * _main_thread_utcb;
Native_utcb * main_thread_utcb() {
return _main_thread_utcb; }
namespace Genode { Rm_session * env_context_area_rm_session(); }
extern Ram_dataspace_capability _main_thread_utcb_ds;
extern Native_thread_id _main_thread_id;
void Thread_base::start()
{
@ -52,11 +51,23 @@ void Thread_base::_deinit_platform_thread()
void Thread_base::_init_platform_thread(size_t, Type type)
{
/* create platform thread */
_tid.platform_thread = new (platform()->core_mem_alloc())
Platform_thread(_context->name, &_context->utcb);
if (type == NORMAL) {
_tid.platform_thread = new (platform()->core_mem_alloc())
Platform_thread(_context->name, &_context->utcb);
return;
}
if (type == NORMAL) { return; }
size_t const utcb_size = sizeof(Native_utcb);
addr_t const context_area = Native_config::context_area_virtual_base();
addr_t const utcb_new = (addr_t)&_context->utcb - context_area;
Rm_session * const rm = env_context_area_rm_session();
PWRN("not implemented!");
/* remap initial main-thread UTCB according to context-area spec */
try { rm->attach_at(_main_thread_utcb_ds, utcb_new, utcb_size); }
catch(...) {
PERR("failed to re-map UTCB");
while (1) ;
}
/* adjust initial object state in case of a main thread */
tid().thread_id = _main_thread_id;
}

View File

@ -32,8 +32,6 @@ using namespace Genode;
extern int main(int argc, char **argv, char **envp);
namespace Genode { Rm_session *env_context_area_rm_session(); }
enum { ATEXIT_SIZE = 256 };