L4Re/departure

Annotated tests/dstest_exec.cc

391:bc65615a8fed
2022-06-30 Paul Boddie Added missing structure members. mmap-region-flags
paul@308 1
/*
paul@308 2
 * Support for executing code in new tasks and threads.
paul@308 3
 *
paul@308 4
 * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
paul@308 5
 *
paul@308 6
 * This program is free software; you can redistribute it and/or
paul@308 7
 * modify it under the terms of the GNU General Public License as
paul@308 8
 * published by the Free Software Foundation; either version 2 of
paul@308 9
 * the License, or (at your option) any later version.
paul@308 10
 *
paul@308 11
 * This program is distributed in the hope that it will be useful,
paul@308 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@308 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@308 14
 * GNU General Public License for more details.
paul@308 15
 *
paul@308 16
 * You should have received a copy of the GNU General Public License
paul@308 17
 * along with this program; if not, write to the Free Software
paul@308 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@308 19
 * Boston, MA  02110-1301, USA
paul@308 20
 */
paul@308 21
paul@308 22
#include <l4/re/env.h>
paul@308 23
#include <l4/sys/err.h>
paul@312 24
#include <l4/util/util.h>
paul@308 25
paul@327 26
#include <exec/elf.h>
paul@370 27
#include <exec/external_pager.h>
paul@349 28
#include <exec/memory.h>
paul@324 29
#include <exec/process.h>
paul@370 30
#include <ipc/cap_alloc.h>
paul@370 31
#include <ipc/map.h>
paul@308 32
#include <ipc/server.h>
paul@312 33
paul@308 34
#include <stdio.h>
paul@308 35
paul@308 36
#include <pthread-l4.h>
paul@308 37
#include <pthread.h>
paul@308 38
paul@312 39
#include "pager_object_server.h"
paul@308 40
paul@308 41
paul@308 42
paul@376 43
/* External system-level pager for the region mapper in a created task. */
paul@376 44
paul@366 45
static ExternalPager exec_pager;
paul@308 46
paul@369 47
static const offset_t initial_stack_size = 16 * L4_PAGESIZE;
paul@369 48
paul@369 49
paul@369 50
paul@369 51
/* Start the system pager in a separate thread. */
paul@369 52
paul@369 53
static long start_pager(ipc_server_config_type &config)
paul@369 54
{
paul@369 55
  pthread_t pager_thread;
paul@369 56
  pthread_attr_t attr;
paul@369 57
paul@369 58
  pthread_attr_init(&attr);
paul@369 59
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
paul@369 60
paul@369 61
  ipc_server_init_for(&config, PagerObject, &exec_pager);
paul@369 62
paul@369 63
  long err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &config);
paul@369 64
paul@369 65
  if (err)
paul@369 66
    return err;
paul@369 67
paul@369 68
  return ipc_server_start_config_thread(&config, pthread_l4_cap(pager_thread));
paul@369 69
}
paul@369 70
paul@308 71
paul@308 72
paul@308 73
int main(int argc, char *argv[])
paul@308 74
{
paul@308 75
  long err;
paul@308 76
paul@370 77
  if (argc < 3)
paul@308 78
  {
paul@370 79
    printf("Need a program to run as the region mapper and a main program.\n");
paul@370 80
    return 1;
paul@370 81
  }
paul@370 82
paul@370 83
  /* Define the different payloads. */
paul@370 84
paul@370 85
  char *rm_filename = argv[1];
paul@370 86
  char *program_filename = argv[2];
paul@370 87
paul@370 88
  /* Initialise the memory segments of the region mapper. These are mapped into
paul@370 89
     this task so that we may access them. */
paul@370 90
paul@370 91
  ExplicitSegment rm_stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW);
paul@370 92
  Payload *rm_payload;
paul@370 93
paul@370 94
  if (exec_get_payload(rm_filename, &rm_payload, true))
paul@370 95
  {
paul@370 96
    printf("Could not initialise region mapper: %s\n", rm_filename);
paul@370 97
    return 1;
paul@370 98
  }
paul@370 99
paul@370 100
  if (rm_stack.allocate(true))
paul@370 101
  {
paul@370 102
    printf("Could not allocate region mapper stack.\n");
paul@308 103
    return 1;
paul@308 104
  }
paul@308 105
paul@370 106
  /* Initialise the memory segments of the actual program. These are not mapped
paul@370 107
     into this task, instead being accessed by the region mapper in the new
paul@370 108
     task. */
paul@323 109
paul@370 110
  ExplicitSegment program_stack(Utcb_area_start - initial_stack_size * 2, initial_stack_size, L4_FPAGE_RW);
paul@370 111
  Payload *program_payload;
