mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
Merge branch 'master' of github.com:mmueller41/genode
This commit is contained in:
@@ -21,6 +21,5 @@ content:
|
||||
for spec in x86_32; do \
|
||||
mv lib/mk/spec/$$spec/ld-fiasco.mk lib/mk/spec/$$spec/ld.mk; \
|
||||
done;
|
||||
sed -i "s/ld-fiasco/ld/" src/lib/ld/fiasco/target.mk
|
||||
sed -i "s/fiasco_timer_drv/timer/" src/timer/fiasco/target.mk
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 1790ce242c001ed77aab9695f69923a44d1dc1d1
|
||||
2022-10-11 1f0607de6493bad0e47b24e66d84474652e8b6be
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
TARGET = ld-fiasco
|
||||
LIBS = ld-fiasco
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 f7900083623a2009d35234c47d2475dea8f6cf53
|
||||
2022-10-11 d258920f8664460c78eeea25fafb89eaa5e7adf5
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 f7d228f6419c2fc9b1b0faf4ba8d88862ba61e81
|
||||
2022-10-11 1c94d29566bccccced246eeaf90702348e2b1a7f
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 391b798b7c1d1b44ff65d855980eb41a8f4a87c1
|
||||
2022-10-11 2668fd23d5cbd45b8f632073fc7c155f96ecb848
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 79eab679e71dd70803b0e1647a23e2ba86c76f50
|
||||
2022-10-11 8da054ff9e4c37895816fd30857b3c42d9e75eb0
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 7a16aeb081d1392c36d83f526936f17cc9560442
|
||||
2022-10-11 f41df6b57d2c4b090a84427e02950df84fb385ad
|
||||
|
||||
@@ -39,5 +39,4 @@ content:
|
||||
for spec in x86_32 x86_64 arm arm_64; do \
|
||||
mv lib/mk/spec/$$spec/ld-foc.mk lib/mk/spec/$$spec/ld.mk; \
|
||||
done;
|
||||
sed -i "s/ld-foc/ld/" src/lib/ld/foc/target.mk
|
||||
sed -i "s/foc_timer_drv/timer/" src/timer/foc/target.mk
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
TARGET = ld-foc
|
||||
LIBS = ld-foc
|
||||
@@ -1,2 +1 @@
|
||||
arm_v7a
|
||||
arm_v8a
|
||||
1
repos/base-hw/board/virt_qemu_arm_v8a/arch
Normal file
1
repos/base-hw/board/virt_qemu_arm_v8a/arch
Normal file
@@ -0,0 +1 @@
|
||||
arm_v8a
|
||||
1
repos/base-hw/board/virt_qemu_arm_v8a/image_link_address
Normal file
1
repos/base-hw/board/virt_qemu_arm_v8a/image_link_address
Normal file
@@ -0,0 +1 @@
|
||||
0x40000000
|
||||
@@ -1,6 +1,6 @@
|
||||
REP_INC_DIR += src/bootstrap/board/virt_qemu
|
||||
REP_INC_DIR += src/bootstrap/board/virt_qemu_arm_v7a
|
||||
|
||||
SRC_CC += bootstrap/board/virt_qemu/platform.cc
|
||||
SRC_CC += bootstrap/board/virt_qemu_arm_v7a/platform.cc
|
||||
SRC_CC += bootstrap/spec/arm/arm_v7_cpu.cc
|
||||
SRC_CC += bootstrap/spec/arm/cortex_a15_cpu.cc
|
||||
SRC_CC += bootstrap/spec/arm/gicv2.cc
|
||||
@@ -1,4 +1,4 @@
|
||||
REP_INC_DIR += src/core/board/virt_qemu
|
||||
REP_INC_DIR += src/core/board/virt_qemu_arm_v7a
|
||||
REP_INC_DIR += src/core/spec/arm/virtualization
|
||||
|
||||
# add C++ sources
|
||||
@@ -1,8 +1,8 @@
|
||||
REP_INC_DIR += src/bootstrap/board/virt_qemu_64
|
||||
REP_INC_DIR += src/bootstrap/board/virt_qemu_arm_v8a
|
||||
|
||||
SRC_CC += bootstrap/spec/arm/gicv3.cc
|
||||
SRC_CC += bootstrap/spec/arm_64/cortex_a53_mmu.cc
|
||||
SRC_CC += bootstrap/board/virt_qemu_64/platform.cc
|
||||
SRC_CC += bootstrap/board/virt_qemu_arm_v8a/platform.cc
|
||||
SRC_CC += lib/base/arm_64/kernel/interface.cc
|
||||
SRC_CC += spec/64bit/memory_map.cc
|
||||
SRC_S += bootstrap/spec/arm_64/crt0.s
|
||||
@@ -1,4 +1,4 @@
|
||||
REP_INC_DIR += src/core/board/virt_qemu_64
|
||||
REP_INC_DIR += src/core/board/virt_qemu_arm_v8a
|
||||
REP_INC_DIR += src/core/spec/arm/virtualization
|
||||
|
||||
# add C++ sources
|
||||
@@ -4,6 +4,6 @@ SRC_CC += timer_connection_time.cc
|
||||
SRC_CC += hw/timer_connection_timestamp.cc
|
||||
SRC_CC += duration.cc
|
||||
|
||||
INC_DIR += $(BASE_DIR)/src/include
|
||||
REP_INC_DIR += src/include
|
||||
|
||||
vpath % $(BASE_DIR)/src/lib/timeout
|
||||
vpath % $(call select_from_repositories,src/lib/timeout)
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 ab1cb582165e76bda4abf27870f44ad7d1ae5b6d
|
||||
2022-10-11 50db06fe21eca6c46c9b4bf7fcbc81538ac74f32
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
CONTENT += src/core/board/imx53_qsb \
|
||||
src/bootstrap/board/imx53_qsb
|
||||
src/bootstrap/board/imx53_qsb \
|
||||
lib/mk/spec/arm_v7/core-hw-imx53_qsb.inc \
|
||||
lib/mk/spec/arm_v7/bootstrap-hw-imx53_qsb.inc
|
||||
|
||||
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 0fff6ce83b962b3fd54cf6eda0a157cb0cb0c9d5
|
||||
2022-10-11 1377d3a2b7afaa265cc5ae6bbd515679be527c40
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 8c17512664a648eaed876c815ea678770eda3280
|
||||
2022-10-11 c32cf899ce00bd69aff5bbd4f7b6b611d2bfa47d
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 edc396d9bc9a2ebf73590e70c1363020226909be
|
||||
2022-10-11 39ff297bc573b8e8bf4f2e6e233bf0b1b21f13af
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 da90478c4c0b8993041bc59488eedb124e680e78
|
||||
2022-10-11 f5456c3ed55b53ccaefee603fdb8d9b1e3ca84ab
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 1b34e317209c48bfc88af6118db32be261ce3e0c
|
||||
2022-10-11 de2f50d9164952dbbf6ce76d29abad5d96da8512
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 46e9f88209bbc95228d3882cc0831770315402e4
|
||||
2022-10-11 5d72eb4e34f582c06c086345b225cee91ce539cc
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
CONTENT += src/core/board/virt_qemu_64 \
|
||||
src/bootstrap/board/virt_qemu_64
|
||||
|
||||
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
||||
@@ -1 +0,0 @@
|
||||
2022-05-24 bb6c39c093a24d2ec4ff1d00e397529c51e95fa7
|
||||
@@ -0,0 +1,4 @@
|
||||
CONTENT += src/core/board/virt_qemu_arm_v7a \
|
||||
src/bootstrap/board/virt_qemu_arm_v7a
|
||||
|
||||
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
||||
1
repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash
Normal file
1
repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash
Normal file
@@ -0,0 +1 @@
|
||||
2022-10-11 70e53c98ef4b3215440efb2ea09e07ff7cd97c4f
|
||||
@@ -0,0 +1,4 @@
|
||||
CONTENT += src/core/board/virt_qemu_arm_v8a \
|
||||
src/bootstrap/board/virt_qemu_arm_v8a
|
||||
|
||||
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
||||
1
repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash
Normal file
1
repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash
Normal file
@@ -0,0 +1 @@
|
||||
2022-10-11 c146d70c9bde3f928110c868a54b8c800beffd79
|
||||
@@ -0,0 +1,2 @@
|
||||
base-hw
|
||||
base
|
||||
@@ -115,6 +115,12 @@ SRC_LIB_BASE += $(notdir $(wildcard $(BASE_HW_DIR)/src/lib/base/*.cc)) \
|
||||
$(notdir $(wildcard $(BASE_DIR)/src/lib/base/*.cc)) \
|
||||
${call selected_content,SRC_LIB_BASE_SPECS}
|
||||
|
||||
SRC_LIB_TIMEOUT += duration.cc \
|
||||
hw/timer_connection_timestamp.cc \
|
||||
timeout.cc \
|
||||
timer_connection.cc \
|
||||
timer_connection_time.cc
|
||||
|
||||
SRC_LIB_STARTUP += init_main_thread.cc _main.cc \
|
||||
$(addprefix spec/,${call selected_content,SRC_LIB_STARTUP_SPECS})
|
||||
|
||||
@@ -125,15 +131,24 @@ SRC_CORE += $(notdir $(wildcard $(BASE_HW_DIR)/src/core/*.cc)) \
|
||||
$(addprefix board/,$(BOARD)) \
|
||||
version.inc target.inc include hw kernel
|
||||
|
||||
LIB_MK := base-hw-common.mk base-hw.mk bootstrap-hw.inc core-hw.inc \
|
||||
timeout-hw.mk cxx.mk base.inc base-common.inc startup.inc \
|
||||
$(addprefix spec/,${call selected_content,LIB_MK_SPECS})
|
||||
# names of the lib/mk/ files to consider for inclusion in the src archive
|
||||
LIB_MK_FILES := base-common.inc base-hw-common.mk \
|
||||
base.inc base-hw.mk \
|
||||
bootstrap-hw.inc bootstrap-hw-$(BOARD).inc bootstrap-hw-$(BOARD).mk \
|
||||
core-hw.inc core-hw-$(BOARD).inc core-hw-$(BOARD).mk \
|
||||
startup.inc startup-hw.mk \
|
||||
timeout-hw.mk cxx.mk ld-hw.mk syscall-hw.mk
|
||||
|
||||
LIB_MK_DIRS := lib/mk $(addprefix lib/mk/spec/,${call selected_content,LIB_MK_SPECS})
|
||||
|
||||
CONTENT += $(foreach D,$(LIB_MK_DIRS),$(addprefix $D/,$(LIB_MK_FILES)))
|
||||
|
||||
CONTENT += $(addprefix src/timer/,$(SRC_TIMER)) \
|
||||
$(addprefix src/include/hw/,$(SRC_INCLUDE_HW)) \
|
||||
$(addprefix src/bootstrap/,$(SRC_BOOTSTRAP)) \
|
||||
$(addprefix lib/mk/,$(LIB_MK)) \
|
||||
$(addprefix src/lib/base/,$(SRC_LIB_BASE)) \
|
||||
$(addprefix src/lib/timeout/,$(SRC_LIB_TIMEOUT)) \
|
||||
$(addprefix src/lib/startup/,$(SRC_LIB_STARTUP)) \
|
||||
$(addprefix src/core/,$(SRC_CORE)) \
|
||||
src/lib/hw src/lib/ld src/lib/cxx \
|
||||
@@ -180,7 +195,6 @@ generalize_target_names: $(CONTENT)
|
||||
# apply kernel-agnostic convention of naming the timer and ld.lib.so
|
||||
for subdir in ${call selected_content,LD_MK_DIRS}; do \
|
||||
mv $$subdir/ld-hw.mk $$subdir/ld.mk; done
|
||||
sed -i "s/ld-hw/ld/" src/lib/ld/hw/target.mk
|
||||
sed -i "s/hw_timer_drv/timer/" src/timer/hw/target.mk
|
||||
# supplement BOARD definition that normally comes form the build dir
|
||||
sed -i "s/\?= unknown/:= $(BOARD)/" src/core/hw/target.mk
|
||||
@@ -189,5 +203,4 @@ generalize_target_names: $(CONTENT)
|
||||
sed -i "1aREQUIRES := $(ARCH)" src/core/hw/target.mk
|
||||
sed -i "1aREQUIRES := $(ARCH)" src/bootstrap/hw/target.mk
|
||||
sed -i "/REQUIRES/s/hw/hw $(ARCH)/" src/timer/hw/target.mk
|
||||
sed -i "1aREQUIRES := $(ARCH)" src/lib/ld/hw/target.mk
|
||||
|
||||
|
||||
@@ -109,7 +109,8 @@ Cpu::Idle_thread::Idle_thread(Board::Address_space_id_allocator &addr_space_id_a
|
||||
Cpu &cpu,
|
||||
Pd &core_pd)
|
||||
:
|
||||
Thread { addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd, "idle" }
|
||||
Thread { addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd,
|
||||
Cpu_priority::min(), 0, "idle", Thread::IDLE }
|
||||
{
|
||||
regs->ip = (addr_t)&idle_thread_main;
|
||||
|
||||
@@ -120,14 +121,9 @@ Cpu::Idle_thread::Idle_thread(Board::Address_space_id_allocator &addr_space_id_a
|
||||
|
||||
void Cpu::schedule(Job * const job)
|
||||
{
|
||||
if (_id == executing_id())
|
||||
_scheduler.ready(job->share());
|
||||
else {
|
||||
_scheduler.ready_check(job->share());
|
||||
|
||||
if (_scheduler.need_to_schedule())
|
||||
trigger_ip_interrupt();
|
||||
}
|
||||
_scheduler.ready(job->share());
|
||||
if (_id != executing_id() && _scheduler.need_to_schedule())
|
||||
trigger_ip_interrupt();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -191,45 +191,17 @@ void Cpu_scheduler::update(time_t time)
|
||||
}
|
||||
|
||||
|
||||
void Cpu_scheduler::ready_check(Share &s1)
|
||||
{
|
||||
assert(_head);
|
||||
|
||||
ready(s1);
|
||||
|
||||
if (_need_to_schedule)
|
||||
return;
|
||||
|
||||
Share * s2 = _head;
|
||||
if (!s1._claim) {
|
||||
_need_to_schedule = s2 == &_idle;
|
||||
} else if (!_head_claims) {
|
||||
_need_to_schedule = true;
|
||||
} else if (s1._prio != s2->_prio) {
|
||||
_need_to_schedule = s1._prio > s2->_prio;
|
||||
} else {
|
||||
for (
|
||||
; s2 && s2 != &s1;
|
||||
s2 =
|
||||
Double_list<Cpu_share>::next(&s2->_claim_item) != nullptr ?
|
||||
&Double_list<Cpu_share>::next(&s2->_claim_item)->payload() :
|
||||
nullptr) ;
|
||||
|
||||
_need_to_schedule = !s2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Cpu_scheduler::ready(Share &s)
|
||||
{
|
||||
assert(!s._ready && &s != &_idle);
|
||||
|
||||
_need_to_schedule = true;
|
||||
|
||||
s._ready = 1;
|
||||
s._fill = _fill;
|
||||
_fills.insert_tail(&s._fill_item);
|
||||
|
||||
if (_head == &_idle)
|
||||
_need_to_schedule = true;
|
||||
|
||||
if (!s._quota)
|
||||
return;
|
||||
|
||||
@@ -239,6 +211,28 @@ void Cpu_scheduler::ready(Share &s)
|
||||
_rcl[s._prio].insert_head(&s._claim_item);
|
||||
else
|
||||
_rcl[s._prio].insert_tail(&s._claim_item);
|
||||
|
||||
/*
|
||||
* Check whether we need to re-schedule
|
||||
*/
|
||||
if (_need_to_schedule)
|
||||
return;
|
||||
|
||||
/* current head has no quota left */
|
||||
if (!_head_claims) {
|
||||
_need_to_schedule = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if current head has different priority */
|
||||
if (s._prio != _head->_prio) {
|
||||
_need_to_schedule = s._prio > _head->_prio;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if current head has same priority, the ready share gets active */
|
||||
if (s._claim)
|
||||
_need_to_schedule = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -246,7 +240,8 @@ void Cpu_scheduler::unready(Share &s)
|
||||
{
|
||||
assert(s._ready && &s != &_idle);
|
||||
|
||||
_need_to_schedule = true;
|
||||
if (&s == _head)
|
||||
_need_to_schedule = true;
|
||||
|
||||
s._ready = 0;
|
||||
_fills.remove(&s._fill_item);
|
||||
@@ -270,21 +265,15 @@ void Cpu_scheduler::remove(Share &s)
|
||||
{
|
||||
assert(&s != &_idle);
|
||||
|
||||
_need_to_schedule = true;
|
||||
if (s._ready) unready(s);
|
||||
|
||||
if (&s == _head)
|
||||
_head = nullptr;
|
||||
|
||||
if (s._ready)
|
||||
_fills.remove(&s._fill_item);
|
||||
|
||||
if (!s._quota)
|
||||
return;
|
||||
|
||||
if (s._ready)
|
||||
_rcl[s._prio].remove(&s._claim_item);
|
||||
else
|
||||
_ucl[s._prio].remove(&s._claim_item);
|
||||
_ucl[s._prio].remove(&s._claim_item);
|
||||
}
|
||||
|
||||
|
||||
@@ -292,8 +281,6 @@ void Cpu_scheduler::insert(Share &s)
|
||||
{
|
||||
assert(!s._ready);
|
||||
|
||||
_need_to_schedule = true;
|
||||
|
||||
if (!s._quota)
|
||||
return;
|
||||
|
||||
|
||||
@@ -180,15 +180,10 @@ class Kernel::Cpu_scheduler
|
||||
void timeout() { _need_to_schedule = true; }
|
||||
|
||||
/**
|
||||
* Update head according to the consumed time
|
||||
* Update head according to the current (absolute) time
|
||||
*/
|
||||
void update(time_t time);
|
||||
|
||||
/**
|
||||
* Set 's1' ready and return wether this outdates current head
|
||||
*/
|
||||
void ready_check(Share &s1);
|
||||
|
||||
/**
|
||||
* Set share 's' ready
|
||||
*/
|
||||
|
||||
@@ -329,6 +329,23 @@ void Thread::_call_start_thread()
|
||||
/* join protection domain */
|
||||
thread._pd = (Pd *) user_arg_3();
|
||||
thread._ipc_init(*(Native_utcb *)user_arg_4(), *this);
|
||||
|
||||
/*
|
||||
* Sanity check core threads!
|
||||
*
|
||||
* Currently, the model assumes that there is only one core
|
||||
* entrypoint, which serves requests, and which can destroy
|
||||
* threads and pds. If this changes, we have to inform all
|
||||
* cpus about pd destructions to remove their page-tables
|
||||
* from the hardware in case that a core-thread running with
|
||||
* that same pd is currently active. Therefore, warn if the
|
||||
* semantic changes, and additional core threads are started
|
||||
* across cpu cores.
|
||||
*/
|
||||
if (thread._pd == &_core_pd && cpu.id() != _cpu_pool.primary_cpu().id())
|
||||
Genode::raw("Error: do not start core threads"
|
||||
" on CPU cores different than boot cpu");
|
||||
|
||||
thread._become_active();
|
||||
}
|
||||
|
||||
@@ -369,7 +386,7 @@ void Thread::_call_restart_thread()
|
||||
|
||||
Thread &thread = *thread_ptr;
|
||||
|
||||
if (!_core && (&pd() != &thread.pd())) {
|
||||
if (_type == USER && (&pd() != &thread.pd())) {
|
||||
raw(*this, ": failed to lookup thread ", (unsigned)user_arg_1(),
|
||||
" to restart it");
|
||||
_die();
|
||||
@@ -447,6 +464,18 @@ void Thread::_call_delete_thread()
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_delete_pd()
|
||||
{
|
||||
Genode::Kernel_object<Pd> & pd =
|
||||
*(Genode::Kernel_object<Pd>*)user_arg_1();
|
||||
|
||||
if (_cpu->active(pd->mmu_regs))
|
||||
_cpu->switch_to(_core_pd.mmu_regs);
|
||||
|
||||
_call_delete<Pd>();
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_await_request_msg()
|
||||
{
|
||||
if (_ipc_node.can_await_request()) {
|
||||
@@ -793,7 +822,7 @@ void Thread::_call()
|
||||
case call_id_pause_vm(): _call_pause_vm(); return;
|
||||
default:
|
||||
/* check wether this is a core thread */
|
||||
if (!_core) {
|
||||
if (_type != CORE) {
|
||||
Genode::raw(*this, ": not entitled to do kernel call");
|
||||
_die();
|
||||
return;
|
||||
@@ -805,7 +834,7 @@ void Thread::_call()
|
||||
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
||||
_core_pd, (unsigned) user_arg_2(),
|
||||
(unsigned) _core_to_kernel_quota(user_arg_3()),
|
||||
(char const *) user_arg_4());
|
||||
(char const *) user_arg_4(), USER);
|
||||
return;
|
||||
case call_id_new_core_thread():
|
||||
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
||||
@@ -822,7 +851,7 @@ void Thread::_call()
|
||||
*(Genode::Platform_pd *) user_arg_3(),
|
||||
_addr_space_id_alloc);
|
||||
return;
|
||||
case call_id_delete_pd(): _call_delete<Pd>(); return;
|
||||
case call_id_delete_pd(): _call_delete_pd(); return;
|
||||
case call_id_new_signal_receiver(): _call_new<Signal_receiver>(); return;
|
||||
case call_id_new_signal_context():
|
||||
_call_new<Signal_context>(*(Signal_receiver*) user_arg_2(), user_arg_3());
|
||||
@@ -857,7 +886,7 @@ void Thread::_mmu_exception()
|
||||
return;
|
||||
}
|
||||
|
||||
if (_core)
|
||||
if (_type != USER)
|
||||
Genode::raw(*this, " raised a fault, which should never happen ",
|
||||
_fault);
|
||||
|
||||
@@ -874,7 +903,7 @@ Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
||||
unsigned const priority,
|
||||
unsigned const quota,
|
||||
char const *const label,
|
||||
bool core)
|
||||
Type type)
|
||||
:
|
||||
Kernel::Object { *this },
|
||||
Cpu_job { priority, quota },
|
||||
@@ -885,8 +914,8 @@ Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
||||
_ipc_node { *this },
|
||||
_state { AWAITS_START },
|
||||
_label { label },
|
||||
_core { core },
|
||||
regs { core }
|
||||
_type { type },
|
||||
regs { type != USER }
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
@@ -57,6 +57,10 @@ struct Kernel::Thread_fault
|
||||
*/
|
||||
class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
{
|
||||
public:
|
||||
|
||||
enum Type { USER, CORE, IDLE };
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
@@ -149,7 +153,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
capid_t _timeout_sigid { 0 };
|
||||
bool _paused { false };
|
||||
bool _cancel_next_await_signal { false };
|
||||
bool const _core { false };
|
||||
Type const _type;
|
||||
|
||||
Genode::Constructible<Tlb_invalidation> _tlb_invalidation {};
|
||||
Genode::Constructible<Destroy> _destroy {};
|
||||
@@ -230,6 +234,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
void _call_restart_thread();
|
||||
void _call_yield_thread();
|
||||
void _call_delete_thread();
|
||||
void _call_delete_pd();
|
||||
void _call_await_request_msg();
|
||||
void _call_send_request_msg();
|
||||
void _call_send_reply_msg();
|
||||
@@ -301,7 +306,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
unsigned const priority,
|
||||
unsigned const quota,
|
||||
char const *const label,
|
||||
bool core = false);
|
||||
Type const type);
|
||||
|
||||
/**
|
||||
* Constructor for core/kernel thread
|
||||
@@ -315,7 +320,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
char const *const label)
|
||||
:
|
||||
Thread(addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd,
|
||||
Cpu_priority::min(), 0, label, true)
|
||||
Cpu_priority::min(), 0, label, CORE)
|
||||
{ }
|
||||
|
||||
~Thread();
|
||||
@@ -432,6 +437,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
char const * label() const { return _label; }
|
||||
Thread_fault fault() const { return _fault; }
|
||||
Genode::Native_utcb *utcb() { return _utcb; }
|
||||
Type type() const { return _type; }
|
||||
|
||||
Pd &pd() const
|
||||
{
|
||||
|
||||
@@ -77,6 +77,8 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
||||
Kernel::Signal_context & context,
|
||||
Identity & id);
|
||||
|
||||
~Vm();
|
||||
|
||||
/**
|
||||
* Inject an interrupt to this VM
|
||||
*
|
||||
|
||||
@@ -22,13 +22,17 @@
|
||||
|
||||
using namespace Genode;
|
||||
using namespace Kernel;
|
||||
using Device = Board::Timer;
|
||||
|
||||
using Device = Board::Timer;
|
||||
using counter_t = Board::Timer::Counter::access_t;
|
||||
|
||||
|
||||
enum {
|
||||
TICS_PER_MS =
|
||||
Board::CORTEX_A9_PRIVATE_TIMER_CLK /
|
||||
Board::CORTEX_A9_PRIVATE_TIMER_DIV / 1000
|
||||
Board::CORTEX_A9_PRIVATE_TIMER_DIV / 1000,
|
||||
|
||||
MAX_COUNTER_VAL = ~(counter_t)0
|
||||
};
|
||||
|
||||
|
||||
@@ -79,12 +83,33 @@ time_t Timer::us_to_ticks(time_t const us) const {
|
||||
|
||||
time_t Timer::_duration() const
|
||||
{
|
||||
Device::Counter::access_t last = _last_timeout_duration;
|
||||
Device::Counter::access_t cnt = _device.read<Device::Counter>();
|
||||
Device::Counter::access_t ret = (_device.read<Device::Interrupt_status::Event>())
|
||||
? _max_value() - cnt + last : last - cnt;
|
||||
return ret;
|
||||
counter_t const start_counter_val { (counter_t)_last_timeout_duration };
|
||||
counter_t const curr_counter_val { _device.read<Device::Counter>() };
|
||||
|
||||
/*
|
||||
* Calculate result depending on whether the counter already wrapped or
|
||||
* not. See the comment in the implementation of '_max_value' for an
|
||||
* explanation why this comparison is done instead of checking the IRQ
|
||||
* status and why it is sufficient.
|
||||
*/
|
||||
if (curr_counter_val > start_counter_val)
|
||||
return start_counter_val + (MAX_COUNTER_VAL - curr_counter_val);
|
||||
|
||||
return start_counter_val - curr_counter_val;
|
||||
}
|
||||
|
||||
|
||||
time_t Timer::_max_value() const { return 0xfffffffe; }
|
||||
time_t Timer::_max_value() const
|
||||
{
|
||||
/*
|
||||
* We propagate a max timeout value far lower than the one required
|
||||
* by the hardware. This is because on some platforms (Qemu 4.2.1 PBXA9),
|
||||
* the IRQ status register is not reliable. Sometimes, it indicates an IRQ
|
||||
* too early, i.e., shortly before the counter wraps. Therefore we have to
|
||||
* accomplish wrap detection via counter comparison only. Therefore, we
|
||||
* have to make sure that we always read out the counter before it hits
|
||||
* the max timout value again. And, therefore, the max timeout value has
|
||||
* to be far away from the first value the counter has after wrapping.
|
||||
*/
|
||||
return MAX_COUNTER_VAL >> 1;
|
||||
}
|
||||
|
||||
@@ -87,24 +87,25 @@ void Arm_cpu::mmu_fault_status(Fsr::access_t fsr, Thread_fault & fault)
|
||||
}
|
||||
|
||||
|
||||
void Arm_cpu::switch_to(Arm_cpu::Context&, Arm_cpu::Mmu_context & o)
|
||||
bool Arm_cpu::active(Arm_cpu::Mmu_context & ctx)
|
||||
{
|
||||
if (o.cidr == 0) return;
|
||||
return (Cidr::read() == ctx.cidr);
|
||||
}
|
||||
|
||||
Cidr::access_t cidr = Cidr::read();
|
||||
if (cidr != o.cidr) {
|
||||
/**
|
||||
* First switch to global mappings only to prevent
|
||||
* that wrong branch predicts result due to ASID
|
||||
* and Page-Table not being in sync (see ARM RM B 3.10.4)
|
||||
*/
|
||||
Cidr::write(0);
|
||||
Cpu::synchronization_barrier();
|
||||
Ttbr0::write(o.ttbr0);
|
||||
Cpu::synchronization_barrier();
|
||||
Cidr::write(o.cidr);
|
||||
Cpu::synchronization_barrier();
|
||||
}
|
||||
|
||||
void Arm_cpu::switch_to(Arm_cpu::Mmu_context & ctx)
|
||||
{
|
||||
/**
|
||||
* First switch to global mappings only to prevent
|
||||
* that wrong branch predicts result due to ASID
|
||||
* and Page-Table not being in sync (see ARM RM B 3.10.4)
|
||||
*/
|
||||
Cidr::write(0);
|
||||
Cpu::synchronization_barrier();
|
||||
Ttbr0::write(ctx.ttbr0);
|
||||
Cpu::synchronization_barrier();
|
||||
Cidr::write(ctx.cidr);
|
||||
Cpu::synchronization_barrier();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -104,7 +104,8 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu
|
||||
else Tlbiall::write(0);
|
||||
}
|
||||
|
||||
void switch_to(Context&, Mmu_context & o);
|
||||
bool active(Mmu_context &);
|
||||
void switch_to(Mmu_context &);
|
||||
|
||||
static void mmu_fault(Context & c, Kernel::Thread_fault & fault);
|
||||
static void mmu_fault_status(Fsr::access_t fsr,
|
||||
|
||||
@@ -67,7 +67,8 @@ void Kernel::Thread::Tlb_invalidation::execute() { };
|
||||
|
||||
void Thread::proceed(Cpu & cpu)
|
||||
{
|
||||
cpu.switch_to(*regs, pd().mmu_regs);
|
||||
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
||||
cpu.switch_to(pd().mmu_regs);
|
||||
|
||||
regs->cpu_exception = cpu.stack_start();
|
||||
kernel_to_user_context_switch((static_cast<Cpu::Context*>(&*regs)),
|
||||
|
||||
@@ -38,6 +38,9 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
||||
}
|
||||
|
||||
|
||||
Vm::~Vm() {}
|
||||
|
||||
|
||||
void Vm::exception(Cpu & cpu)
|
||||
{
|
||||
switch(_state.cpu_exception) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
push { r0 }
|
||||
mrc p15, 4, r0, c1, c1, 0 /* read HCR register */
|
||||
tst r0, #1 /* check VM bit */
|
||||
beq _host_to_vm
|
||||
beq _from_host
|
||||
mov r0, #\exception_type
|
||||
b _vm_to_host
|
||||
.endm /* _vm_exit */
|
||||
@@ -47,10 +47,27 @@ _vt_dab_entry: _vm_exit 5
|
||||
_vt_irq_entry: _vm_exit 6
|
||||
_vt_trp_entry: _vm_exit 8
|
||||
|
||||
_host_to_vm:
|
||||
_from_host:
|
||||
pop { r0 }
|
||||
cmp r0, #0
|
||||
beq _to_vm
|
||||
cmp r0, #1
|
||||
beq _invalidate_tlb
|
||||
eret
|
||||
|
||||
|
||||
_invalidate_tlb:
|
||||
push { r3, r4 }
|
||||
mrrc p15, 6, r3, r4, c2 /* save VTTBR */
|
||||
mcrr p15, 6, r1, r2, c2 /* write VTTBR */
|
||||
mcr p15, 0, r0, c8, c3, 0 /* TLBIALLIS */
|
||||
mcrr p15, 6, r3, r4, c2 /* restore VTTBR */
|
||||
eret
|
||||
|
||||
_to_vm:
|
||||
push { r1 }
|
||||
ldr r0, [sp, #1*4]
|
||||
add r0, r0, #13*4
|
||||
push { r2 }
|
||||
add r0, r1, #13*4
|
||||
ldmia r0!, { r1-r5 }
|
||||
msr sp_usr, r1
|
||||
mov lr, r2
|
||||
@@ -115,6 +132,7 @@ _host_to_vm:
|
||||
ldmia r0, {r0-r12} /* load vm's r0-r12 */
|
||||
eret
|
||||
|
||||
|
||||
_vm_to_host:
|
||||
push { r0 } /* push cpu excep. */
|
||||
ldr r0, [sp, #3*4] /* load vm state ptr */
|
||||
@@ -218,6 +236,7 @@ _vm_to_host:
|
||||
|
||||
|
||||
/* host kernel must jump to this point to switch to a vm */
|
||||
.global hypervisor_enter_vm
|
||||
hypervisor_enter_vm:
|
||||
.global hypervisor_call
|
||||
hypervisor_call:
|
||||
hvc #0
|
||||
bx lr
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* \brief Interface between kernel and hypervisor
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2022-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SPEC__ARM_V7__VIRTUALIZATION_HYPERVISOR_H_
|
||||
#define _SPEC__ARM_V7__VIRTUALIZATION_HYPERVISOR_H_
|
||||
|
||||
#include <base/stdint.h>
|
||||
#include <cpu/vm_state_virtualization.h>
|
||||
|
||||
namespace Hypervisor {
|
||||
|
||||
struct Host_context;
|
||||
|
||||
enum Call_number {
|
||||
WORLD_SWITCH = 0,
|
||||
TLB_INVALIDATE = 1,
|
||||
};
|
||||
|
||||
using Call_arg = Genode::umword_t;
|
||||
using Call_ret = Genode::umword_t;
|
||||
|
||||
extern "C"
|
||||
Call_ret hypervisor_call(Call_arg call_id,
|
||||
Call_arg arg0,
|
||||
Call_arg arg1);
|
||||
|
||||
|
||||
inline void invalidate_tlb(Genode::uint64_t vttbr)
|
||||
{
|
||||
hypervisor_call(TLB_INVALIDATE,
|
||||
(vttbr & 0xffffffff),
|
||||
((vttbr >> 32U) & 0xffffffff));
|
||||
}
|
||||
|
||||
|
||||
inline void switch_world(Genode::Vm_state & vm_state,
|
||||
Host_context & host_state)
|
||||
{
|
||||
hypervisor_call(WORLD_SWITCH,
|
||||
(Call_arg)&vm_state,
|
||||
(Call_arg)&host_state);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _SPEC__ARM_V7__VIRTUALIZATION_HYPERVISOR_H_ */
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/vm.h>
|
||||
#include <kernel/main.h>
|
||||
#include <spec/arm_v7/virtualization/hypervisor.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -41,7 +42,7 @@ namespace Kernel {
|
||||
using namespace Kernel;
|
||||
|
||||
|
||||
struct Host_context
|
||||
struct Hypervisor::Host_context
|
||||
{
|
||||
Cpu::Ttbr_64bit::access_t vttbr;
|
||||
Cpu::Hcr::access_t hcr;
|
||||
@@ -61,15 +62,13 @@ struct Host_context
|
||||
} vt_host_context;
|
||||
|
||||
|
||||
extern "C" void hypervisor_enter_vm(Genode::Vm_state&, Host_context&);
|
||||
|
||||
|
||||
static Host_context & host_context(Cpu & cpu)
|
||||
static Hypervisor::Host_context & host_context(Cpu & cpu)
|
||||
{
|
||||
static Genode::Constructible<Host_context> host_context[NR_OF_CPUS];
|
||||
static Genode::Constructible<Hypervisor::Host_context>
|
||||
host_context[NR_OF_CPUS];
|
||||
if (!host_context[cpu.id()].constructed()) {
|
||||
host_context[cpu.id()].construct();
|
||||
Host_context & c = *host_context[cpu.id()];
|
||||
Hypervisor::Host_context & c = *host_context[cpu.id()];
|
||||
c.sp = cpu.stack_start();
|
||||
c.ttbr0 = Cpu::Ttbr0_64bit::read();
|
||||
c.ttbr1 = Cpu::Ttbr1_64bit::read();
|
||||
@@ -152,6 +151,15 @@ Kernel::Vm::Vm(Irq::Pool & user_irq_pool,
|
||||
}
|
||||
|
||||
|
||||
Kernel::Vm::~Vm()
|
||||
{
|
||||
Cpu::Ttbr_64bit::access_t vttbr =
|
||||
Cpu::Ttbr_64bit::Ba::masked((Cpu::Ttbr_64bit::access_t)_id.table);
|
||||
Cpu::Ttbr_64bit::Asid::set(vttbr, _id.id);
|
||||
Hypervisor::invalidate_tlb(vttbr);
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Vm::exception(Cpu & cpu)
|
||||
{
|
||||
switch(_state.cpu_exception) {
|
||||
@@ -190,7 +198,7 @@ void Kernel::Vm::proceed(Cpu & cpu)
|
||||
_state.esr_el2 = Cpu::Hstr::init();
|
||||
_state.hpfar_el2 = Cpu::Hcr::init();
|
||||
|
||||
hypervisor_enter_vm(_state, host_context(cpu));
|
||||
Hypervisor::switch_world(_state, host_context(cpu));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,12 +26,15 @@ Genode::Cpu::Context::Context(bool privileged)
|
||||
}
|
||||
|
||||
|
||||
void Genode::Cpu::switch_to(Context&, Mmu_context & mmu_context)
|
||||
bool Genode::Cpu::active(Mmu_context & mmu_context)
|
||||
{
|
||||
if (mmu_context.id() == 0) return;
|
||||
return (mmu_context.id() == Ttbr::Asid::get(Ttbr0_el1::read()));
|
||||
}
|
||||
|
||||
if (mmu_context.id() != Ttbr::Asid::get(Ttbr0_el1::read()))
|
||||
Ttbr0_el1::write(mmu_context.ttbr);
|
||||
|
||||
void Genode::Cpu::switch_to(Mmu_context & mmu_context)
|
||||
{
|
||||
Ttbr0_el1::write(mmu_context.ttbr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -99,7 +99,8 @@ struct Genode::Cpu : Hw::Arm_64_cpu
|
||||
return Ttbr::Asid::get(ttbr) & 0xffff; }
|
||||
};
|
||||
|
||||
void switch_to(Context&, Mmu_context &);
|
||||
bool active(Mmu_context &);
|
||||
void switch_to(Mmu_context &);
|
||||
|
||||
static void mmu_fault(Context &, Kernel::Thread_fault &);
|
||||
|
||||
|
||||
@@ -55,6 +55,16 @@ void Thread::exception(Cpu & cpu)
|
||||
" ISS=", Cpu::Esr::Iss::get(esr),
|
||||
" ip=", (void*)regs->ip);
|
||||
};
|
||||
|
||||
/*
|
||||
* If the machine exception is caused by a non-privileged
|
||||
* component, mark it dead, and continue execution.
|
||||
*/
|
||||
if (regs->exception_type == Cpu::SYNC_LEVEL_EL0) {
|
||||
Genode::raw("Will freeze thread ", *this);
|
||||
_become_inactive(DEAD);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -75,10 +85,14 @@ void Thread::exception(Cpu & cpu)
|
||||
void Kernel::Thread::Tlb_invalidation::execute() { };
|
||||
|
||||
|
||||
bool Kernel::Pd::invalidate_tlb(Cpu &, addr_t addr, size_t size)
|
||||
bool Kernel::Pd::invalidate_tlb(Cpu & cpu, addr_t addr, size_t size)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* only apply to the active cpu */
|
||||
if (cpu.id() != Cpu::executing_id())
|
||||
return false;
|
||||
|
||||
/**
|
||||
* The kernel part of the address space is mapped as global
|
||||
* therefore we have to invalidate it differently
|
||||
@@ -108,7 +122,9 @@ bool Kernel::Pd::invalidate_tlb(Cpu &, addr_t addr, size_t size)
|
||||
|
||||
void Thread::proceed(Cpu & cpu)
|
||||
{
|
||||
cpu.switch_to(*regs, pd().mmu_regs);
|
||||
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
||||
cpu.switch_to(pd().mmu_regs);
|
||||
|
||||
kernel_to_user_context_switch((static_cast<Cpu::Context*>(&*regs)),
|
||||
(void*)cpu.stack_start());
|
||||
}
|
||||
|
||||
@@ -22,24 +22,34 @@
|
||||
.global hypervisor_exception_vector
|
||||
hypervisor_exception_vector:
|
||||
.rept 16
|
||||
add sp, sp, #-16 /* push x0, x1 to stack */
|
||||
stp x0, x1, [sp]
|
||||
mrs x1, hcr_el2 /* read HCR register */
|
||||
tst x1, #1 /* check VM bit */
|
||||
beq _host_to_vm /* if VM bit is not set, switch to VM */
|
||||
ldr x0, [sp, #32] /* otherwise, load vm_state pointer */
|
||||
adr x1, . /* hold exception vector offset in x1 */
|
||||
and x1, x1, #0xf80
|
||||
b _vm_to_host
|
||||
add sp, sp, #-16 /* push x29, x30 to stack */
|
||||
stp x29, x30, [sp]
|
||||
mrs x30, hcr_el2 /* read HCR register */
|
||||
tst x30, #1 /* check VM bit */
|
||||
beq _from_host /* if VM bit is not set, its a host call */
|
||||
ldr x29, [sp, #32] /* otherwise, load vm_state pointer */
|
||||
adr x30, . /* hold exception vector offset in x30 */
|
||||
and x30, x30, #0xf80
|
||||
b _from_vm
|
||||
.balign 128
|
||||
.endr
|
||||
|
||||
_host_to_vm:
|
||||
_from_host:
|
||||
ldp x29, x30, [sp], #2*8 /* pop x29, x30 from stack */
|
||||
cmp x0, #0
|
||||
beq _to_vm
|
||||
cmp x0, #1
|
||||
beq _invalidate_tlb
|
||||
eret
|
||||
|
||||
add sp, sp, #-16 /* push arg2 (vm pic state) to stack */
|
||||
str x2, [sp]
|
||||
_to_vm:
|
||||
add sp, sp, #-16 /* push arg1/2 (vm/host state to stack */
|
||||
stp x1, x2, [sp]
|
||||
add sp, sp, #-16 /* push arg3 (vm pic state) to stack */
|
||||
str x3, [sp]
|
||||
|
||||
msr vttbr_el2, x3 /* stage2 table pointer was arg3 */
|
||||
msr vttbr_el2, x4 /* stage2 table pointer was arg4 */
|
||||
mov x0, x1
|
||||
|
||||
add x0, x0, #31*8 /* skip x0...x30, loaded later */
|
||||
|
||||
@@ -179,27 +189,38 @@ _host_to_vm:
|
||||
|
||||
eret
|
||||
|
||||
_vm_to_host:
|
||||
|
||||
_invalidate_tlb:
|
||||
msr vttbr_el2, x1
|
||||
tlbi vmalle1is
|
||||
msr vttbr_el2, xzr
|
||||
eret
|
||||
|
||||
|
||||
_from_vm:
|
||||
|
||||
/*********************
|
||||
** Save vm context **
|
||||
*********************/
|
||||
|
||||
/** general-purpose register **/
|
||||
add x0, x0, #2*8 /* skip x0 and x1 for now */
|
||||
stp x2, x3, [x0], #2*8
|
||||
stp x4, x5, [x0], #2*8
|
||||
stp x6, x7, [x0], #2*8
|
||||
stp x8, x9, [x0], #2*8
|
||||
stp x10, x11, [x0], #2*8
|
||||
stp x12, x13, [x0], #2*8
|
||||
stp x14, x15, [x0], #2*8
|
||||
stp x16, x17, [x0], #2*8
|
||||
stp x18, x19, [x0], #2*8
|
||||
stp x20, x21, [x0], #2*8
|
||||
stp x22, x23, [x0], #2*8
|
||||
stp x24, x25, [x0], #2*8
|
||||
stp x26, x27, [x0], #2*8
|
||||
stp x0, x1, [x29], #2*8
|
||||
stp x2, x3, [x29], #2*8
|
||||
stp x4, x5, [x29], #2*8
|
||||
stp x6, x7, [x29], #2*8
|
||||
stp x8, x9, [x29], #2*8
|
||||
stp x10, x11, [x29], #2*8
|
||||
stp x12, x13, [x29], #2*8
|
||||
stp x14, x15, [x29], #2*8
|
||||
stp x16, x17, [x29], #2*8
|
||||
stp x18, x19, [x29], #2*8
|
||||
stp x20, x21, [x29], #2*8
|
||||
stp x22, x23, [x29], #2*8
|
||||
stp x24, x25, [x29], #2*8
|
||||
stp x26, x27, [x29], #2*8
|
||||
mov x0, x29
|
||||
mov x1, x30
|
||||
ldp x29, x30, [sp], #2*8 /* pop x29, x30 from stack */
|
||||
stp x28, x29, [x0], #2*8
|
||||
str x30, [x0], #1*8
|
||||
|
||||
@@ -284,11 +305,8 @@ _vm_to_host:
|
||||
mov x0, #0b111
|
||||
msr cnthctl_el2, x0
|
||||
|
||||
|
||||
ldp x0, x1, [sp], #2*8 /* pop x0, x1 from stack */
|
||||
ldr x29, [sp], #2*8 /* pop vm pic state from stack */
|
||||
ldp x2, x30, [sp], #2*8 /* pop vm, and host state from stack */
|
||||
stp x0, x1, [x2] /* save x0, x1 to vm state */
|
||||
ldr x29, [sp], #2*8 /* pop vm pic state from stack */
|
||||
ldp x2, x30, [sp], #2*8 /* pop vm, and host state from stack */
|
||||
|
||||
|
||||
/**********************
|
||||
@@ -364,6 +382,7 @@ _vm_to_host:
|
||||
eret
|
||||
|
||||
/* host kernel must jump to this point to switch to a vm */
|
||||
.global hypervisor_enter_vm
|
||||
hypervisor_enter_vm:
|
||||
.global hypervisor_call
|
||||
hypervisor_call:
|
||||
hvc #0
|
||||
ret
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* \brief Interface between kernel and hypervisor
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2022-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SPEC__ARM_V8__VIRTUALIZATION_HYPERVISOR_H_
|
||||
#define _SPEC__ARM_V8__VIRTUALIZATION_HYPERVISOR_H_
|
||||
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Hypervisor {
|
||||
|
||||
enum Call_number {
|
||||
WORLD_SWITCH = 0,
|
||||
TLB_INVALIDATE = 1,
|
||||
};
|
||||
|
||||
using Call_arg = Genode::umword_t;
|
||||
using Call_ret = Genode::umword_t;
|
||||
|
||||
extern "C"
|
||||
Call_ret hypervisor_call(Call_arg call_id,
|
||||
Call_arg arg0,
|
||||
Call_arg arg1,
|
||||
Call_arg arg2,
|
||||
Call_arg arg3);
|
||||
|
||||
|
||||
inline void invalidate_tlb(Call_arg ttbr)
|
||||
{
|
||||
hypervisor_call(TLB_INVALIDATE, ttbr, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
inline void switch_world(Call_arg guest_state,
|
||||
Call_arg host_state,
|
||||
Call_arg pic_state,
|
||||
Call_arg ttbr)
|
||||
{
|
||||
hypervisor_call(WORLD_SWITCH, guest_state, host_state, pic_state, ttbr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _SPEC__ARM_V8__VIRTUALIZATION_HYPERVISOR_H_ */
|
||||
@@ -23,14 +23,12 @@
|
||||
#include <kernel/vm.h>
|
||||
#include <kernel/main.h>
|
||||
|
||||
#include <spec/arm_v8/virtualization/hypervisor.h>
|
||||
|
||||
using Genode::addr_t;
|
||||
using Kernel::Cpu;
|
||||
using Kernel::Vm;
|
||||
|
||||
extern void * kernel_stack;
|
||||
extern "C" void hypervisor_enter_vm(addr_t vm, addr_t host,
|
||||
addr_t pic, addr_t guest_table);
|
||||
|
||||
|
||||
static Genode::Vm_state & host_context(Cpu & cpu)
|
||||
{
|
||||
@@ -154,6 +152,15 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
||||
}
|
||||
|
||||
|
||||
Vm::~Vm()
|
||||
{
|
||||
Cpu::Vttbr_el2::access_t vttbr_el2 =
|
||||
Cpu::Vttbr_el2::Ba::masked((Cpu::Vttbr_el2::access_t)_id.table);
|
||||
Cpu::Vttbr_el2::Asid::set(vttbr_el2, _id.id);
|
||||
Hypervisor::invalidate_tlb(vttbr_el2);
|
||||
}
|
||||
|
||||
|
||||
void Vm::exception(Cpu & cpu)
|
||||
{
|
||||
switch (_state.exception_type) {
|
||||
@@ -197,7 +204,7 @@ void Vm::proceed(Cpu & cpu)
|
||||
addr_t pic = Hw::Mm::el2_addr(&_vcpu_context.pic);
|
||||
addr_t host = Hw::Mm::el2_addr(&host_context(cpu));
|
||||
|
||||
hypervisor_enter_vm(guest, host, pic, vttbr_el2);
|
||||
Hypervisor::switch_world(guest, host, pic, vttbr_el2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -115,11 +115,14 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||
*/
|
||||
static unsigned executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); }
|
||||
|
||||
|
||||
void switch_to(Context &, Mmu_context & mmu_context)
|
||||
bool active(Mmu_context & mmu_context)
|
||||
{
|
||||
if (mmu_context.id() && (Ttbr0_64bit::read() != mmu_context.ttbr0))
|
||||
Ttbr0_64bit::write(mmu_context.ttbr0);
|
||||
return (Ttbr0_64bit::read() == mmu_context.ttbr0);
|
||||
}
|
||||
|
||||
void switch_to(Mmu_context & mmu_context)
|
||||
{
|
||||
Ttbr0_64bit::write(mmu_context.ttbr0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -53,22 +53,16 @@ Mmu_context::~Mmu_context()
|
||||
}
|
||||
|
||||
|
||||
bool Genode::Cpu::active(Mmu_context & context)
|
||||
{
|
||||
return Satp::read() == context.satp;
|
||||
}
|
||||
|
||||
|
||||
void Genode::Cpu::switch_to(Mmu_context & context)
|
||||
{
|
||||
/*
|
||||
* The sstatus register defines to which privilege level
|
||||
* the machin returns when doing an exception return
|
||||
*/
|
||||
bool user = Satp::Asid::get(context.satp);
|
||||
Sstatus::access_t v = Sstatus::read();
|
||||
Sstatus::Spp::set(v, user ? 0 : 1);
|
||||
Sstatus::write(v);
|
||||
|
||||
/* change the translation table when necessary */
|
||||
if (user) {
|
||||
Satp::write(context.satp);
|
||||
sfence();
|
||||
}
|
||||
Satp::write(context.satp);
|
||||
sfence();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ class Genode::Cpu : public Hw::Riscv_cpu
|
||||
|
||||
static void invalidate_tlb_by_pid(unsigned const /* pid */) { sfence(); }
|
||||
|
||||
bool active(Mmu_context & context);
|
||||
void switch_to(Mmu_context & context);
|
||||
static void mmu_fault(Context & c, Kernel::Thread_fault & f);
|
||||
|
||||
|
||||
@@ -100,7 +100,16 @@ void Kernel::Thread::_call_cache_invalidate_data_region() { }
|
||||
|
||||
void Kernel::Thread::proceed(Cpu & cpu)
|
||||
{
|
||||
cpu.switch_to(_pd->mmu_regs);
|
||||
/*
|
||||
* The sstatus register defines to which privilege level
|
||||
* the machine returns when doing an exception return
|
||||
*/
|
||||
Cpu::Sstatus::access_t v = Cpu::Sstatus::read();
|
||||
Cpu::Sstatus::Spp::set(v, (type() == USER) ? 0 : 1);
|
||||
Cpu::Sstatus::write(v);
|
||||
|
||||
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
||||
cpu.switch_to(_pd->mmu_regs);
|
||||
|
||||
asm volatile("csrw sscratch, %1 \n"
|
||||
"mv x31, %0 \n"
|
||||
|
||||
@@ -111,11 +111,20 @@ extern void const * const kernel_stack;
|
||||
extern Genode::size_t const kernel_stack_size;
|
||||
|
||||
|
||||
void Genode::Cpu::switch_to(Context & context, Mmu_context &mmu_context)
|
||||
bool Genode::Cpu::active(Mmu_context &mmu_context)
|
||||
{
|
||||
if ((context.cs != 0x8) && (mmu_context.cr3 != Cr3::read()))
|
||||
Cr3::write(mmu_context.cr3);
|
||||
return (mmu_context.cr3 == Cr3::read());
|
||||
}
|
||||
|
||||
|
||||
void Genode::Cpu::switch_to(Mmu_context &mmu_context)
|
||||
{
|
||||
Cr3::write(mmu_context.cr3);
|
||||
}
|
||||
|
||||
|
||||
void Genode::Cpu::switch_to(Context & context)
|
||||
{
|
||||
tss.ist[0] = (addr_t)&context + sizeof(Genode::Cpu_state);
|
||||
|
||||
addr_t const stack_base = reinterpret_cast<addr_t>(&kernel_stack);
|
||||
|
||||
@@ -126,7 +126,10 @@ class Genode::Cpu : public Hw::X86_64_cpu
|
||||
*
|
||||
* \param context next CPU context
|
||||
*/
|
||||
void switch_to(Context & context, Mmu_context &mmu_context);
|
||||
void switch_to(Context & context);
|
||||
|
||||
bool active(Mmu_context &mmu_context);
|
||||
void switch_to(Mmu_context &mmu_context);
|
||||
|
||||
static void mmu_fault(Context & regs, Kernel::Thread_fault & fault);
|
||||
|
||||
|
||||
@@ -43,7 +43,10 @@ void Kernel::Thread::_call_cache_invalidate_data_region() { }
|
||||
|
||||
void Kernel::Thread::proceed(Cpu & cpu)
|
||||
{
|
||||
cpu.switch_to(*regs, pd().mmu_regs);
|
||||
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
||||
cpu.switch_to(pd().mmu_regs);
|
||||
|
||||
cpu.switch_to(*regs);
|
||||
|
||||
asm volatile("fxrstor (%1) \n"
|
||||
"mov %0, %%rsp \n"
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
TARGET = ld-hw
|
||||
LIBS = ld-hw
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2014-2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@@ -18,125 +18,110 @@
|
||||
/* core includes */
|
||||
#include <kernel/cpu_scheduler.h>
|
||||
|
||||
/*
|
||||
* Utilities
|
||||
*/
|
||||
using namespace Genode;
|
||||
using namespace Kernel;
|
||||
|
||||
using Genode::size_t;
|
||||
using Genode::addr_t;
|
||||
using Genode::construct_at;
|
||||
using Kernel::Cpu_share;
|
||||
using Kernel::Cpu_scheduler;
|
||||
|
||||
|
||||
struct Data
|
||||
struct Main
|
||||
{
|
||||
Cpu_share idle;
|
||||
Cpu_scheduler scheduler;
|
||||
char shares[9][sizeof(Cpu_share)];
|
||||
enum { MAX_SHARES = 10 };
|
||||
|
||||
Data() : idle(0, 0), scheduler(idle, 1000, 100) { }
|
||||
Constructible<Cpu_share> shares[MAX_SHARES] {};
|
||||
Cpu_scheduler scheduler;
|
||||
time_t current_time { 0 };
|
||||
|
||||
Cpu_share & _idle()
|
||||
{
|
||||
if (!shares[0].constructed()) shares[0].construct(0, 0);
|
||||
return *shares[0];
|
||||
}
|
||||
|
||||
Main() : scheduler(_idle(), 1000, 100) { }
|
||||
|
||||
void done()
|
||||
{
|
||||
Genode::log("done");
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
unsigned share_id(Cpu_share & share)
|
||||
{
|
||||
for (unsigned i = 0; i < MAX_SHARES; i++)
|
||||
if (shares[i].constructed() && (&*shares[i] == &share))
|
||||
return i;
|
||||
return ~0U;
|
||||
}
|
||||
|
||||
Cpu_share & share(unsigned const id)
|
||||
{
|
||||
return *shares[id];
|
||||
}
|
||||
|
||||
void create(unsigned const id)
|
||||
{
|
||||
switch (id) {
|
||||
case 1: shares[id].construct(2, 230); break;
|
||||
case 2: shares[id].construct(0, 170); break;
|
||||
case 3: shares[id].construct(3, 110); break;
|
||||
case 4: shares[id].construct(1, 90); break;
|
||||
case 5: shares[id].construct(3, 120); break;
|
||||
case 6: shares[id].construct(3, 0); break;
|
||||
case 7: shares[id].construct(2, 180); break;
|
||||
case 8: shares[id].construct(2, 100); break;
|
||||
case 9: shares[id].construct(2, 0); break;
|
||||
default: return;
|
||||
}
|
||||
scheduler.insert(*shares[id]);
|
||||
}
|
||||
|
||||
void destroy(unsigned const id)
|
||||
{
|
||||
if (!id || id >= MAX_SHARES)
|
||||
return;
|
||||
|
||||
scheduler.remove(share(id));
|
||||
shares[id].destruct();
|
||||
}
|
||||
|
||||
unsigned time()
|
||||
{
|
||||
return scheduler.quota() - scheduler.residual();
|
||||
}
|
||||
|
||||
void update_check(unsigned const l, unsigned const c, unsigned const t,
|
||||
unsigned const s, unsigned const q)
|
||||
{
|
||||
current_time += c;
|
||||
scheduler.update(current_time);
|
||||
unsigned const st = time();
|
||||
if (t != st) {
|
||||
log("wrong time ", st, " in line ", l);
|
||||
done();
|
||||
}
|
||||
Cpu_share & hs = scheduler.head();
|
||||
unsigned const hq = scheduler.head_quota();
|
||||
if (&hs != &share(s)) {
|
||||
log("wrong share ", share_id(hs), " in line ", l);
|
||||
done();
|
||||
}
|
||||
if (hq != q) {
|
||||
log("wrong quota ", hq, " in line ", l);
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
void ready_check(unsigned const l, unsigned const s, bool const x)
|
||||
{
|
||||
scheduler.ready(share(s));
|
||||
if (scheduler.need_to_schedule() != x) {
|
||||
log("wrong check result ", scheduler.need_to_schedule(), " in line ", l);
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
void test();
|
||||
};
|
||||
|
||||
|
||||
Data * data()
|
||||
{
|
||||
static Data d;
|
||||
return &d;
|
||||
}
|
||||
|
||||
|
||||
void done()
|
||||
{
|
||||
Genode::log("done");
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
|
||||
unsigned share_id(void * const pointer)
|
||||
{
|
||||
addr_t const address = (addr_t)pointer;
|
||||
addr_t const base = (addr_t)data()->shares;
|
||||
if (address < base || address >= base + sizeof(data()->shares)) {
|
||||
return 0; }
|
||||
return (unsigned)((address - base) / sizeof(Cpu_share) + 1);
|
||||
}
|
||||
|
||||
|
||||
Cpu_share * share(unsigned const id)
|
||||
{
|
||||
if (!id) { return &data()->idle; }
|
||||
return reinterpret_cast<Cpu_share *>(&data()->shares[id - 1]);
|
||||
}
|
||||
|
||||
|
||||
void create(unsigned const id)
|
||||
{
|
||||
Cpu_share * const s = share(id);
|
||||
void * const p = (void *)s;
|
||||
switch (id) {
|
||||
case 1: construct_at<Cpu_share>(p, 2, 230); break;
|
||||
case 2: construct_at<Cpu_share>(p, 0, 170); break;
|
||||
case 3: construct_at<Cpu_share>(p, 3, 110); break;
|
||||
case 4: construct_at<Cpu_share>(p, 1, 90); break;
|
||||
case 5: construct_at<Cpu_share>(p, 3, 120); break;
|
||||
case 6: construct_at<Cpu_share>(p, 3, 0); break;
|
||||
case 7: construct_at<Cpu_share>(p, 2, 180); break;
|
||||
case 8: construct_at<Cpu_share>(p, 2, 100); break;
|
||||
case 9: construct_at<Cpu_share>(p, 2, 0); break;
|
||||
default: return;
|
||||
}
|
||||
data()->scheduler.insert(*s);
|
||||
}
|
||||
|
||||
|
||||
void destroy(unsigned const id)
|
||||
{
|
||||
Cpu_share * const s = share(id);
|
||||
data()->scheduler.remove(*s);
|
||||
s->~Cpu_share();
|
||||
}
|
||||
|
||||
|
||||
unsigned time()
|
||||
{
|
||||
return data()->scheduler.quota() -
|
||||
data()->scheduler.residual();
|
||||
}
|
||||
|
||||
|
||||
void update_check(unsigned const l, unsigned const c, unsigned const t,
|
||||
unsigned const s, unsigned const q)
|
||||
{
|
||||
data()->scheduler.update(c);
|
||||
unsigned const st = time();
|
||||
if (t != st) {
|
||||
Genode::log("wrong time ", st, " in line ", l);
|
||||
done();
|
||||
}
|
||||
Cpu_share &hs = data()->scheduler.head();
|
||||
unsigned const hq = data()->scheduler.head_quota();
|
||||
if (&hs != share(s)) {
|
||||
unsigned const hi = share_id(&hs);
|
||||
Genode::log("wrong share ", hi, " in line ", l);
|
||||
done();
|
||||
}
|
||||
if (hq != q) {
|
||||
Genode::log("wrong quota ", hq, " in line ", l);
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ready_check(unsigned const l, unsigned const s, bool const x)
|
||||
{
|
||||
data()->scheduler.ready_check(*share(s));
|
||||
if (data()->scheduler.need_to_schedule() != x) {
|
||||
Genode::log("wrong check result ", data()->scheduler.need_to_schedule(), " in line ", l);
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shortcuts for all basic operations that the test consists of
|
||||
@@ -144,10 +129,10 @@ void ready_check(unsigned const l, unsigned const s, bool const x)
|
||||
|
||||
#define C(s) create(s);
|
||||
#define D(s) destroy(s);
|
||||
#define A(s) data()->scheduler.ready(*share(s));
|
||||
#define I(s) data()->scheduler.unready(*share(s));
|
||||
#define Y data()->scheduler.yield();
|
||||
#define Q(s, q) data()->scheduler.quota(*share(s), q);
|
||||
#define A(s) scheduler.ready(share(s));
|
||||
#define I(s) scheduler.unready(share(s));
|
||||
#define Y scheduler.yield();
|
||||
#define Q(s, q) scheduler.quota(share(s), q);
|
||||
#define U(c, t, s, q) update_check(__LINE__, c, t, s, q);
|
||||
#define O(s) ready_check(__LINE__, s, true);
|
||||
#define N(s) ready_check(__LINE__, s, false);
|
||||
@@ -157,6 +142,13 @@ void ready_check(unsigned const l, unsigned const s, bool const x)
|
||||
* Main routine
|
||||
*/
|
||||
void Component::construct(Genode::Env &)
|
||||
{
|
||||
static Main main;
|
||||
main.test();
|
||||
}
|
||||
|
||||
|
||||
void Main::test()
|
||||
{
|
||||
/*
|
||||
* Step-by-step testing
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
FROM_BASE_LINUX := etc src/lib/syscall src/lib/lx_hybrid lib/import include
|
||||
FROM_BASE_LINUX_AND_BASE := lib/mk src/lib/base src/include
|
||||
FROM_BASE := src/lib/timeout
|
||||
FROM_BASE_LINUX_AND_BASE := src/lib/base src/include
|
||||
|
||||
content: $(FROM_BASE_LINUX) $(FROM_BASE_LINUX_AND_BASE) $(FROM_BASE) LICENSE
|
||||
content: $(FROM_BASE_LINUX) $(FROM_BASE_LINUX_AND_BASE) LICENSE
|
||||
|
||||
$(FROM_BASE_LINUX):
|
||||
mkdir -p $@
|
||||
@@ -13,9 +12,30 @@ $(FROM_BASE_LINUX_AND_BASE):
|
||||
cp -r $(GENODE_DIR)/repos/base/$@/* $@
|
||||
cp -r $(REP_DIR)/$@/* $@
|
||||
|
||||
$(FROM_BASE):
|
||||
BASE_LIB_MK_CONTENT := \
|
||||
$(addprefix lib/mk/,base-common.inc timeout.mk)
|
||||
|
||||
content: $(BASE_LIB_MK_CONTENT)
|
||||
|
||||
$(BASE_LIB_MK_CONTENT):
|
||||
mkdir -p $(dir $@)
|
||||
cp $(GENODE_DIR)/repos/base/$@ $@
|
||||
|
||||
content: src/lib/timeout
|
||||
|
||||
src/lib/timeout:
|
||||
mkdir -p $@
|
||||
cp -r $(GENODE_DIR)/repos/base/$@/* $@
|
||||
|
||||
BASE_LINUX_LIB_MK_CONTENT := \
|
||||
$(addprefix lib/mk/,lx_hybrid.mk base-linux.inc base-linux-common.mk) \
|
||||
$(foreach S,arm arm_64 x86_32 x86_64,lib/mk/spec/$S/syscall-linux.mk)
|
||||
|
||||
content: $(BASE_LINUX_LIB_MK_CONTENT)
|
||||
|
||||
$(BASE_LINUX_LIB_MK_CONTENT):
|
||||
mkdir -p $(dir $@)
|
||||
cp $(REP_DIR)/$@ $@
|
||||
|
||||
LICENSE:
|
||||
cp $(GENODE_DIR)/LICENSE $@
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-04-12 dcb2c9200b333adb17f9a8737620cbd84f641408
|
||||
2022-10-11 4544924c73b2ee1d8d2717672320f14732807267
|
||||
|
||||
@@ -10,7 +10,6 @@ content:
|
||||
mv lib/mk/spec/$$spec/ld-linux.mk lib/mk/spec/$$spec/ld.mk; done;
|
||||
sed -i "/TARGET/s/core-linux/core/" src/core/linux/target.mk
|
||||
sed -i "s/BOARD.*unknown/BOARD := linux/" lib/mk/core-linux.inc
|
||||
sed -i "s/ld-linux/ld/" src/lib/ld/linux/target.mk
|
||||
sed -i "s/linux_timer_drv/timer/" src/timer/linux/target.mk
|
||||
rm -rf src/lib/initramfs
|
||||
rm -rf src/initramfs
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 4aea382035415c79bf5d551642ebfa64d42e4d21
|
||||
2022-10-11 d7e12d81f12f081bb7c00233c18f3c8ac2f00d67
|
||||
|
||||
@@ -5,14 +5,14 @@ REQUIRES = x86_64
|
||||
INITRAMFS = initramfs
|
||||
INITRAMFS_SRC_C = init.c
|
||||
|
||||
EXT_OBJECTS += $(BUILD_BASE_DIR)/lib/initramfs/$(INITRAMFS)
|
||||
EXT_OBJECTS += $(BUILD_BASE_DIR)/initramfs/$(INITRAMFS)
|
||||
|
||||
$(TARGET): $(INITRAMFS)
|
||||
|
||||
$(INITRAMFS): $(INITRAMFS_SRC_C)
|
||||
$(MSG_BUILD)$(INITRAMFS)
|
||||
$(VERBOSE)gcc $^ -O0 $(CC_MARCH) -Wall -W -Wextra -Werror -std=gnu99 -o $@ -Wl,-O3 -Wl,--as-needed -static
|
||||
$(VERBOSE)ln -sf $(BUILD_BASE_DIR)/lib/initramfs/$(INITRAMFS) $(BUILD_BASE_DIR)/bin/
|
||||
$(VERBOSE)ln -sf $(BUILD_BASE_DIR)/initramfs/$(INITRAMFS) $(BUILD_BASE_DIR)/bin/
|
||||
|
||||
clean_initramfs:
|
||||
$(VERBOSE)rm -rf $(INITRAMFS)
|
||||
@@ -172,6 +172,24 @@ void Region_map_mmap::_add_to_rmap(Region const ®ion)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tracing must be inhibited in attach/detach as RPC trace points may trigger
|
||||
* attachment of trace dataspaces, which would result in nested mutex
|
||||
* acquisition.
|
||||
*/
|
||||
|
||||
namespace Genode { extern bool inhibit_tracing; }
|
||||
|
||||
struct Inhibit_tracing_guard
|
||||
{
|
||||
bool old_value = inhibit_tracing;
|
||||
|
||||
Inhibit_tracing_guard() { inhibit_tracing = true; }
|
||||
|
||||
~Inhibit_tracing_guard() { inhibit_tracing = old_value; }
|
||||
};
|
||||
|
||||
|
||||
Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
||||
size_t size, off_t offset,
|
||||
bool use_local_addr,
|
||||
@@ -180,6 +198,8 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
||||
{
|
||||
Mutex::Guard mutex_guard(mutex());
|
||||
|
||||
Inhibit_tracing_guard it_guard { };
|
||||
|
||||
/* only support attach_at for sub RM sessions */
|
||||
if (_sub_rm && !use_local_addr) {
|
||||
error("Region_map_mmap::attach: attaching w/o local addr not supported");
|
||||
@@ -325,6 +345,8 @@ void Region_map_mmap::detach(Region_map::Local_addr local_addr)
|
||||
{
|
||||
Mutex::Guard mutex_guard(mutex());
|
||||
|
||||
Inhibit_tracing_guard it_guard { };
|
||||
|
||||
/*
|
||||
* Cases
|
||||
*
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
TARGET = ld-linux.lib
|
||||
LIBS = ld-linux
|
||||
|
||||
BUILD_ARTIFACTS := ld-linux.lib.so
|
||||
@@ -260,6 +260,30 @@ namespace Nova {
|
||||
*/
|
||||
enum Pd_op { TRANSFER_QUOTA = 0U, PD_DEBUG = 2U };
|
||||
|
||||
class Gsi_flags
|
||||
{
|
||||
private:
|
||||
|
||||
uint8_t _value { 0 };
|
||||
|
||||
public:
|
||||
|
||||
enum Mode { HIGH, LOW, EDGE };
|
||||
|
||||
Gsi_flags() { }
|
||||
|
||||
Gsi_flags(Mode m)
|
||||
{
|
||||
switch (m) {
|
||||
case HIGH: _value = 0b110; break; /* level-high */
|
||||
case LOW: _value = 0b111; break; /* level-low */
|
||||
case EDGE: _value = 0b100; break; /* edge-triggered */
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t value() const { return _value; }
|
||||
};
|
||||
|
||||
|
||||
class Descriptor
|
||||
{
|
||||
|
||||
@@ -457,12 +457,12 @@ namespace Nova {
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t assign_gsi(mword_t sm, mword_t dev, mword_t cpu,
|
||||
mword_t &msi_addr, mword_t &msi_data,
|
||||
mword_t si = ~0UL)
|
||||
mword_t si = ~0UL, Gsi_flags flags = Gsi_flags())
|
||||
{
|
||||
msi_addr = dev;
|
||||
msi_data = cpu;
|
||||
|
||||
return syscall_5(NOVA_ASSIGN_GSI, 0, sm, msi_addr, msi_data, si);
|
||||
return syscall_5(NOVA_ASSIGN_GSI, flags.value(), sm, msi_addr, msi_data, si);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -402,11 +402,11 @@ namespace Nova {
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t assign_gsi(mword_t sm, mword_t dev, mword_t cpu,
|
||||
mword_t &msi_addr, mword_t &msi_data,
|
||||
mword_t si = ~0UL)
|
||||
mword_t si = ~0UL, Gsi_flags flags = Gsi_flags())
|
||||
{
|
||||
msi_addr = dev;
|
||||
msi_data = cpu;
|
||||
return syscall_5(NOVA_ASSIGN_GSI, 0, sm, msi_addr, msi_data, si);
|
||||
return syscall_5(NOVA_ASSIGN_GSI, flags.value(), sm, msi_addr, msi_data, si);
|
||||
}
|
||||
}
|
||||
#endif /* _INCLUDE__SPEC__64BIT__NOVA__SYSCALLS_H_ */
|
||||
|
||||
@@ -1 +1 @@
|
||||
33a2fa953ec52b0f63b921f4d33d68891c0aada0
|
||||
9ad770935115d201863fd83924e4684b14b8b56f
|
||||
|
||||
@@ -4,7 +4,7 @@ DOWNLOADS := nova.git
|
||||
|
||||
# r10 branch
|
||||
URL(nova) := https://github.com/alex-ab/NOVA.git
|
||||
REV(nova) := 00dc49bc18e7f72a9c85487e8f94fd859511d89d
|
||||
REV(nova) := a34076e7b8d48d08c2edee7754eadad8b6ea5312
|
||||
DIR(nova) := src/kernel/nova
|
||||
|
||||
PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch))
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
FROM_BASE_NOVA := etc include
|
||||
FROM_BASE := lib/mk/timeout.mk src/lib/timeout
|
||||
|
||||
# base-nova.lib.a depends on timeout.lib.a, which includes base/internal/gloabls.h
|
||||
FROM_BASE := lib/mk/timeout.mk src/lib/timeout \
|
||||
src/include/base/internal/globals.h
|
||||
|
||||
content: $(FROM_BASE_NOVA) $(FROM_BASE) LICENSE
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 91bc8d51bbe703d56f5671019d14e4636f21bf1f
|
||||
2022-10-11 4458ea63a69ae070e19a3cb09a403137755d2cb0
|
||||
|
||||
@@ -15,8 +15,7 @@ src/kernel/nova: src/kernel
|
||||
|
||||
content:
|
||||
for spec in x86_32 x86_64; do \
|
||||
mv lib/mk/spec/$$spec/ld-nova.mk lib/mk/spec/$$spec/ld.mk; \
|
||||
mv lib/mk/spec/$$spec/ld-nova.mk lib/mk/spec/$$spec/ld.mk; \
|
||||
done;
|
||||
sed -i "s/ld-nova/ld/" src/lib/ld/nova/target.mk
|
||||
sed -i "s/nova_timer_drv/timer/" src/timer/nova/target.mk
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 8b59a28ade1392bae4aa772bbead1584a2dde1de
|
||||
2022-10-11 574204b7d442811236bba60e4fe3f79e34fe9985
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#ifndef _CORE__INCLUDE__IRQ_OBJECT_H_
|
||||
#define _CORE__INCLUDE__IRQ_OBJECT_H_
|
||||
|
||||
namespace Genode { class Irq_object; }
|
||||
#include <nova/syscall-generic.h> /* Gsi_flags */
|
||||
|
||||
namespace Genode { class Irq_object; class Irq_args; }
|
||||
|
||||
class Genode::Irq_object
|
||||
{
|
||||
@@ -26,22 +28,24 @@ class Genode::Irq_object
|
||||
addr_t _msi_data;
|
||||
addr_t _device_phys = 0; /* PCI config extended address */
|
||||
|
||||
Nova::Gsi_flags _gsi_flags { };
|
||||
|
||||
enum { KERNEL_CAP_COUNT_LOG2 = 0 };
|
||||
|
||||
Genode::addr_t irq_sel() const { return _kernel_caps; }
|
||||
addr_t irq_sel() const { return _kernel_caps; }
|
||||
|
||||
public:
|
||||
|
||||
Irq_object();
|
||||
~Irq_object();
|
||||
|
||||
Genode::addr_t msi_address() const { return _msi_addr; }
|
||||
Genode::addr_t msi_value() const { return _msi_data; }
|
||||
addr_t msi_address() const { return _msi_addr; }
|
||||
addr_t msi_value() const { return _msi_data; }
|
||||
|
||||
void sigh(Signal_context_capability cap);
|
||||
void ack_irq();
|
||||
|
||||
void start(unsigned irq, Genode::addr_t);
|
||||
void start(unsigned irq, addr_t, Irq_args const &);
|
||||
};
|
||||
|
||||
#endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
/* core includes */
|
||||
#include <irq_root.h>
|
||||
#include <irq_args.h>
|
||||
#include <platform.h>
|
||||
|
||||
/* NOVA includes */
|
||||
@@ -27,13 +28,12 @@
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
static bool irq_ctrl(Genode::addr_t irq_sel,
|
||||
Genode::addr_t &msi_addr, Genode::addr_t &msi_data,
|
||||
Genode::addr_t sig_sel, Genode::addr_t virt_addr = 0)
|
||||
static bool irq_ctrl(addr_t irq_sel, addr_t &msi_addr, addr_t &msi_data,
|
||||
addr_t sig_sel, Nova::Gsi_flags flags, addr_t virt_addr)
|
||||
{
|
||||
/* assign IRQ to CPU && request msi data to be used by driver */
|
||||
uint8_t res = Nova::assign_gsi(irq_sel, virt_addr, boot_cpu(),
|
||||
msi_addr, msi_data, sig_sel);
|
||||
msi_addr, msi_data, sig_sel, flags);
|
||||
|
||||
if (res != Nova::NOVA_OK)
|
||||
error("setting up MSI failed - error ", res);
|
||||
@@ -46,30 +46,28 @@ static bool irq_ctrl(Genode::addr_t irq_sel,
|
||||
}
|
||||
|
||||
|
||||
static bool associate(Genode::addr_t irq_sel,
|
||||
Genode::addr_t &msi_addr, Genode::addr_t &msi_data,
|
||||
Genode::Signal_context_capability sig_cap,
|
||||
Genode::addr_t virt_addr = 0)
|
||||
{
|
||||
return irq_ctrl(irq_sel, msi_addr, msi_data, sig_cap.local_name(),
|
||||
virt_addr);
|
||||
}
|
||||
|
||||
|
||||
static void deassociate(Genode::addr_t irq_sel)
|
||||
static bool associate_gsi(addr_t irq_sel, Signal_context_capability sig_cap,
|
||||
Nova::Gsi_flags gsi_flags)
|
||||
{
|
||||
addr_t dummy1 = 0, dummy2 = 0;
|
||||
|
||||
if (!irq_ctrl(irq_sel, dummy1, dummy2, irq_sel))
|
||||
return irq_ctrl(irq_sel, dummy1, dummy2, sig_cap.local_name(), gsi_flags, 0);
|
||||
}
|
||||
|
||||
|
||||
static void deassociate(addr_t irq_sel)
|
||||
{
|
||||
addr_t dummy1 = 0, dummy2 = 0;
|
||||
|
||||
if (!irq_ctrl(irq_sel, dummy1, dummy2, irq_sel, Nova::Gsi_flags(), 0))
|
||||
warning("Irq could not be de-associated");
|
||||
}
|
||||
|
||||
|
||||
static bool msi(Genode::addr_t irq_sel, Genode::addr_t phys_mem,
|
||||
Genode::addr_t &msi_addr, Genode::addr_t &msi_data,
|
||||
Genode::Signal_context_capability sig_cap)
|
||||
static bool associate_msi(addr_t irq_sel, addr_t phys_mem, addr_t &msi_addr,
|
||||
addr_t &msi_data, Signal_context_capability sig_cap)
|
||||
{
|
||||
return platform().region_alloc().alloc_aligned(4096, 12).convert<bool>(
|
||||
return platform().region_alloc().alloc_aligned(4096, 12).convert<bool>(
|
||||
|
||||
[&] (void *virt_ptr) {
|
||||
|
||||
@@ -89,7 +87,7 @@ static bool msi(Genode::addr_t irq_sel, Genode::addr_t phys_mem,
|
||||
}
|
||||
|
||||
/* try to assign MSI to device */
|
||||
bool res = associate(irq_sel, msi_addr, msi_data, sig_cap, virt_addr);
|
||||
bool res = irq_ctrl(irq_sel, msi_addr, msi_data, sig_cap.local_name(), Nova::Gsi_flags(), virt_addr);
|
||||
|
||||
unmap_local(Nova::Mem_crd(virt_addr >> 12, 0, Rights(true, true, true)));
|
||||
platform().region_alloc().free(virt_ptr, 4096);
|
||||
@@ -118,11 +116,12 @@ void Irq_object::sigh(Signal_context_capability cap)
|
||||
return;
|
||||
}
|
||||
|
||||
/* associate GSI or MSI to device belonging to device_phys */
|
||||
bool ok = false;
|
||||
if (_device_phys)
|
||||
ok = msi(irq_sel(), _device_phys, _msi_addr, _msi_data, cap);
|
||||
ok = associate_msi(irq_sel(), _device_phys, _msi_addr, _msi_data, cap);
|
||||
else
|
||||
ok = associate(irq_sel(), _msi_addr, _msi_data, cap);
|
||||
ok = associate_gsi(irq_sel(), cap, _gsi_flags);
|
||||
|
||||
if (!ok) {
|
||||
deassociate(irq_sel());
|
||||
@@ -141,7 +140,7 @@ void Irq_object::ack_irq()
|
||||
}
|
||||
|
||||
|
||||
void Irq_object::start(unsigned irq, Genode::addr_t const device_phys)
|
||||
void Irq_object::start(unsigned irq, addr_t const device_phys, Irq_args const &irq_args)
|
||||
{
|
||||
/* map IRQ SM cap from kernel to core at irq_sel selector */
|
||||
using Nova::Obj_crd;
|
||||
@@ -158,12 +157,29 @@ void Irq_object::start(unsigned irq, Genode::addr_t const device_phys)
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
/* initialize GSI IRQ flags */
|
||||
auto gsi_flags = [] (Irq_args const &args) {
|
||||
if (args.trigger() == Irq_session::TRIGGER_UNCHANGED
|
||||
|| args.polarity() == Irq_session::POLARITY_UNCHANGED)
|
||||
return Nova::Gsi_flags();
|
||||
|
||||
if (args.trigger() == Irq_session::TRIGGER_EDGE)
|
||||
return Nova::Gsi_flags(Nova::Gsi_flags::EDGE);
|
||||
|
||||
if (args.polarity() == Irq_session::POLARITY_HIGH)
|
||||
return Nova::Gsi_flags(Nova::Gsi_flags::HIGH);
|
||||
else
|
||||
return Nova::Gsi_flags(Nova::Gsi_flags::LOW);
|
||||
};
|
||||
|
||||
_gsi_flags = gsi_flags(irq_args);
|
||||
|
||||
/* associate GSI or MSI to device belonging to device_phys */
|
||||
bool ok = false;
|
||||
if (device_phys)
|
||||
ok = msi(irq_sel(), device_phys, _msi_addr, _msi_data, _sigh_cap);
|
||||
ok = associate_msi(irq_sel(), device_phys, _msi_addr, _msi_data, _sigh_cap);
|
||||
else
|
||||
ok = associate(irq_sel(), _msi_addr, _msi_data, _sigh_cap);
|
||||
ok = associate_gsi(irq_sel(), _sigh_cap, _gsi_flags);
|
||||
|
||||
if (!ok)
|
||||
throw Service_denied();
|
||||
@@ -212,7 +228,9 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||
:
|
||||
_irq_number(~0U), _irq_alloc(irq_alloc), _irq_object()
|
||||
{
|
||||
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
|
||||
Irq_args const irq_args(args);
|
||||
|
||||
long irq_number = irq_args.irq_number();
|
||||
long device_phys = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
||||
if (device_phys) {
|
||||
|
||||
@@ -232,7 +250,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||
|
||||
_irq_number = (unsigned)irq_number;
|
||||
|
||||
_irq_object.start(_irq_number, device_phys);
|
||||
_irq_object.start(_irq_number, device_phys, irq_args);
|
||||
}
|
||||
|
||||
|
||||
@@ -241,7 +259,7 @@ Irq_session_component::~Irq_session_component()
|
||||
if (_irq_number == ~0U)
|
||||
return;
|
||||
|
||||
Genode::addr_t free_irq = _irq_number;
|
||||
addr_t free_irq = _irq_number;
|
||||
_irq_alloc.free((void *)free_irq);
|
||||
}
|
||||
|
||||
@@ -252,13 +270,13 @@ void Irq_session_component::ack_irq()
|
||||
}
|
||||
|
||||
|
||||
void Irq_session_component::sigh(Genode::Signal_context_capability cap)
|
||||
void Irq_session_component::sigh(Signal_context_capability cap)
|
||||
{
|
||||
_irq_object.sigh(cap);
|
||||
}
|
||||
|
||||
|
||||
Genode::Irq_session::Info Irq_session_component::info()
|
||||
Irq_session::Info Irq_session_component::info()
|
||||
{
|
||||
if (!_irq_object.msi_address() || !_irq_object.msi_value())
|
||||
return { .type = Info::Type::INVALID, .address = 0, .value = 0 };
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
TARGET = ld-nova
|
||||
LIBS = ld-nova
|
||||
@@ -19,8 +19,7 @@ src/kernel/okl4: src/kernel
|
||||
|
||||
content:
|
||||
for spec in x86_32; do \
|
||||
mv lib/mk/spec/$$spec/ld-okl4.mk lib/mk/spec/$$spec/ld.mk; \
|
||||
mv lib/mk/spec/$$spec/ld-okl4.mk lib/mk/spec/$$spec/ld.mk; \
|
||||
done;
|
||||
sed -i "s/ld-okl4/ld/" src/lib/ld/okl4/target.mk
|
||||
sed -i "s/pit_timer_drv/timer/" src/timer/pit/target.inc
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 3b2acba4ebd649394e26217802598cf650a4b226
|
||||
2022-10-11 b81b8b94731cda35017a740b0110ff4e8e233e07
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
TARGET = ld-okl4
|
||||
LIBS = ld-okl4
|
||||
@@ -21,6 +21,5 @@ content:
|
||||
for spec in x86_32; do \
|
||||
mv lib/mk/spec/$$spec/ld-pistachio.mk lib/mk/spec/$$spec/ld.mk; \
|
||||
done;
|
||||
sed -i "s/ld-pistachio/ld/" src/lib/ld/pistachio/target.mk
|
||||
sed -i "s/pit_timer_drv/timer/" src/timer/pit/target.inc
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 ca2c90ebcbaa61ade7373d6ea48a608912cd2629
|
||||
2022-10-11 b522663f9c8c779f255e2a5eb37f98b4301c5446
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
TARGET = ld-pistachio
|
||||
LIBS = ld-pistachio
|
||||
@@ -35,7 +35,6 @@ etc/board.conf:
|
||||
|
||||
content:
|
||||
mv lib/mk/spec/arm/ld-sel4.mk lib/mk/spec/arm/ld.mk;
|
||||
sed -i "s/ld-sel4/ld/" src/lib/ld/sel4/target.mk
|
||||
sed -i "s/imx6_timer_drv/timer/" src/timer/epit/imx6/target.inc
|
||||
find lib/mk/spec -name kernel-sel4-*.mk -o -name syscall-sel4-*.mk |\
|
||||
grep -v "sel4-imx6q_sabrelite.mk" | xargs rm -rf
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-05-24 5d9558d34f4bd3f3e34d9b175fe3eb37be3561be
|
||||
2022-10-11 6966c1e6595fec6e545ae729b9a5893e745a9fc9
|
||||
|
||||
@@ -35,7 +35,6 @@ etc/board.conf:
|
||||
|
||||
content:
|
||||
mv lib/mk/spec/arm/ld-sel4.mk lib/mk/spec/arm/ld.mk;
|
||||
sed -i "s/ld-sel4/ld/" src/lib/ld/sel4/target.mk
|
||||
sed -i "s/imx7_timer_drv/timer/" src/timer/gpt/imx7/target.inc
|
||||
find lib/mk/spec -name kernel-sel4-*.mk -o -name syscall-sel4-*.mk |\
|
||||
grep -v "sel4-imx7d_sabre.mk" | xargs rm -rf
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user