1 /*
2  * Copyright (c) 2024 BayLibre SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <mmu.h>
7 #include <kernel_arch_interface.h>
8 #include <zephyr/kernel/mm/demand_paging.h>
9 #include <zephyr/linker/linker-defs.h>
10 #include <zephyr/arch/common/semihost.h>
11 
12 /*
13  * semihost.h declares prototypes with longs but (at least on QEMU)
14  * returned values are 32-bits only. Let's use an int.
15  */
16 static int semih_fd = -1;
17 
k_mem_paging_backing_store_location_get(struct k_mem_page_frame * pf,uintptr_t * location,bool page_fault)18 int k_mem_paging_backing_store_location_get(struct k_mem_page_frame *pf,
19 					    uintptr_t *location,
20 					    bool page_fault)
21 {
22 	if (k_mem_page_frame_is_backed(pf)) {
23 		return k_mem_paging_backing_store_location_query(
24 				k_mem_page_frame_to_virt(pf), location);
25 	} else {
26 		/* this is a read-only backing store */
27 		return -ENOMEM;
28 	}
29 }
30 
k_mem_paging_backing_store_location_free(uintptr_t location)31 void k_mem_paging_backing_store_location_free(uintptr_t location)
32 {
33 }
34 
k_mem_paging_backing_store_page_out(uintptr_t location)35 void k_mem_paging_backing_store_page_out(uintptr_t location)
36 {
37 	__ASSERT(false, "not ever supposed to be called");
38 	k_panic();
39 }
40 
k_mem_paging_backing_store_page_in(uintptr_t location)41 void k_mem_paging_backing_store_page_in(uintptr_t location)
42 {
43 	long size = CONFIG_MMU_PAGE_SIZE;
44 
45 	if (semihost_seek(semih_fd, (long)location) != 0 ||
46 	    semihost_read(semih_fd, K_MEM_SCRATCH_PAGE, size) != size) {
47 		k_panic();
48 	}
49 }
50 
k_mem_paging_backing_store_page_finalize(struct k_mem_page_frame * pf,uintptr_t location)51 void k_mem_paging_backing_store_page_finalize(struct k_mem_page_frame *pf,
52 					      uintptr_t location)
53 {
54 	k_mem_page_frame_set(pf, K_MEM_PAGE_FRAME_BACKED);
55 }
56 
k_mem_paging_backing_store_location_query(void * addr,uintptr_t * location)57 int k_mem_paging_backing_store_location_query(void *addr, uintptr_t *location)
58 {
59 	uintptr_t offset = (uintptr_t)addr - (uintptr_t)lnkr_ondemand_start;
60 	uintptr_t file_offset = (uintptr_t)lnkr_ondemand_load_start
61 				- (uintptr_t)__text_region_start + offset;
62 
63 	__ASSERT(file_offset % CONFIG_MMU_PAGE_SIZE == 0, "file_offset = %#lx", file_offset);
64 	*location = file_offset;
65 	return 0;
66 }
67 
k_mem_paging_backing_store_init(void)68 void k_mem_paging_backing_store_init(void)
69 {
70 	semih_fd = semihost_open("./zephyr/zephyr.bin", SEMIHOST_OPEN_RB);
71 	__ASSERT(semih_fd >= 0, "semihost_open() returned %d", semih_fd);
72 	if (semih_fd < 0) {
73 		k_panic();
74 	}
75 }
76