paul@323 112
paul@370 113
  if (exec_get_payload(program_filename, &program_payload, false))
paul@323 114
  {
paul@370 115
    printf("Could not initialise program: %s\n", program_filename);
paul@325 116
    return 1;
paul@325 117
  }
paul@325 118
paul@370 119
  if (program_stack.allocate(true))
paul@316 120
  {
paul@370 121
    printf("Could not allocate program stack.\n");
paul@349 122
    return 1;
paul@308 123
  }
paul@308 124
paul@370 125
  /* Initialise pager regions for the region mapper. */
paul@312 126
paul@370 127
  for (unsigned int i = 0; i < rm_payload->segments(); i++)
paul@325 128
  {
paul@370 129
    if (rm_payload->segment(i)->loadable())
paul@370 130
      exec_pager.add(rm_payload->segment(i)->region());
paul@349 131
  }
paul@325 132
paul@370 133
  exec_pager.add(rm_stack.region());
paul@308 134
paul@369 135
  /* Start the pager in a separate thread. */
paul@354 136
paul@354 137
  ipc_server_config_type config;
paul@308 138
paul@354 139
  printf("Starting pager thread...\n");
paul@369 140
paul@369 141
  err = start_pager(config);
paul@308 142
paul@308 143
  if (err)
paul@308 144
  {
paul@308 145
    printf("Could not start pager.\n");
paul@308 146
    return 1;
paul@308 147
  }
paul@308 148
paul@370 149
  /* Configure the environment for the task, reserving two threads. */
paul@308 150
paul@370 151
  Process process(2);
paul@321 152
paul@365 153
  err = process.configure_task();
paul@308 154
paul@308 155
  if (err)
paul@308 156
  {
paul@321 157
    printf("Could not configure task.\n");
paul@308 158
    return 1;
paul@308 159
  }
paul@308 160
paul@370 161
  /* Configure the environment for the thread, specifying the pager (and
paul@370 162
     exception handler plus region mapper). */
paul@370 163
paul@365 164
  err = process.configure_thread(config.server);
paul@365 165
paul@365 166
  if (err)
paul@365 167
  {
paul@365 168
    printf("Could not configure thread.\n");
paul@365 169
    return 1;
paul@365 170
  }
paul@365 171
paul@370 172
  /* Create an unbound IPC gate for the region mapper. */
paul@370 173
paul@370 174
  l4_cap_idx_t ipc_gate = ipc_cap_alloc();
paul@370 175
paul@370 176
  if (l4_is_invalid_cap(ipc_gate))
paul@370 177
  {
paul@370 178
    printf("Could not allocate IPC gate capability.\n");
paul@370 179
    return 1;
paul@370 180
  }
paul@370 181
paul@370 182
  err = l4_error(l4_factory_create_gate(l4re_env()->factory, ipc_gate, L4_INVALID_CAP, 0));
paul@370 183
paul@370 184
  if (err)
paul@370 185
  {
paul@370 186
    printf("Could not create IPC gate.\n");
paul@370 187
    return 1;
paul@370 188
  }
paul@370 189
paul@370 190
  /* Define regions employing dataspaces to provide program segments.
paul@370 191
paul@370 192
     Define capabilities for mapping, including region dataspace capabilities,
paul@370 193
     the stack dataspace capability, and the server capability.
paul@370 194
paul@370 195
     Here, the arrays are sized for the maximum number of regions and
paul@370 196
     capabilities, but in practice only the loadable segments are used, leaving
paul@370 197
     fewer elements utilised. A terminating entry is employed to indicate the
paul@370 198
     limit of utilised elements. */
paul@370 199
paul@370 200
  struct exec_region rm_regions[rm_payload->segments() + 2];
paul@370 201
  struct ipc_mapped_cap rm_mapped_caps[rm_payload->segments() + 3];
paul@376 202
  l4_cap_idx_t mapped_cap;
paul@370 203
  unsigned int rm_index = 0;
paul@370 204
paul@376 205
  for (unsigned int i = 0; i < program_payload->segments(); i++)
paul@370 206
  {
paul@376 207
    Segment *s = program_payload->segment(i);
paul@321 208
paul@370 209
    if (s->loadable())
paul@370 210
    {
paul@376 211
      mapped_cap = process.allocate_cap();
paul@370 212
      rm_regions[rm_index] = s->exec_region();
paul@376 213
      rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {mapped_cap, rm_regions[rm_index].ds, L4_CAP_FPAGE_RWS, 0};
paul@376 214
      rm_regions[rm_index].ds = mapped_cap;
paul@370 215
      rm_index++;
paul@370 216
    }
paul@370 217
  }
paul@370 218
paul@370 219
  /* Introduce the stack region and capability. */
paul@370 220
paul@376 221
  mapped_cap = process.allocate_cap();
