1.1 --- a/tests/dstest_exec.cc Mon Jun 13 00:58:21 2022 +0200
1.2 +++ b/tests/dstest_exec.cc Mon Jun 13 17:32:24 2022 +0200
1.3 @@ -24,9 +24,11 @@
1.4 #include <l4/util/util.h>
1.5
1.6 #include <exec/elf.h>
1.7 +#include <exec/external_pager.h>
1.8 #include <exec/memory.h>
1.9 -#include <exec/external_pager.h>
1.10 #include <exec/process.h>
1.11 +#include <ipc/cap_alloc.h>
1.12 +#include <ipc/map.h>
1.13 #include <ipc/server.h>
1.14
1.15 #include <stdio.h>
1.16 @@ -70,38 +72,63 @@
1.17 {
1.18 long err;
1.19
1.20 - if (argc < 2)
1.21 + if (argc < 3)
1.22 {
1.23 - printf("Need a program to run.\n");
1.24 + printf("Need a program to run as the region mapper and a main program.\n");
1.25 + return 1;
1.26 + }
1.27 +
1.28 + /* Define the different payloads. */
1.29 +
1.30 + char *rm_filename = argv[1];
1.31 + char *program_filename = argv[2];
1.32 +
1.33 + /* Initialise the memory segments of the region mapper. These are mapped into
1.34 + this task so that we may access them. */
1.35 +
1.36 + ExplicitSegment rm_stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW);
1.37 + Payload *rm_payload;
1.38 +
1.39 + if (exec_get_payload(rm_filename, &rm_payload, true))
1.40 + {
1.41 + printf("Could not initialise region mapper: %s\n", rm_filename);
1.42 + return 1;
1.43 + }
1.44 +
1.45 + if (rm_stack.allocate(true))
1.46 + {
1.47 + printf("Could not allocate region mapper stack.\n");
1.48 return 1;
1.49 }
1.50
1.51 - /* Initialise the memory of the new task. */
1.52 + /* Initialise the memory segments of the actual program. These are not mapped
1.53 + into this task, instead being accessed by the region mapper in the new
1.54 + task. */
1.55
1.56 - ExplicitSegment stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW);
1.57 - Payload *payload;
1.58 + ExplicitSegment program_stack(Utcb_area_start - initial_stack_size * 2, initial_stack_size, L4_FPAGE_RW);
1.59 + Payload *program_payload;
1.60
1.61 - if (exec_get_payload(argv[1], &payload, true))
1.62 + if (exec_get_payload(program_filename, &program_payload, false))
1.63 {
1.64 - printf("Could not initialise program.\n");
1.65 + printf("Could not initialise program: %s\n", program_filename);
1.66 return 1;
1.67 }
1.68
1.69 - if (stack.allocate(true))
1.70 + if (program_stack.allocate(true))
1.71 {
1.72 - printf("Could not allocate stack.\n");
1.73 + printf("Could not allocate program stack.\n");
1.74 return 1;
1.75 }
1.76
1.77 - /* Initialise pager regions. */
1.78 + /* Initialise pager regions for the region mapper. */
1.79
1.80 - for (unsigned int i = 0; i < payload->segments(); i++)
1.81 + for (unsigned int i = 0; i < rm_payload->segments(); i++)
1.82 {
1.83 - if (payload->segment(i)->loadable())
1.84 - exec_pager.add(payload->segment(i)->region());
1.85 + if (rm_payload->segment(i)->loadable())
1.86 + exec_pager.add(rm_payload->segment(i)->region());
1.87 }
1.88
1.89 - exec_pager.add(stack.region());
1.90 + exec_pager.add(rm_stack.region());
1.91
1.92 /* Start the pager in a separate thread. */
1.93
1.94 @@ -117,10 +144,9 @@
1.95 return 1;
1.96 }
1.97
1.98 - /* Configure the environment for the task, specifying the pager (and exception
1.99 - handler plus region mapper). */
1.100 + /* Configure the environment for the task, reserving two threads. */
1.101
1.102 - Process process;
1.103 + Process process(2);
1.104
1.105 err = process.configure_task();
1.106
1.107 @@ -130,6 +156,9 @@
1.108 return 1;
1.109 }
1.110
1.111 + /* Configure the environment for the thread, specifying the pager (and
1.112 + exception handler plus region mapper). */
1.113 +
1.114 err = process.configure_thread(config.server);
1.115
1.116 if (err)
1.117 @@ -138,25 +167,143 @@
1.118 return 1;
1.119 }
1.120
1.121 - /* Populate a thread stack with argument and environment details. */
1.122 + /* Create an unbound IPC gate for the region mapper. */
1.123 +
1.124 + l4_cap_idx_t ipc_gate = ipc_cap_alloc();
1.125 +
1.126 + if (l4_is_invalid_cap(ipc_gate))
1.127 + {
1.128 + printf("Could not allocate IPC gate capability.\n");
1.129 + return 1;
1.130 + }
1.131 +
1.132 + err = l4_error(l4_factory_create_gate(l4re_env()->factory, ipc_gate, L4_INVALID_CAP, 0));
1.133 +
1.134 + if (err)
1.135 + {
1.136 + printf("Could not create IPC gate.\n");
1.137 + return 1;
1.138 + }
1.139 +
1.140 + /* Define regions employing dataspaces to provide program segments.
1.141 +
1.142 + Define capabilities for mapping, including region dataspace capabilities,
1.143 + the stack dataspace capability, and the server capability.
1.144 +
1.145 + Here, the arrays are sized for the maximum number of regions and
1.146 + capabilities, but in practice only the loadable segments are used, leaving
1.147 + fewer elements utilised. A terminating entry is employed to indicate the
1.148 + limit of utilised elements. */
1.149 +
1.150 + struct exec_region rm_regions[rm_payload->segments() + 2];
1.151 + struct ipc_mapped_cap rm_mapped_caps[rm_payload->segments() + 3];
1.152 + unsigned int rm_index = 0;
1.153 +
1.154 + for (unsigned int i = 0; i < rm_payload->segments(); i++)
1.155 + {
1.156 + Segment *s = rm_payload->segment(i);
1.157
1.158 - Stack program_st(stack);
1.159 + if (s->loadable())
1.160 + {
1.161 + rm_regions[rm_index] = s->exec_region();
1.162 + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {process.allocate_cap(), rm_regions[rm_index].ds, L4_CAP_FPAGE_RWS};
1.163 + rm_index++;
1.164 + }
1.165 + }
1.166 +
1.167 + /* Introduce the stack region and capability. */
1.168 +
1.169 + rm_regions[rm_index] = program_stack.exec_region();
1.170 + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {process.allocate_cap(), program_stack.exec_region().ds, L4_CAP_FPAGE_RWS};
1.171 + rm_index++;
1.172 +
1.173 + /* Terminate the region array. */
1.174 +
1.175 + rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP};
1.176 +
1.177 + /* Introduce the server capability. */
1.178 +
1.179 + l4_cap_idx_t ipc_gate_cap = process.allocate_cap();
1.180 +
1.181 + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {ipc_gate_cap, ipc_gate, L4_CAP_FPAGE_RWS};
1.182 + rm_index++;
1.183 +
1.184 + /* Terminate the capability array. */
1.185 +
1.186 + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0};
1.187 +
1.188 + /* Map these additional capabilities. */
1.189 +
1.190 + printf("Map additional capabilities...\n");
1.191 +
1.192 + process.map_capabilities(rm_mapped_caps);
1.193 +
1.194 + /* Define the IPC gate as an initial capability to be acquired by the region
1.195 + mapper via the l4re_env API. The capability index is assigned above when
1.196 + mapping the capability and encoded in the entry below. */
1.197 +
1.198 + l4re_env_cap_entry_t rm_init_caps[] = {
1.199 + l4re_env_cap_entry_t("server", ipc_gate_cap, L4_CAP_FPAGE_RWS),
1.200 + l4re_env_cap_entry_t()
1.201 + };
1.202
1.203 /* NOTE: Environment vector is currently not defined. */
1.204
1.205 char *envp[] = {NULL};
1.206
1.207 - program_st.populate(argc - 1, argv + 1, envp);
1.208 + /* Populate a thread stack with argument and environment details for the
1.209 + region mapper, plus the initial server capability and region details. */
1.210
1.211 - /* Start the new thread in the given stack. */
1.212 + printf("Populating region mapper stack...\n");
1.213 +
1.214 + Stack rm_st(rm_stack);
1.215
1.216 - printf("Run thread...\n");
1.217 + rm_st.set_init_caps(rm_init_caps);
1.218 + rm_st.set_regions(rm_regions);
1.219 + rm_st.populate(1, argv + 1, envp);
1.220
1.221 - err = process.thread_start(payload->entry_point(), program_st);
1.222 + /* Start the region mapper thread in the appropriate stack. */
1.223 +
1.224 + printf("Run region mapper thread...\n");
1.225 +
1.226 + err = process.thread_start(rm_payload->entry_point(), rm_st);
1.227
1.228 if (err)
1.229 {
1.230 - printf("Could not run thread.\n");
1.231 + printf("Could not run thread for region mapper.\n");
1.232 + return 1;
1.233 + }
1.234 +
1.235 + /* Configure the environment for the thread, specifying the pager (and
1.236 + exception handler plus region mapper). */
1.237 +
1.238 + err = process.configure_thread(ipc_gate);
1.239 +
1.240 + if (err)
1.241 + {
1.242 + printf("Could not configure task.\n");
1.243 + return 1;
1.244 + }
1.245 +
1.246 + /* Populate a thread stack with argument and environment details for the
1.247 + actual program. The server capability should be assigned to the region
1.248 + mapper capability slot already. */
1.249 +
1.250 + printf("Populating program stack...\n");
1.251 +
1.252 + Stack program_st(program_stack);
1.253 +
1.254 + program_st.populate(argc - 2, argv + 2, envp);
1.255 +
1.256 + /* Start the program thread in the appropriate stack. */
1.257 +
1.258 + printf("Run program thread...\n");
1.259 +
1.260 + err = process.thread_start(program_payload->entry_point(), program_st);
1.261 +
1.262 + if (err)
1.263 + {
1.264 + printf("Could not run thread for program.\n");
1.265 return 1;
1.266 }
1.267