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) @@ -16,4 +16,9 @@ if(NOT DEFINED CONFIG_BACKING_STORE_CUSTOM)
CONFIG_BACKING_STORE_QEMU_X86_TINY_FLASH
backing_store_qemu_x86_tiny.c
)
zephyr_library_sources_ifdef(
CONFIG_BACKING_STORE_ONDEMAND_SEMIHOST
backing_store_ondemand_semihost.c
)
endif()

10
subsys/demand_paging/backing_store/Kconfig

@ -28,6 +28,16 @@ config BACKING_STORE_QEMU_X86_TINY_FLASH @@ -28,6 +28,16 @@ config BACKING_STORE_QEMU_X86_TINY_FLASH
the symbols outside of boot and pinned sections into the flash
area, allowing testing of the demand paging mechanism on
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
if BACKING_STORE_RAM

75
subsys/demand_paging/backing_store/backing_store_ondemand_semihost.c

@ -0,0 +1,75 @@ @@ -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