paul@370 222
  rm_regions[rm_index] = program_stack.exec_region();
paul@376 223
  rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {mapped_cap, program_stack.exec_region().ds, L4_CAP_FPAGE_RWS, 0};
paul@376 224
  rm_regions[rm_index].ds = mapped_cap;
paul@370 225
  rm_index++;
paul@370 226
paul@370 227
  /* Terminate the region array. */
paul@370 228
paul@370 229
  rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP};
paul@370 230
paul@370 231
  /* Introduce the server capability. */
paul@370 232
paul@370 233
  l4_cap_idx_t ipc_gate_cap = process.allocate_cap();
paul@370 234
paul@376 235
  printf("Mapping %lx to %lx in task.\n", ipc_gate, ipc_gate_cap);
paul@376 236
paul@376 237
  rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {ipc_gate_cap, ipc_gate, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS};
paul@370 238
  rm_index++;
paul@370 239
paul@370 240
  /* Terminate the capability array. */
paul@370 241
paul@376 242
  rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0, 0};
paul@370 243
paul@370 244
  /* Map these additional capabilities. */
paul@370 245
paul@370 246
  printf("Map additional capabilities...\n");
paul@370 247
paul@376 248
  process.map_capabilities(rm_mapped_caps, false);
paul@370 249
paul@370 250
  /* Define the IPC gate as an initial capability to be acquired by the region
paul@370 251
     mapper via the l4re_env API. The capability index is assigned above when
paul@370 252
     mapping the capability and encoded in the entry below. */
paul@370 253
paul@370 254
  l4re_env_cap_entry_t rm_init_caps[] = {
paul@370 255
    l4re_env_cap_entry_t("server", ipc_gate_cap, L4_CAP_FPAGE_RWS),
paul@370 256
    l4re_env_cap_entry_t()
paul@370 257
    };
paul@321 258
paul@321 259
  /* NOTE: Environment vector is currently not defined. */
paul@321 260
paul@321 261
  char *envp[] = {NULL};
paul@321 262
paul@370 263
  /* Populate a thread stack with argument and environment details for the
paul@370 264
     region mapper, plus the initial server capability and region details. */
paul@321 265
paul@370 266
  printf("Populating region mapper stack...\n");
paul@370 267
paul@370 268
  Stack rm_st(rm_stack);
paul@308 269
paul@370 270
  rm_st.set_init_caps(rm_init_caps);
paul@370 271
  rm_st.set_regions(rm_regions);
paul@370 272
  rm_st.populate(1, argv + 1, envp);
paul@308 273
paul@370 274
  /* Start the region mapper thread in the appropriate stack. */
paul@370 275
paul@370 276
  printf("Run region mapper thread...\n");
paul@370 277
paul@370 278
  err = process.thread_start(rm_payload->entry_point(), rm_st);
paul@308 279
paul@308 280
  if (err)
paul@308 281
  {
paul@370 282
    printf("Could not run thread for region mapper.\n");
paul@370 283
    return 1;
paul@370 284
  }
paul@370 285
paul@370 286
  /* Configure the environment for the thread, specifying the pager (and
paul@370 287
     exception handler plus region mapper). */
paul@370 288
paul@376 289
  err = process.configure_thread(ipc_gate, ipc_gate_cap);
paul@370 290
paul@370 291
  if (err)
paul@370 292
  {
paul@370 293
    printf("Could not configure task.\n");
paul@370 294
    return 1;
paul@370 295
  }
paul@370 296
paul@370 297
  /* Populate a thread stack with argument and environment details for the
paul@370 298
     actual program. The server capability should be assigned to the region
paul@370 299
     mapper capability slot already. */
paul@370 300
paul@370 301
  printf("Populating program stack...\n");
paul@370 302
paul@370 303
  Stack program_st(program_stack);
paul@370 304
paul@370 305
  program_st.populate(argc - 2, argv + 2, envp);
paul@370 306
paul@370 307
  /* Start the program thread in the appropriate stack. */
paul@370 308
paul@370 309
  printf("Run program thread...\n");
paul@370 310
paul@370 311
  err = process.thread_start(program_payload->entry_point(), program_st);
paul@370 312
paul@370 313
  if (err)
paul@370 314
  {
paul@370 315
    printf("Could not run thread for program.\n");
paul@308 316
    return 1;
paul@308 317
  }
paul@308 318
paul@308 319
  printf("Finished.\n");
paul@376 320
paul@369 321
  while (1)
paul@369 322
    l4_sleep_forever();
paul@308 323
paul@308 324
  return 0;
paul@308 325
}
paul@308 326
paul@308 327
/* vim: tabstop=2 expandtab shiftwidth=2
paul@308 328
*/