# HG changeset patch # User Paul Boddie # Date 1655134344 -7200 # Node ID 65230d933d16b59b210834dd91823819531ddd1d # Parent 571ff28dabfb88e8080d998f63633b375e93225c Fixed capability index allocation, introducing control over such allocation in the process abstraction, also allocating separate indexes for the region mapper in different threads. A separate pager capability has been eliminated. Fixed process initialisation, separating the preparation of each thread, since the process abstraction maintains a common environment structure, and only one thread should therefore be initialised at a time. diff -r 571ff28dabfb -r 65230d933d16 conf/dstest_exec.cfg --- a/conf/dstest_exec.cfg Mon Jun 13 00:58:21 2022 +0200 +++ b/conf/dstest_exec.cfg Mon Jun 13 17:32:24 2022 +0200 @@ -47,4 +47,4 @@ }, log = { "client", "g" }, }, - "rom/dstest_exec", "home/paulb/dstest_exec_payload", "hello", "world"); + "rom/dstest_exec", "home/paulb/dstest_region_mapper", "home/paulb/dstest_exec_payload", "hello", "world"); diff -r 571ff28dabfb -r 65230d933d16 libexec/include/exec/process.h --- a/libexec/include/exec/process.h Mon Jun 13 00:58:21 2022 +0200 +++ b/libexec/include/exec/process.h Mon Jun 13 17:32:24 2022 +0200 @@ -77,15 +77,11 @@ l4_addr_t _utcb_start; - /* Common environment details. */ + /* Common and thread environment details. */ l4re_aux_t _aux; l4re_env_t _env; - /* Mapped capability details. */ - - unsigned int _num_mapped_caps = 0; - /* Task and thread initialisation. */ long create_task(); @@ -95,6 +91,8 @@ public: explicit Process(int reserved_threads = 1); + l4_cap_idx_t allocate_cap(); + long configure_task(); long configure_thread(l4_cap_idx_t server); diff -r 571ff28dabfb -r 65230d933d16 libexec/lib/src/process.cc --- a/libexec/lib/src/process.cc Mon Jun 13 00:58:21 2022 +0200 +++ b/libexec/lib/src/process.cc Mon Jun 13 17:32:24 2022 +0200 @@ -61,15 +61,18 @@ /* Populate the common initial environment for the threads. */ _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 = L4_EXEC_RM_CAP; _env.mem_alloc = L4_EXEC_MA_CAP; - _env.first_free_cap = L4_EXEC_FIRST_FREE_CAP_INDEX; _env.utcb_area = utcb_fpage; _env.first_free_utcb = l4_fpage_memaddr(utcb_fpage) + reserved_threads * L4_UTCB_OFFSET; + /* Capability details that are updated for each thread. */ + + _env.main_thread = L4_BASE_THREAD_CAP; + _env.rm = L4_EXEC_RM_CAP; + _env.first_free_cap = L4_EXEC_FIRST_FREE_CAP_INDEX; + /* Populate auxiliary information. */ _aux.kip_ds = L4_EXEC_KIP_CAP; @@ -77,6 +80,13 @@ _aux.ldr_flags = 0; } +/* Capability index allocation. */ + +l4_cap_idx_t Process::allocate_cap() +{ + return (_env.first_free_cap++ << L4_CAP_SHIFT); +} + /* Task and thread initialisation. */ long Process::create_task() @@ -137,8 +147,12 @@ long Process::configure_thread(l4_cap_idx_t server) { + /* Employ a distinct region mapper for each thread's environment, this acting + as pager. */ + + _env.rm = allocate_cap(); + struct ipc_mapped_cap mapped_caps[] = { - {L4_EXEC_PAGER_CAP, server, L4_CAP_FPAGE_RWS}, {_env.rm, server, L4_CAP_FPAGE_RWS}, {0, L4_INVALID_CAP, 0}, }; @@ -151,7 +165,13 @@ long Process::map_capabilities(struct ipc_mapped_cap mapped_caps[], bool to_count) { - return ipc_map_capabilities(_task, mapped_caps, to_count ? &_num_mapped_caps : NULL); + unsigned int num_mapped_caps; + long err = ipc_map_capabilities(_task, mapped_caps, to_count ? &num_mapped_caps : NULL); + + if (to_count) + _env.first_free_cap += num_mapped_caps; + + return err; } /* Create, initialise and start a thread. */ @@ -169,8 +189,8 @@ /* Initialise the thread with pager, UTCB and task details. */ l4_thread_control_start(); - l4_thread_control_pager(L4_EXEC_PAGER_CAP); - l4_thread_control_exc_handler(L4_EXEC_PAGER_CAP); + l4_thread_control_pager(_env.rm); + l4_thread_control_exc_handler(_env.rm); l4_thread_control_bind((l4_utcb_t *) _utcb_start, _task); err = l4_error(l4_thread_control_commit(thread)); @@ -181,14 +201,12 @@ return err; } - /* Map the thread capability to the task. */ + /* Map the thread capability to the task using a distinct capability index. */ + + _env.main_thread = allocate_cap(); ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.main_thread, thread, L4_CAP_FPAGE_RWS}); - /* Update the environment for any mapped capabilities. */ - - _env.first_free_cap = L4_EXEC_FIRST_FREE_CAP_INDEX + _num_mapped_caps; - /* Populate the initial environment in the thread. */ st.set_l4re_aux(&_aux); diff -r 571ff28dabfb -r 65230d933d16 libipc/lib/src/map.c --- a/libipc/lib/src/map.c Mon Jun 13 00:58:21 2022 +0200 +++ b/libipc/lib/src/map.c Mon Jun 13 17:32:24 2022 +0200 @@ -49,7 +49,7 @@ err = ipc_map_capability(task, mapped_caps[i]); if (count != NULL) - *count = i + 1; + *count = i; return err; } diff -r 571ff28dabfb -r 65230d933d16 tests/dstest_exec.cc --- a/tests/dstest_exec.cc Mon Jun 13 00:58:21 2022 +0200 +++ b/tests/dstest_exec.cc Mon Jun 13 17:32:24 2022 +0200 @@ -24,9 +24,11 @@ #include #include +#include #include -#include #include +#include +#include #include #include @@ -70,38 +72,63 @@ { long err; - if (argc < 2) + if (argc < 3) { - printf("Need a program to run.\n"); + printf("Need a program to run as the region mapper and a main program.\n"); + return 1; + } + + /* Define the different payloads. */ + + char *rm_filename = argv[1]; + char *program_filename = argv[2]; + + /* Initialise the memory segments of the region mapper. These are mapped into + this task so that we may access them. */ + + ExplicitSegment rm_stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW); + Payload *rm_payload; + + if (exec_get_payload(rm_filename, &rm_payload, true)) + { + printf("Could not initialise region mapper: %s\n", rm_filename); + return 1; + } + + if (rm_stack.allocate(true)) + { + printf("Could not allocate region mapper stack.\n"); return 1; } - /* Initialise the memory of the new task. */ + /* Initialise the memory segments of the actual program. These are not mapped + into this task, instead being accessed by the region mapper in the new + task. */ - ExplicitSegment stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW); - Payload *payload; + ExplicitSegment program_stack(Utcb_area_start - initial_stack_size * 2, initial_stack_size, L4_FPAGE_RW); + Payload *program_payload; - if (exec_get_payload(argv[1], &payload, true)) + if (exec_get_payload(program_filename, &program_payload, false)) { - printf("Could not initialise program.\n"); + printf("Could not initialise program: %s\n", program_filename); return 1; } - if (stack.allocate(true)) + if (program_stack.allocate(true)) { - printf("Could not allocate stack.\n"); + printf("Could not allocate program stack.\n"); return 1; } - /* Initialise pager regions. */ + /* Initialise pager regions for the region mapper. */ - for (unsigned int i = 0; i < payload->segments(); i++) + for (unsigned int i = 0; i < rm_payload->segments(); i++) { - if (payload->segment(i)->loadable()) - exec_pager.add(payload->segment(i)->region()); + if (rm_payload->segment(i)->loadable()) + exec_pager.add(rm_payload->segment(i)->region()); } - exec_pager.add(stack.region()); + exec_pager.add(rm_stack.region()); /* Start the pager in a separate thread. */ @@ -117,10 +144,9 @@ return 1; } - /* Configure the environment for the task, specifying the pager (and exception - handler plus region mapper). */ + /* Configure the environment for the task, reserving two threads. */ - Process process; + Process process(2); err = process.configure_task(); @@ -130,6 +156,9 @@ return 1; } + /* Configure the environment for the thread, specifying the pager (and + exception handler plus region mapper). */ + err = process.configure_thread(config.server); if (err) @@ -138,25 +167,143 @@ return 1; } - /* Populate a thread stack with argument and environment details. */ + /* Create an unbound IPC gate for the region mapper. */ + + l4_cap_idx_t ipc_gate = ipc_cap_alloc(); + + if (l4_is_invalid_cap(ipc_gate)) + { + printf("Could not allocate IPC gate capability.\n"); + return 1; + } + + err = l4_error(l4_factory_create_gate(l4re_env()->factory, ipc_gate, L4_INVALID_CAP, 0)); + + if (err) + { + printf("Could not create IPC gate.\n"); + return 1; + } + + /* Define regions employing dataspaces to provide program segments. + + Define capabilities for mapping, including region dataspace capabilities, + the stack dataspace capability, and the server capability. + + Here, the arrays are sized for the maximum number of regions and + capabilities, but in practice only the loadable segments are used, leaving + fewer elements utilised. A terminating entry is employed to indicate the + limit of utilised elements. */ + + struct exec_region rm_regions[rm_payload->segments() + 2]; + struct ipc_mapped_cap rm_mapped_caps[rm_payload->segments() + 3]; + unsigned int rm_index = 0; + + for (unsigned int i = 0; i < rm_payload->segments(); i++) + { + Segment *s = rm_payload->segment(i); - Stack program_st(stack); + if (s->loadable()) + { + rm_regions[rm_index] = s->exec_region(); + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {process.allocate_cap(), rm_regions[rm_index].ds, L4_CAP_FPAGE_RWS}; + rm_index++; + } + } + + /* Introduce the stack region and capability. */ + + rm_regions[rm_index] = program_stack.exec_region(); + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {process.allocate_cap(), program_stack.exec_region().ds, L4_CAP_FPAGE_RWS}; + rm_index++; + + /* Terminate the region array. */ + + rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP}; + + /* Introduce the server capability. */ + + l4_cap_idx_t ipc_gate_cap = process.allocate_cap(); + + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {ipc_gate_cap, ipc_gate, L4_CAP_FPAGE_RWS}; + rm_index++; + + /* Terminate the capability array. */ + + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0}; + + /* Map these additional capabilities. */ + + printf("Map additional capabilities...\n"); + + process.map_capabilities(rm_mapped_caps); + + /* Define the IPC gate as an initial capability to be acquired by the region + mapper via the l4re_env API. The capability index is assigned above when + mapping the capability and encoded in the entry below. */ + + l4re_env_cap_entry_t rm_init_caps[] = { + l4re_env_cap_entry_t("server", ipc_gate_cap, L4_CAP_FPAGE_RWS), + l4re_env_cap_entry_t() + }; /* NOTE: Environment vector is currently not defined. */ char *envp[] = {NULL}; - program_st.populate(argc - 1, argv + 1, envp); + /* Populate a thread stack with argument and environment details for the + region mapper, plus the initial server capability and region details. */ - /* Start the new thread in the given stack. */ + printf("Populating region mapper stack...\n"); + + Stack rm_st(rm_stack); - printf("Run thread...\n"); + rm_st.set_init_caps(rm_init_caps); + rm_st.set_regions(rm_regions); + rm_st.populate(1, argv + 1, envp); - err = process.thread_start(payload->entry_point(), program_st); + /* Start the region mapper thread in the appropriate stack. */ + + printf("Run region mapper thread...\n"); + + err = process.thread_start(rm_payload->entry_point(), rm_st); if (err) { - printf("Could not run thread.\n"); + printf("Could not run thread for region mapper.\n"); + return 1; + } + + /* Configure the environment for the thread, specifying the pager (and + exception handler plus region mapper). */ + + err = process.configure_thread(ipc_gate); + + if (err) + { + printf("Could not configure task.\n"); + return 1; + } + + /* Populate a thread stack with argument and environment details for the + actual program. The server capability should be assigned to the region + mapper capability slot already. */ + + printf("Populating program stack...\n"); + + Stack program_st(program_stack); + + program_st.populate(argc - 2, argv + 2, envp); + + /* Start the program thread in the appropriate stack. */ + + printf("Run program thread...\n"); + + err = process.thread_start(program_payload->entry_point(), program_st); + + if (err) + { + printf("Could not run thread for program.\n"); return 1; }