# HG changeset patch # User Paul Boddie # Date 1651360045 -7200 # Node ID 813c00c07646257e2dbff52435413a613eb5fb01 # Parent b9f42fe7c67e631725e8b2b2c4596908ad40e626 Added various elements to allow the payload to run apparently successfully. diff -r b9f42fe7c67e -r 813c00c07646 tests/Makefile --- a/tests/Makefile Tue Apr 26 23:15:30 2022 +0200 +++ b/tests/Makefile Sun May 01 01:07:25 2022 +0200 @@ -27,17 +27,20 @@ include $(IDL_MK_DIR)/idl.mk +# Compound interfaces. + +pager_object_NAME = PagerObject +pager_object_INTERFACES = region_mapper system_pager + +COMP_INTERFACES_CC = pager_object + # Individual interfaces. -CLIENT_INTERFACES_CC = system_pager - -SERVER_INTERFACES_CC = system_pager +SERVER_INTERFACES_CC = $(call common_interfaces,$(COMP_INTERFACES_CC)) # Generated and plain source files. -CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC)) - -SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC)) +SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC) $(COMP_INTERFACES_CC)) # Normal source files. @@ -66,8 +69,7 @@ SRC_CC_dstest_test_client = dstest_test_client.cc PLAIN_SRC_CC_dstest_exec = dstest_exec.cc -SRC_CC_dstest_exec = $(PLAIN_SRC_CC_dstest_exec) $(SERVER_INTERFACES_SRC_CC) \ - $(CLIENT_INTERFACES_SRC_CC) +SRC_CC_dstest_exec = $(PLAIN_SRC_CC_dstest_exec) $(SERVER_INTERFACES_SRC_CC) REQUIRES_LIBS = l4re_c-util libfsclient libmem libipc libstdc++ libsystypes libe2access_blockserver PRIVATE_INCDIR = $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR) @@ -75,4 +77,4 @@ include $(L4DIR)/mk/prog.mk include $(IDL_MK_DIR)/interface_rules.mk -$(PLAIN_SRC_CC_dstest_exec): $(SERVER_INTERFACES_SRC_CC) $(CLIENT_INTERFACES_SRC_CC) +$(PLAIN_SRC_CC_dstest_exec): $(SERVER_INTERFACES_SRC_CC) diff -r b9f42fe7c67e -r 813c00c07646 tests/dstest_exec.cc --- a/tests/dstest_exec.cc Tue Apr 26 23:15:30 2022 +0200 +++ b/tests/dstest_exec.cc Sun May 01 01:07:25 2022 +0200 @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -32,6 +34,8 @@ #include #include +#include + #include #include #include @@ -39,67 +43,271 @@ #include #include -#include "system_pager_interface.h" -#include "system_pager_server.h" +#include "pager_object_interface.h" +#include "pager_object_server.h" -/* A simple system pager. */ +/* Region data structures. */ -class ExecPager : public SystemPager +class Region { public: - l4_addr_t buf, buf_start; - unsigned int buf_log2size; + l4_addr_t start; + unsigned int log2size; + l4_umword_t flags; + l4_addr_t map_start; + + explicit Region() + : start(0), log2size(0), flags(0), map_start(0) + { + } + + explicit Region(l4_addr_t start, unsigned int log2size, l4_umword_t flags, + l4_addr_t map_start) + : start(start), log2size(log2size), flags(flags), map_start(map_start) + { + } +}; + +typedef std::map Regions; + + + +/* A simple system pager also acting as a region mapper. */ + +class ExecPager : public PagerObject +{ +protected: + Regions _regions; + +public: + virtual void add(Region region) + { + _regions[region.map_start] = region; + } + + /* Notification methods. */ virtual long exception(l4_exc_regs_t regs, l4_snd_fpage_t *region); virtual long page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region); + + /* Region manager/mapper methods. */ + + virtual long attach(address_t *start, offset_t size, map_flags_t flags, + l4_cap_idx_t ds, address_t offset, unsigned char align); + }; +/* Handle a general exception. */ + long ExecPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region) { (void) region; printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s)); + + printf("r15 = %lx\n", regs.r15); + printf("r14 = %lx\n", regs.r14); + printf("r13 = %lx\n", regs.r13); + printf("r12 = %lx\n", regs.r12); + printf("r11 = %lx\n", regs.r11); + printf("r10 = %lx\n", regs.r10); + printf("r9 = %lx\n", regs.r9); + printf("r8 = %lx\n", regs.r8); + printf("rdi = %lx\n", regs.rdi); + printf("rsi = %lx\n", regs.rsi); + printf("rbp = %lx\n", regs.rbp); + printf("pfa = %lx\n", regs.pfa); + printf("rbx = %lx\n", regs.rbx); + printf("rdx = %lx\n", regs.rdx); + printf("rcx = %lx\n", regs.rcx); + printf("rax = %lx\n", regs.rax); + printf("trapno = %lx\n", regs.trapno); + printf("err = %lx\n", regs.err); + printf("ip = %lx\n", regs.ip); + printf("flags = %lx\n", regs.flags); + printf("sp = %lx\n", regs.sp); + printf("ss = %lx\n", regs.ss); + printf("fs_base = %lx\n", regs.fs_base); + printf("gs_base = %lx\n", regs.gs_base); + return L4_EOK; } +/* Handle a page fault using any configured regions. */ + long ExecPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region) { l4_umword_t addr = pfa & ~7UL, flags = pfa & 7; - printf("page_fault(%lx, %lx) -> %lx (%lx)...\n", pfa, pc, addr, flags); +#if 0 + printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags); +#endif + + Regions::iterator it = _regions.upper_bound(addr); + + if (it != _regions.begin()) + it--; + else + { + printf("not mapped!\n"); + return -L4_ENOMEM; + } + + Region &r = it->second; - if ((addr >= buf_start) && (addr < buf_start + (1UL << buf_log2size))) + if ((addr >= r.map_start) && (addr < r.map_start + (1UL << r.log2size))) { - region->fpage = l4_fpage(buf, buf_log2size, L4_FPAGE_RX); - region->snd_base = buf_start; + l4_addr_t page_addr = trunc(addr, L4_PAGESIZE); + + region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, r.flags); + region->snd_base = page_addr; + +#if 0 + printf("%lx...%lx from %lx...%lx size %d rights %x\n", + r.map_start, region->snd_base, + r.start, l4_fpage_memaddr(region->fpage), + l4_fpage_size(region->fpage), + l4_fpage_rights(region->fpage)); + printf("%lx -> ", addr); + + for (unsigned int i = 0; i < sizeof(l4_umword_t); i++) + printf("%02x", *((unsigned char *)(r.start + (addr - r.map_start) + i))); + + printf("\n"); +#endif return L4_EOK; } +#if 0 + printf("not mapped!\n"); +#endif + return -L4_ENOMEM; } +/* Attach a region for provision when page faults occur. This is required in + the initialisation of a program by the C library which requires a region + mapper. */ + +long ExecPager::attach(address_t *start, offset_t size, map_flags_t flags, + l4_cap_idx_t ds, address_t offset, unsigned char align) +{ +#if 0 + printf("attach(%lx, %ld, %lx, ..., %lx, %d)\n", *start, size, flags, offset, align); +#endif + + if (align < L4_PAGESHIFT) + align = L4_PAGESHIFT; + + offset_t increment = 1UL << align; + offset_t region_size = round(size, increment); + + /* Either attempt to find an address for the specified region, starting from + any indicated address. */ + + if (flags & L4RE_RM_F_SEARCH_ADDR) + { + address_t region_start = trunc(*start, increment); + Regions::iterator it = _regions.upper_bound(*start); + + if (!region_start) + region_start += increment; + +#if 0 + printf("-> search from %lx -> %lx...\n", *start, region_start); +#endif + + /* Before last known region. */ + + while (it != _regions.end()) + { + Regions::iterator next = it; + Region &r = it->second; + address_t start_limit; + address_t end_limit = r.map_start; + + /* Consider any preceding region. If no such region exists, choose an + address at the start of memory. */ + + if (it == _regions.begin()) + start_limit = L4_PAGESIZE; + else + { + it--; + Region &pr = it->second; + start_limit = pr.map_start + (1UL << pr.log2size); + it = next; + } + + /* Test against the limits. */ + + if (region_start < start_limit) + region_start = round(start_limit, increment); + + /* Investigate subsequent regions if not enough space exists between the + preceding region (or start of memory) and the current region. */ + + if ((region_start + region_size) > end_limit) + { + it++; + if (it == _regions.end()) + return -L4_ENOMEM; + } + else + break; + } + + /* Attach the provided dataspace. + NOTE: This is only done in this implementation to support the paging + mechanism. In a region mapper residing within the actual task, the + dataspace's map operation would be invoked to obtain mappings. */ + + l4_addr_t ds_start; + + long err = ipc_attach_dataspace(ds, size, (void **) &ds_start); + + if (err) + return err; + + l4_touch_rw((const void *) ds_start, size); + +#if 0 + printf("-> added region for %lx size %ld (%d)\n", region_start, region_size, page_order(region_size)); +#endif + + add(Region(ds_start, page_order(region_size), flags & L4RE_DS_F_RIGHTS_MASK, region_start)); + + *start = region_start; + return L4_EOK; + } + + /* Or attempt to add the specified region at a specific address. */ + + else + { + // NOTE: To be implemented. + + return -L4_ENOMEM; + } +} + static ExecPager exec_pager; -static void init_pager(ipc_server_config_type *config, l4_addr_t buf, - unsigned int buf_log2size, l4_addr_t buf_start) +static void init_pager(ipc_server_config_type *config) { - exec_pager.buf = buf; - exec_pager.buf_log2size = buf_log2size; - exec_pager.buf_start = buf_start; - ipc_server_init_config(config); - config->expected_items = SystemPager_expected_items; - config->handler = (ipc_server_handler_type) handle_SystemPager; - config->handler_obj = static_cast(&exec_pager); + config->expected_items = PagerObject_expected_items; + config->handler = (ipc_server_handler_type) handle_PagerObject; + config->handler_obj = static_cast(&exec_pager); } static long start_pager(ipc_server_config_type *config, pthread_t thread) @@ -128,13 +336,6 @@ -static offset_t find_region_size(offset_t size) -{ - return 1 << page_order(size); -} - - - /* Capability mapping definitions for the new task. */ struct mapped_cap @@ -197,34 +398,60 @@ return 1; } - /* Copy the entire payload to a new dataspace. */ + /* Copy the payload regions to new dataspaces. + NOTE: This should be directed by the ELF metadata. */ - char *buf; + char *program_buf; offset_t nread; - offset_t region_size = find_region_size(4000000); - l4re_ds_t region_ds; + offset_t program_region_contents = 0x28466; + offset_t program_region_size = round(program_region_contents, L4_PAGESIZE); + l4re_ds_t program_region_ds; - err = ipc_allocate_align(region_size, L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RWX, - page_order(4000000), (void **) &buf, ®ion_ds); + err = ipc_allocate_align(program_region_size, L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RWX, + L4_PAGESHIFT, (void **) &program_buf, &program_region_ds); if (err) { - printf("Could not reserve memory.\n"); + printf("Could not reserve program memory.\n"); return 1; } - printf("Reading from file into %p.\n", buf); - - nread = client_read(file, buf, 4000000); + nread = client_read(file, program_buf, program_region_contents); - printf("Read %ld from file.\n", nread); + printf("Read %ld from file into %p.\n", nread, program_buf); - if (memcmp(buf + 0xae3, "\x31\xed", 2)) + if (memcmp(program_buf + 0xae3, "\x31\xed", 2)) { printf("Did not find expected instructions at start.\n"); return 1; } + offset_t data_region_start = 0x102a360; + offset_t data_region_size = round(0x8068, L4_PAGESIZE); + offset_t data_region_base = trunc(data_region_start, L4_PAGESIZE); + offset_t data_region_offset = data_region_start - data_region_base; + + char *data_buf; + offset_t data_region_contents = 0x2058; + l4re_ds_t data_region_ds; + + err = ipc_allocate_align(data_region_size, L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW, + L4_PAGESHIFT, (void **) &data_buf, &data_region_ds); + + if (err) + { + printf("Could not reserve data memory.\n"); + return 1; + } + + memset(data_buf, 0, data_region_size); + + client_seek(file, 0x29360, SEEK_SET); + nread = client_read(file, data_buf + data_region_offset, data_region_contents); + + printf("Read %ld from file into %p in region %p with size %ld for %lx.\n", + nread, data_buf + data_region_offset, data_buf, data_region_size, data_region_base); + /* UTCB location and size. */ l4_addr_t utcb_start = Utcb_area_start; @@ -235,15 +462,134 @@ if (utcb_log2size < L4_PAGESHIFT) utcb_log2size = L4_PAGESHIFT; + l4_fpage_t utcb_fpage = l4_fpage(utcb_start, utcb_log2size, 0); + /* KIP allocation. */ l4_addr_t kip_start = (l4_addr_t) l4re_kip(); printf("KIP at %lx.\n", kip_start); - /* Create a new task and thread. */ + /* Stack allocation. */ + + l4_addr_t stack_buf; + offset_t stack_size = 16 * L4_PAGESIZE; + l4_addr_t stack_region_base = 0x8000000 - stack_size; + l4re_ds_t stack_ds; + + err = ipc_allocate_align(stack_size, L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW, + L4_PAGESHIFT, (void **) &stack_buf, &stack_ds); + + if (err) + { + printf("Could not reserve stack.\n"); + return 1; + } + + /* Populate stack with additional capabilities. */ + + l4re_env_cap_entry_t *stack_env_cap = (l4re_env_cap_entry_t *) (stack_buf + stack_size); + + /* Special invalid/terminating environment capability entry. */ + + *(--stack_env_cap) = l4re_env_cap_entry_t(); + + printf("Stack region end: %p\n", stack_env_cap); + + l4_addr_t caps_start = (l4_addr_t) stack_env_cap; + l4_umword_t *stack_element = (l4_umword_t *) stack_env_cap; + + /* Loader flags, debugging flags, and the KIP capability index. + See: generate_l4aux in Remote_app_model */ + + *(--stack_element) = 0; + *(--stack_element) = 0; + *(--stack_element) = 0x14 << L4_CAP_SHIFT; + + printf("Stack L4 aux elements: %p / %lx\n", stack_element, ((l4_addr_t) stack_element - stack_buf) + stack_region_base); + + /* Populate stack with standard capabilities. */ + + l4re_env_t *env = (l4re_env_t *) stack_element; + + env--; + env->factory = L4_BASE_FACTORY_CAP; + env->main_thread = L4_BASE_THREAD_CAP; + env->log = L4_BASE_LOG_CAP; + env->scheduler = L4_BASE_SCHEDULER_CAP; + env->rm = 0x11 << L4_CAP_SHIFT; + env->mem_alloc = 0x12 << L4_CAP_SHIFT; + env->first_free_cap = 0x15; + env->caps = (l4re_env_cap_entry_t *) (caps_start - stack_buf) + stack_region_base; + env->utcb_area = utcb_fpage; + env->first_free_utcb = utcb_start + L4_UTCB_OFFSET; + + /* Populate stack with AUXV and environment pointer. */ + + stack_element = (l4_umword_t *) env; + + printf("Stack L4 env elements: %p / %lx\n", stack_element, ((l4_addr_t) stack_element - stack_buf) + stack_region_base); - l4_fpage_t utcb_fpage = l4_fpage(utcb_start, utcb_log2size, 0); + /* AUXV NULL. */ + + *(--stack_element) = 0; + *(--stack_element) = 0; + + /* L4Re global environment pointer. */ + + *(--stack_element) = ((l4_addr_t) env - stack_buf) + stack_region_base; + *(--stack_element) = 0xf1; + + /* Apparently required entries. */ + + *(--stack_element) = L4_PAGESIZE; + *(--stack_element) = AT_PAGESZ; + + *(--stack_element) = 0; + *(--stack_element) = AT_UID; + + *(--stack_element) = 0; + *(--stack_element) = AT_EUID; + + *(--stack_element) = 0; + *(--stack_element) = AT_GID; + + *(--stack_element) = 0; + *(--stack_element) = AT_EGID; + + char *stack_envp = (char *) stack_element; + + printf("Stack L4 envp: %p / %lx\n", stack_element, ((l4_addr_t) stack_element - stack_buf) + stack_region_base); + + /* Populate stack with argument values. */ + + char *stack_arg = stack_envp; + + stack_arg = (char *) trunc((offset_t) stack_arg - strlen(argv[1]) - 1, sizeof(l4_umword_t)); + + memset(stack_arg, 0, stack_envp - stack_arg); + memcpy(stack_arg, argv[1], strlen(argv[1])); + + printf("Stack L4 program argument: %p / %lx\n", stack_arg, ((l4_addr_t) stack_arg - stack_buf) + stack_region_base); + + /* Populate stack with the environment pointer. */ + + stack_element = (l4_umword_t *) stack_arg; + + *(--stack_element) = (l4_umword_t) ((l4_addr_t) stack_envp - stack_buf) + stack_region_base; + + /* Populate stack with argument pointers and count. */ + /* NOTE: Just one argument currently. */ + + *(--stack_element) = (l4_umword_t) ((l4_addr_t) stack_arg - stack_buf) + stack_region_base; + *(--stack_element) = 1; + + printf("Stack L4 start: %p / %lx\n", stack_element, ((l4_addr_t) stack_element - stack_buf) + stack_region_base); + printf("%ld %lx %lx\n", stack_element[0], stack_element[1], stack_element[2]); + + l4_addr_t stack_start = ((l4_addr_t) stack_element - stack_buf) + stack_region_base; + + /* Create a new task and thread. */ err = l4_error(l4_factory_create_task(l4re_env()->factory, task, utcb_fpage)); @@ -270,7 +616,11 @@ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - init_pager(&config, (l4_addr_t) buf, page_order(file->size), 0x1000000); + init_pager(&config); + + exec_pager.add(Region((l4_addr_t) program_buf, page_order(program_region_size), L4_FPAGE_RX, 0x1000000)); + exec_pager.add(Region((l4_addr_t) data_buf, page_order(data_region_size), L4_FPAGE_RW, data_region_base)); + exec_pager.add(Region((l4_addr_t) stack_buf, page_order(stack_size), L4_FPAGE_RW, stack_region_base)); err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &config); @@ -288,15 +638,25 @@ return 1; } - /* Map the pager capability into the region manager/mapper slot. */ + /* Define capability mappings for the new task. */ - err = l4_error(l4_task_map(task, L4RE_THIS_TASK_CAP, - l4_obj_fpage(config.server, 0, L4_CAP_FPAGE_RWS), - l4_map_obj_control(0x10 << L4_CAP_SHIFT, L4_MAP_ITEM_MAP))); + struct mapped_cap mapped_caps[] = { + {config.server, L4_CAP_FPAGE_RWS, 0x10 << L4_CAP_SHIFT}, + {config.server, L4_CAP_FPAGE_RWS, 0x11 << L4_CAP_SHIFT}, + {task, L4_CAP_FPAGE_RWS, L4_BASE_TASK_CAP}, + {thread, L4_CAP_FPAGE_RWS, L4_BASE_THREAD_CAP}, + {l4re_env()->factory, L4_CAP_FPAGE_RWS, L4_BASE_FACTORY_CAP}, + {l4re_env()->log, L4_CAP_FPAGE_RWS, L4_BASE_LOG_CAP}, + {l4re_env()->scheduler, L4_CAP_FPAGE_RWS, L4_BASE_SCHEDULER_CAP}, + {l4re_env()->mem_alloc, L4_CAP_FPAGE_RWS, 0x12 << L4_CAP_SHIFT}, + {L4_INVALID_CAP, 0, 0}, + }; + + err = map_capabilities(task, mapped_caps); if (err) { - printf("Could not map pager capability into task.\n"); + printf("Could not capabilities into task.\n"); return 1; } @@ -312,25 +672,6 @@ return 1; } - /* Define capability mappings for the new task. */ - - struct mapped_cap mapped_caps[] = { - {task, L4_CAP_FPAGE_RWS, L4_BASE_TASK_CAP}, - {thread, L4_CAP_FPAGE_RWS, L4_BASE_THREAD_CAP}, - {l4re_env()->factory, L4_CAP_FPAGE_RWS, L4_BASE_FACTORY_CAP}, - {l4re_env()->log, L4_CAP_FPAGE_RWS, L4_BASE_LOG_CAP}, - {l4re_env()->scheduler, L4_CAP_FPAGE_RWS, L4_BASE_SCHEDULER_CAP}, - {L4_INVALID_CAP, 0, 0}, - }; - - err = map_capabilities(task, mapped_caps); - - if (err) - { - printf("Could not capabilities into task.\n"); - return 1; - } - /* Configure the thread with the region manager acting as pager and exception handler. The UTCB will be situated at an address supported by a dataspace attached to the new task. */ @@ -349,25 +690,13 @@ return 1; } - /* Map the payload into the new task. */ - - printf("Map %p with size %ld (2 ** %d).\n", buf, file->size, page_order(file->size)); - - l4_fpage_t payload_fpage = l4_fpage((l4_addr_t) buf, page_order(file->size), L4_FPAGE_RX); - - err = l4_error(l4_task_map(task, L4RE_THIS_TASK_CAP, payload_fpage, 0x1000000)); - - if (err) - { - printf("Could not map payload into task.\n"); - return 1; - } - /* Start the new thread. */ printf("Schedule thread...\n"); - err = l4_error(l4_thread_ex_regs(thread, 0x1000ae3, 0x2000000 /* stack top */, 0)); + printf("Stack at 0x%lx mapped to region at 0x%lx.\n", stack_start, stack_region_base); + + err = l4_error(l4_thread_ex_regs(thread, 0x1000ae3, stack_start, 0)); if (err) {