diff --git a/subsys/demand_paging/backing_store/CMakeLists.txt b/subsys/demand_paging/backing_store/CMakeLists.txt index 61cabe62b62..8df76d071c2 100644 --- a/subsys/demand_paging/backing_store/CMakeLists.txt +++ b/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 backing_store_qemu_x86_tiny.c ) + + zephyr_library_sources_ifdef( + CONFIG_BACKING_STORE_ONDEMAND_SEMIHOST + backing_store_ondemand_semihost.c + ) endif() diff --git a/subsys/demand_paging/backing_store/Kconfig b/subsys/demand_paging/backing_store/Kconfig index 16781dbd114..96b8ead7796 100644 --- a/subsys/demand_paging/backing_store/Kconfig +++ b/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 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 diff --git a/subsys/demand_paging/backing_store/backing_store_ondemand_semihost.c b/subsys/demand_paging/backing_store/backing_store_ondemand_semihost.c new file mode 100644 index 00000000000..9f062a3002a --- /dev/null +++ b/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 +#include +#include +#include +#include + +/* + * 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(); + } +}