Browse Source

demand_paging: add a semihosting based backing store for on-demand sections

This is especially handy for tests and validation using QEMU.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
pull/78288/head
Nicolas Pitre 11 months ago committed by Anas Nashif
parent
commit
4fd3bf2060
  1. 5
      subsys/demand_paging/backing_store/CMakeLists.txt
  2. 10
      subsys/demand_paging/backing_store/Kconfig
  3. 75
      subsys/demand_paging/backing_store/backing_store_ondemand_semihost.c

5
subsys/demand_paging/backing_store/CMakeLists.txt

@ -16,4 +16,9 @@ if(NOT DEFINED CONFIG_BACKING_STORE_CUSTOM)
CONFIG_BACKING_STORE_QEMU_X86_TINY_FLASH CONFIG_BACKING_STORE_QEMU_X86_TINY_FLASH
backing_store_qemu_x86_tiny.c backing_store_qemu_x86_tiny.c
) )
zephyr_library_sources_ifdef(
CONFIG_BACKING_STORE_ONDEMAND_SEMIHOST
backing_store_ondemand_semihost.c
)
endif() endif()

10
subsys/demand_paging/backing_store/Kconfig

@ -28,6 +28,16 @@ config BACKING_STORE_QEMU_X86_TINY_FLASH
the symbols outside of boot and pinned sections into the flash the symbols outside of boot and pinned sections into the flash
area, allowing testing of the demand paging mechanism on area, allowing testing of the demand paging mechanism on
code and data. code and data.
config BACKING_STORE_ONDEMAND_SEMIHOST
bool "Backing store for on-demand linker section using semihosting"
depends on SEMIHOST && LINKER_USE_ONDEMAND_SECTION
help
This is used to do on-demand paging of code and data marked with
__ondemand_func and __ondemand_rodata tags respectively. The compiled
zephyr.bin on the host is used to retrieve needed data with the
semihosting I/O facility.
endchoice endchoice
if BACKING_STORE_RAM if BACKING_STORE_RAM

75
subsys/demand_paging/backing_store/backing_store_ondemand_semihost.c

@ -0,0 +1,75 @@
/*
* Copyright (c) 2024 BayLibre SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <mmu.h>
#include <kernel_arch_interface.h>
#include <zephyr/kernel/mm/demand_paging.h>
#include <zephyr/linker/linker-defs.h>
#include <zephyr/arch/common/semihost.h>
/*
* semihost.h declares prototypes with longs but (at least on QEMU)
* returned values are 32-bits only. Let's use an int.
*/
static int semih_fd = -1;
int k_mem_paging_backing_store_location_get(struct k_mem_page_frame *pf,
uintptr_t *location,
bool page_fault)
{
if (k_mem_page_frame_is_backed(pf)) {
return k_mem_paging_backing_store_location_query(
k_mem_page_frame_to_virt(pf), location);
} else {
/* this is a read-only backing store */
return -ENOMEM;
}
}
void k_mem_paging_backing_store_location_free(uintptr_t location)
{
}
void k_mem_paging_backing_store_page_out(uintptr_t location)
{
__ASSERT(true, "not ever supposed to be called");
k_panic();
}
void k_mem_paging_backing_store_page_in(uintptr_t location)
{
long size = CONFIG_MMU_PAGE_SIZE;
if (semihost_seek(semih_fd, (long)location) != 0 ||
semihost_read(semih_fd, K_MEM_SCRATCH_PAGE, size) != size) {
k_panic();
}
}
void k_mem_paging_backing_store_page_finalize(struct k_mem_page_frame *pf,
uintptr_t location)
{
k_mem_page_frame_set(pf, K_MEM_PAGE_FRAME_BACKED);
}
int k_mem_paging_backing_store_location_query(void *addr, uintptr_t *location)
{
uintptr_t offset = (uintptr_t)addr - (uintptr_t)lnkr_ondemand_start;
uintptr_t file_offset = (uintptr_t)lnkr_ondemand_load_start
- (uintptr_t)__text_region_start + offset;
__ASSERT(file_offset % CONFIG_MMU_PAGE_SIZE == 0, "file_offset = %#lx", file_offset);
*location = file_offset;
return 0;
}
void k_mem_paging_backing_store_init(void)
{
semih_fd = semihost_open("./zephyr/zephyr.bin", SEMIHOST_OPEN_RB);
__ASSERT(semih_fd >= 0, "semihost_open() returned %d", semih_fd);
if (semih_fd < 0) {
k_panic();
}
}
Loading…
Cancel
Save