mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
hw: avoid overhead for cache maintainance
When running on x86, and riscv never enter the kernel for cache maintainance, but use the dummy implementation of the generic base library instead. On ARMv8 it is not necessary to enter privileged mode for cache cleaning, and unification of instruction/data cache, but only for invalidating cache lines at all levels, which is necessary for the use cases, where this function it needed (coherency of DMA memory). Fix genodelabs/genode#4339
This commit is contained in:
parent
66fd027b96
commit
08c56e61e1
3
repos/base-hw/lib/mk/spec/arm/base-hw.mk
Normal file
3
repos/base-hw/lib/mk/spec/arm/base-hw.mk
Normal file
@ -0,0 +1,3 @@
|
||||
vpath cache.cc $(REP_DIR)/src/lib/base/arm
|
||||
|
||||
include $(REP_DIR)/lib/mk/base-hw.inc
|
3
repos/base-hw/lib/mk/spec/arm_64/base-hw.mk
Normal file
3
repos/base-hw/lib/mk/spec/arm_64/base-hw.mk
Normal file
@ -0,0 +1,3 @@
|
||||
vpath cache.cc $(REP_DIR)/src/lib/base/arm_64
|
||||
|
||||
include $(REP_DIR)/lib/mk/base-hw.inc
|
1
repos/base-hw/lib/mk/spec/riscv/base-hw.mk
Normal file
1
repos/base-hw/lib/mk/spec/riscv/base-hw.mk
Normal file
@ -0,0 +1 @@
|
||||
include $(REP_DIR)/lib/mk/base-hw.inc
|
1
repos/base-hw/lib/mk/spec/x86_64/base-hw.mk
Normal file
1
repos/base-hw/lib/mk/spec/x86_64/base-hw.mk
Normal file
@ -0,0 +1 @@
|
||||
include $(REP_DIR)/lib/mk/base-hw.inc
|
@ -133,7 +133,7 @@ SRC_CORE += $(notdir $(wildcard $(BASE_HW_DIR)/src/core/*.cc)) \
|
||||
|
||||
# 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 \
|
||||
base.inc base-hw.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 \
|
||||
|
@ -57,6 +57,10 @@ struct Genode::Cpu : Arm_cpu
|
||||
|
||||
return instruction_cache_line_size;
|
||||
}
|
||||
|
||||
static inline size_t cache_line_size() {
|
||||
return Genode::min(data_cache_line_size(),
|
||||
instruction_cache_line_size()); }
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__ARM_V6__CPU_H_ */
|
||||
|
@ -79,6 +79,11 @@ struct Genode::Arm_v7_cpu : Arm_cpu
|
||||
|
||||
return instruction_cache_line_size;
|
||||
}
|
||||
|
||||
|
||||
static inline size_t cache_line_size() {
|
||||
return Genode::min(data_cache_line_size(),
|
||||
instruction_cache_line_size()); }
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__ARM_V7__CPU_SUPPORT_H_ */
|
||||
|
54
repos/base-hw/src/include/base/internal/cache.h
Normal file
54
repos/base-hw/src/include/base/internal/cache.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* \brief Cache maintainance utilities
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2022-12-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _INCLUDE__BASE__INTERNAL__CACHE_H_
|
||||
#define _INCLUDE__BASE__INTERNAL__CACHE_H_
|
||||
|
||||
#include <base/internal/page_size.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <util/touch.h>
|
||||
|
||||
template <typename FN>
|
||||
static inline void for_each_page(Genode::addr_t addr,
|
||||
Genode::size_t size,
|
||||
FN const & fn)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
while (size) {
|
||||
addr_t next_page = align_addr(addr+1, get_page_size_log2());
|
||||
size_t s = min(size, next_page - addr);
|
||||
touch_read(reinterpret_cast<unsigned char *>(addr));
|
||||
fn(addr, s);
|
||||
addr += s;
|
||||
size -= s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename FN>
|
||||
static inline void for_each_cache_line(Genode::addr_t addr,
|
||||
Genode::size_t size,
|
||||
FN const & fn)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
static size_t cache_line_size = Kernel::cache_line_size();
|
||||
|
||||
addr_t start = addr;
|
||||
addr_t const end = addr + size;
|
||||
for (; start < end; start += cache_line_size)
|
||||
fn(start);
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__BASE__INTERNAL__CACHE_H_ */
|
41
repos/base-hw/src/lib/base/arm/cache.cc
Normal file
41
repos/base-hw/src/lib/base/arm/cache.cc
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* \brief Implementation of cache operations for ARM
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2022-12-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <kernel/interface.h>
|
||||
|
||||
#include <base/internal/cache.h>
|
||||
#include <cpu/cache.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
void Genode::cache_coherent(addr_t addr, size_t size)
|
||||
{
|
||||
for_each_page(addr, size, [] (addr_t addr, size_t size) {
|
||||
Kernel::cache_coherent_region(addr, size); });
|
||||
}
|
||||
|
||||
|
||||
void Genode::cache_clean_invalidate_data(addr_t addr, size_t size)
|
||||
{
|
||||
for_each_page(addr, size, [] (addr_t addr, size_t size) {
|
||||
Kernel::cache_clean_invalidate_data_region(addr, size); });
|
||||
}
|
||||
|
||||
|
||||
void Genode::cache_invalidate_data(addr_t addr, size_t size)
|
||||
{
|
||||
for_each_page(addr, size, [] (addr_t addr, size_t size) {
|
||||
Kernel::cache_invalidate_data_region(addr, size); });
|
||||
}
|
||||
|
57
repos/base-hw/src/lib/base/arm_64/cache.cc
Normal file
57
repos/base-hw/src/lib/base/arm_64/cache.cc
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* \brief Implementation of the cache maintainance on ARMv8
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2022-12-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <kernel/interface.h>
|
||||
|
||||
#include <base/internal/cache.h>
|
||||
#include <cpu/cache.h>
|
||||
#include <cpu/memory_barrier.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
void Genode::cache_coherent(addr_t addr, size_t size)
|
||||
{
|
||||
Genode::memory_barrier();
|
||||
|
||||
for_each_page(addr, size, [] (addr_t addr, size_t size) {
|
||||
for_each_cache_line(addr, size, [&] (addr_t addr) {
|
||||
asm volatile("dc cvau, %0" :: "r" (addr));
|
||||
asm volatile("dsb ish");
|
||||
asm volatile("ic ivau, %0" :: "r" (addr));
|
||||
asm volatile("dsb ish");
|
||||
asm volatile("isb");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Genode::cache_clean_invalidate_data(addr_t addr, size_t size)
|
||||
{
|
||||
Genode::memory_barrier();
|
||||
|
||||
for_each_page(addr, size, [&] (addr_t addr, size_t size) {
|
||||
|
||||
for_each_cache_line(addr, size, [&] (addr_t addr) {
|
||||
asm volatile("dc civac, %0" :: "r" (addr)); });
|
||||
});
|
||||
|
||||
asm volatile("dsb sy");
|
||||
asm volatile("isb");
|
||||
}
|
||||
|
||||
|
||||
void Genode::cache_invalidate_data(addr_t addr, size_t size)
|
||||
{
|
||||
for_each_page(addr, size, [] (addr_t addr, size_t size) {
|
||||
Kernel::cache_invalidate_data_region(addr, size); });
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* \brief Implementation of the cache operations
|
||||
* \author Christian Prochaska
|
||||
* \date 2014-05-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014-2017 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.
|
||||
*/
|
||||
|
||||
#include <kernel/interface.h>
|
||||
|
||||
#include <base/internal/page_size.h>
|
||||
#include <cpu/cache.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <util/touch.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
template <typename FN>
|
||||
static void for_cachelines(addr_t addr, size_t size, FN const & fn)
|
||||
{
|
||||
/**
|
||||
* The kernel accepts the cache maintainance calls for one designated
|
||||
* page only. Otherwise, it just ignores the call to limit the time being
|
||||
* uninteruppptible in the kernel. Therefore, we have to loop if more than
|
||||
* one page is affected by the given region.
|
||||
*/
|
||||
while (size) {
|
||||
addr_t next_page = align_addr(addr+1, get_page_size_log2());
|
||||
size_t s = min(size, next_page - addr);
|
||||
touch_read(reinterpret_cast<unsigned char *>(addr));
|
||||
fn(addr, s);
|
||||
addr += s;
|
||||
size -= s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Genode::cache_coherent(addr_t addr, size_t size)
|
||||
{
|
||||
for_cachelines(addr, size, [] (addr_t addr, size_t size) {
|
||||
Kernel::cache_coherent_region(addr, size); });
|
||||
}
|
||||
|
||||
|
||||
void Genode::cache_clean_invalidate_data(addr_t addr, size_t size)
|
||||
{
|
||||
for_cachelines(addr, size, [] (addr_t addr, size_t size) {
|
||||
Kernel::cache_clean_invalidate_data_region(addr, size); });
|
||||
}
|
||||
|
||||
|
||||
void Genode::cache_invalidate_data(addr_t addr, size_t size)
|
||||
{
|
||||
for_cachelines(addr, size, [] (addr_t addr, size_t size) {
|
||||
Kernel::cache_invalidate_data_region(addr, size); });
|
||||
}
|
Loading…
Reference in New Issue
Block a user