L4Re/departure

Annotated tests/dstest_exec.cc

318:a66c7ca81849
2022-05-03 Paul Boddie Introduced support for multiple program arguments.
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@308 24
#include <l4/sys/factory.h>
paul@308 25
#include <l4/sys/task.h>
paul@308 26
#include <l4/sys/thread.h>
paul@312 27
#include <l4/util/elf.h>
paul@312 28
#include <l4/util/util.h>
paul@308 29
paul@315 30
#include <l4/libloader/adjust_stack>
paul@315 31
paul@308 32
#include <fsclient/client.h>
paul@308 33
#include <ipc/cap_alloc.h>
paul@308 34
#include <ipc/mem_ipc.h>
paul@308 35
#include <ipc/server.h>
paul@311 36
#include <mem/memory_utils.h>
paul@308 37
#include <systypes/fcntl.h>
paul@308 38
paul@312 39
#include <map>
paul@312 40
paul@308 41
#include <stdio.h>
paul@308 42
#include <stdlib.h>
paul@308 43
#include <string.h>
paul@308 44
paul@308 45
#include <pthread-l4.h>
paul@308 46
#include <pthread.h>
paul@308 47
paul@312 48
#include "pager_object_interface.h"
paul@312 49
#include "pager_object_server.h"
paul@308 50
paul@308 51
paul@308 52
paul@312 53
/* Region data structures. */
paul@308 54
paul@312 55
class Region
paul@308 56
{
paul@308 57
public:
paul@312 58
  l4_addr_t start;
paul@312 59
  unsigned int log2size;
paul@312 60
  l4_umword_t flags;
paul@312 61
  l4_addr_t map_start;
paul@312 62
paul@312 63
  explicit Region()
paul@312 64
  : start(0), log2size(0), flags(0), map_start(0)
paul@312 65
  {
paul@312 66
  }
paul@312 67
paul@312 68
  explicit Region(l4_addr_t start, unsigned int log2size, l4_umword_t flags,
paul@312 69
                  l4_addr_t map_start)
paul@312 70
  : start(start), log2size(log2size), flags(flags), map_start(map_start)
paul@312 71
  {
paul@312 72
  }
paul@312 73
};
paul@312 74
paul@316 75
paul@316 76
paul@316 77
/* Program segment abstraction. */
paul@316 78
paul@316 79
class Segment
paul@316 80
{
paul@316 81
protected:
paul@316 82
  Region _region;
paul@316 83
paul@316 84
public:
paul@316 85
  /* Allocated memory. */
paul@316 86
paul@316 87
  char *buf;
paul@316 88
  l4re_ds_t ds;
paul@316 89
paul@316 90
  /* Segment base and corresponding region base. */
paul@316 91
paul@316 92
  l4_addr_t base, region_base;
paul@316 93
paul@316 94
  /* Segment size and corresponding region size. */
paul@316 95
paul@316 96
  offset_t size, region_size;
paul@316 97
paul@316 98
  /* Offset of segment content within the region. */
paul@316 99
paul@316 100
  offset_t region_offset;
paul@316 101
paul@316 102
  /* Access flags. */
paul@316 103
paul@316 104
  l4re_rm_flags_t flags;
paul@316 105
paul@316 106
  /* File access details. */
paul@316 107
paul@316 108
  offset_t file_offset, file_contents;
paul@316 109
paul@316 110
  explicit Segment(offset_t base, offset_t size, l4re_rm_flags_t flags,
paul@316 111
                   offset_t file_offset = 0, offset_t file_contents = 0)
paul@316 112
  : base(base), size(size), flags(flags), file_offset(file_offset), file_contents(file_contents)
paul@316 113
  {
paul@316 114
    region_base = trunc(base, L4_PAGESIZE);
paul@316 115
    region_offset = base - region_base;
paul@316 116
    region_size = round(size, L4_PAGESIZE);
paul@316 117
  }
paul@316 118
paul@316 119
  long allocate();
paul@316 120
paul@316 121
  long fill(file_t *file);
paul@316 122
paul@316 123
  Region &region();
paul@316 124
paul@316 125
  l4_addr_t region_address(char *address);
paul@316 126
paul@316 127
  l4_addr_t region_address(l4_addr_t address);
paul@316 128
};
paul@316 129
paul@316 130
long Segment::allocate()
paul@316 131
{
paul@316 132
  return ipc_allocate_align(size, L4RE_RM_F_SEARCH_ADDR | flags,
paul@316 133
                           L4_PAGESHIFT, (void **) &buf, &ds);
paul@316 134
}
paul@316 135
paul@316 136
long Segment::fill(file_t *file)
paul@316 137
{
paul@316 138
  if (!file_contents)
paul@316 139
    return L4_EOK;
paul@316 140
paul@316 141
  memset(buf, 0, region_size);
paul@316 142
  client_seek(file, file_offset, SEEK_SET);
paul@316 143
  offset_t nread = client_read(file, buf + region_offset, file_contents);
paul@316 144
paul@316 145
  if (nread < file_contents)
paul@316 146
    return -L4_EIO;
paul@316 147
  else
paul@316 148
    return L4_EOK;
paul@316 149
}
paul@316 150
paul@316 151
Region &Segment::region()
paul@316 152
{
paul@316 153
  _region = Region((l4_addr_t) buf, page_order(region_size), flags, region_base);
paul@316 154
  return _region;
paul@316 155
}
paul@316 156
paul@316 157
l4_addr_t Segment::region_address(char *address)
paul@316 158
{
paul@316 159
  return (l4_addr_t) ((address - buf) + (char *) region_base);
paul@316 160
}
paul@316 161
paul@316 162
l4_addr_t Segment::region_address(l4_addr_t address)
paul@316 163
{
paul@316 164
  return (address - (l4_addr_t) buf) + region_base;
paul@316 165
}
paul@312 166
paul@312 167
paul@312 168
paul@312 169
/* A simple system pager also acting as a region mapper. */
paul@312 170
paul@316 171
typedef std::map<l4_addr_t, Region> Regions;
paul@316 172
paul@312 173
class ExecPager : public PagerObject
paul@312 174
{
paul@312 175
protected:
paul@312 176
  Regions _regions;
paul@312 177
paul@312 178
public:
paul@312 179
  virtual void add(Region region)
paul@312 180
  {
paul@312 181
    _regions[region.map_start] = region;
paul@312 182
  }
paul@312 183
paul@312 184
  /* Notification methods. */
paul@308 185
paul@308 186
  virtual long exception(l4_exc_regs_t regs,
paul@308 187
                         l4_snd_fpage_t *region);
paul@308 188
paul@308 189
  virtual long page_fault(l4_umword_t pfa, l4_umword_t pc,
paul@308 190
                          l4_snd_fpage_t *region);
paul@312 191
paul@312 192
  /* Region manager/mapper methods. */
paul@312 193
paul@312 194
  virtual long attach(address_t *start, offset_t size, map_flags_t flags,
paul@312 195
                      l4_cap_idx_t ds, address_t offset, unsigned char align);
paul@312 196
paul@308 197
};
paul@308 198
paul@312 199
/* Handle a general exception. */
paul@312 200
paul@308 201
long ExecPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region)
paul@308 202
{
paul@308 203
  (void) region;
paul@308 204
paul@308 205
  printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(&regs), l4_utcb_exc_pc(&regs));
paul@312 206
paul@312 207
  printf("r15 = %lx\n", regs.r15);
paul@312 208
  printf("r14 = %lx\n", regs.r14);
paul@312 209
  printf("r13 = %lx\n", regs.r13);
paul@312 210
  printf("r12 = %lx\n", regs.r12);
paul@312 211
  printf("r11 = %lx\n", regs.r11);
paul@312 212
  printf("r10 = %lx\n", regs.r10);
paul@312 213
  printf("r9 = %lx\n", regs.r9);
paul@312 214
  printf("r8 = %lx\n", regs.r8);
paul@312 215
  printf("rdi = %lx\n", regs.rdi);
paul@312 216
  printf("rsi = %lx\n", regs.rsi);
paul@312 217
  printf("rbp = %lx\n", regs.rbp);
paul@312 218
  printf("pfa = %lx\n", regs.pfa);
paul@312 219
  printf("rbx = %lx\n", regs.rbx);
paul@312 220
  printf("rdx = %lx\n", regs.rdx);
paul@312 221
  printf("rcx = %lx\n", regs.rcx);
paul@312 222
  printf("rax = %lx\n", regs.rax);
paul@312 223
  printf("trapno = %lx\n", regs.trapno);
paul@312 224
  printf("err = %lx\n", regs.err);
paul@312 225
  printf("ip = %lx\n", regs.ip);
paul@312 226
  printf("flags = %lx\n", regs.flags);
paul@312 227
  printf("sp = %lx\n", regs.sp);
paul@312 228
  printf("ss = %lx\n", regs.ss);
paul@312 229
  printf("fs_base = %lx\n", regs.fs_base);
paul@312 230
  printf("gs_base = %lx\n", regs.gs_base);
paul@312 231
paul@308 232
  return L4_EOK;
paul@308 233
}
paul@308 234
paul@315 235
#define DEBUG 0
paul@315 236
paul@312 237
/* Handle a page fault using any configured regions. */
paul@312 238
paul@308 239
long ExecPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region)
paul@308 240
{
paul@308 241
  l4_umword_t addr = pfa & ~7UL, flags = pfa & 7;
paul@308 242
paul@315 243
#if DEBUG
paul@312 244
  printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags);
paul@312 245
#endif
paul@312 246
paul@312 247
  Regions::iterator it = _regions.upper_bound(addr);
paul@312 248
paul@312 249
  if (it != _regions.begin())
paul@312 250
    it--;
paul@312 251
  else
paul@312 252
  {
paul@312 253
    printf("not mapped!\n");
paul@312 254
    return -L4_ENOMEM;
paul@312 255
  }
paul@312 256
paul@312 257
  Region &r = it->second;
paul@308 258
paul@312 259
  if ((addr >= r.map_start) && (addr < r.map_start + (1UL << r.log2size)))
paul@308 260
  {
paul@312 261
    l4_addr_t page_addr = trunc(addr, L4_PAGESIZE);
paul@312 262
paul@312 263
    region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, r.flags);
paul@312 264
    region->snd_base = page_addr;
paul@312 265
paul@315 266
#if DEBUG
paul@312 267
    printf("%lx...%lx from %lx...%lx size %d rights %x\n",
paul@312 268
           r.map_start, region->snd_base,
paul@312 269
           r.start, l4_fpage_memaddr(region->fpage),
paul@312 270
           l4_fpage_size(region->fpage),
paul@312 271
           l4_fpage_rights(region->fpage));
paul@312 272
    printf("%lx -> ", addr);
paul@312 273
paul@312 274
    for (unsigned int i = 0; i < sizeof(l4_umword_t); i++)
paul@312 275
      printf("%02x", *((unsigned char *)(r.start + (addr - r.map_start) + i)));
paul@312 276
paul@312 277
    printf("\n");
paul@312 278
#endif
paul@308 279
paul@308 280
    return L4_EOK;
paul@308 281
  }
paul@308 282
paul@315 283
#if DEBUG
paul@312 284
  printf("not mapped!\n");
paul@312 285
#endif
paul@312 286
paul@308 287
  return -L4_ENOMEM;
paul@308 288
}
paul@308 289
paul@312 290
/* Attach a region for provision when page faults occur. This is required in
paul@312 291
   the initialisation of a program by the C library which requires a region
paul@312 292
   mapper. */
paul@312 293
paul@312 294
long ExecPager::attach(address_t *start, offset_t size, map_flags_t flags,
paul@312 295
                       l4_cap_idx_t ds, address_t offset, unsigned char align)
paul@312 296
{
paul@315 297
#if DEBUG
paul@312 298
  printf("attach(%lx, %ld, %lx, ..., %lx, %d)\n", *start, size, flags, offset, align);
paul@312 299
#endif
paul@312 300
paul@312 301
  if (align < L4_PAGESHIFT)
paul@312 302
    align = L4_PAGESHIFT;
paul@312 303
paul@312 304
  offset_t increment = 1UL << align;
paul@312 305
  offset_t region_size = round(size, increment);
paul@312 306
paul@312 307
  /* Either attempt to find an address for the specified region, starting from
paul@312 308
     any indicated address. */
paul@312 309
paul@312 310
  if (flags & L4RE_RM_F_SEARCH_ADDR)
paul@312 311
  {
paul@312 312
    address_t region_start = trunc(*start, increment);
paul@312 313
    Regions::iterator it = _regions.upper_bound(*start);
paul@312 314
paul@312 315
    if (!region_start)
paul@312 316
      region_start += increment;
paul@312 317
paul@315 318
#if DEBUG
paul@312 319
    printf("-> search from %lx -> %lx...\n", *start, region_start);
paul@312 320
#endif
paul@312 321
paul@312 322
    /* Before last known region. */
paul@312 323
paul@312 324
    while (it != _regions.end())
paul@312 325
    {
paul@312 326
      Regions::iterator next = it;
paul@312 327
      Region &r = it->second;
paul@312 328
      address_t start_limit;
paul@312 329
      address_t end_limit = r.map_start;
paul@312 330
paul@312 331
      /* Consider any preceding region. If no such region exists, choose an
paul@312 332
         address at the start of memory. */
paul@312 333
paul@312 334
      if (it == _regions.begin())
paul@312 335
        start_limit = L4_PAGESIZE;
paul@312 336
      else
paul@312 337
      {
paul@312 338
        it--;
paul@312 339
        Region &pr = it->second;
paul@312 340
        start_limit = pr.map_start + (1UL << pr.log2size);
paul@312 341
        it = next;
paul@312 342
      }
paul@312 343
paul@312 344
      /* Test against the limits. */
paul@312 345
paul@312 346
      if (region_start < start_limit)
paul@312 347
        region_start = round(start_limit, increment);
paul@312 348
paul@312 349
      /* Investigate subsequent regions if not enough space exists between the
paul@312 350
         preceding region (or start of memory) and the current region. */
paul@312 351
paul@312 352
      if ((region_start + region_size) > end_limit)
paul@312 353
      {
paul@312 354
        it++;
paul@312 355
        if (it == _regions.end())
paul@312 356
          return -L4_ENOMEM;
paul@312 357
      }
paul@312 358
      else
paul@312 359
        break;
paul@312 360
    }
paul@312 361
paul@312 362
    /* Attach the provided dataspace.
paul@312 363
       NOTE: This is only done in this implementation to support the paging
paul@312 364
             mechanism. In a region mapper residing within the actual task, the
paul@312 365
             dataspace's map operation would be invoked to obtain mappings. */
paul@312 366
paul@312 367
    l4_addr_t ds_start;
paul@312 368
paul@312 369
    long err = ipc_attach_dataspace(ds, size, (void **) &ds_start);
paul@312 370
paul@312 371
    if (err)
paul@312 372
      return err;
paul@312 373
paul@312 374
    l4_touch_rw((const void *) ds_start, size);
paul@312 375
paul@315 376
#if DEBUG
paul@312 377
    printf("-> added region for %lx size %ld (%d)\n", region_start, region_size, page_order(region_size));
paul@312 378
#endif
paul@312 379
paul@312 380
    add(Region(ds_start, page_order(region_size), flags & L4RE_DS_F_RIGHTS_MASK, region_start));
paul@312 381
paul@312 382
    *start = region_start;
paul@312 383
    return L4_EOK;
paul@312 384
  }
paul@312 385
paul@312 386
  /* Or attempt to add the specified region at a specific address. */
paul@312 387
paul@312 388
  else
paul@312 389
  {
paul@312 390
    // NOTE: To be implemented.
paul@312 391
paul@312 392
    return -L4_ENOMEM;
paul@312 393
  }
paul@312 394
}
paul@312 395
paul@308 396
paul@308 397
paul@317 398
static l4_addr_t populate_stack(Segment &stack, int argc, char *argv[], l4_fpage_t utcb_fpage)
paul@317 399
{
paul@317 400
  /* Populate stack with additional capabilities. */
paul@317 401
paul@317 402
  l4re_env_cap_entry_t *stack_env_cap = (l4re_env_cap_entry_t *) (stack.buf + stack.size);
paul@317 403
paul@317 404
  /* Special invalid/terminating environment capability entry. */
paul@317 405
paul@317 406
  *(--stack_env_cap) = l4re_env_cap_entry_t();
paul@317 407
paul@317 408
  printf("Stack region end: %p\n", stack_env_cap);
paul@317 409
paul@317 410
  l4_addr_t caps_start = (l4_addr_t) stack_env_cap;
paul@317 411
  l4_umword_t *stack_element = (l4_umword_t *) stack_env_cap;
paul@317 412
paul@317 413
  /* Populate stack with argument values. */
paul@317 414
paul@317 415
  char *stack_arg = (char *) stack_element;
paul@318 416
  char *stack_arg_top = stack_arg;
paul@318 417
  int arg;
paul@317 418
paul@318 419
  for (arg = argc - 1; arg >= 0; arg--)
paul@318 420
  {
paul@318 421
    char *stack_arg_last = stack_arg;
paul@317 422
paul@318 423
    stack_arg -= round(strlen(argv[arg]) + 1, sizeof(l4_umword_t));
paul@317 424
paul@318 425
    memset(stack_arg, 0, stack_arg_last - stack_arg);
paul@318 426
    memcpy(stack_arg, argv[arg], strlen(argv[arg]));
paul@318 427
paul@318 428
    printf("Stack L4 program argument: %p / %lx\n", stack_arg, stack.region_address(stack_arg));
paul@318 429
  }
paul@317 430
paul@317 431
  stack_element = (l4_umword_t *) stack_arg;
paul@317 432
paul@317 433
  /* Loader flags, debugging flags, and the KIP capability index.
paul@317 434
     See: generate_l4aux in Remote_app_model */
paul@317 435
paul@317 436
  *(--stack_element) = 0;
paul@317 437
  *(--stack_element) = 0;
paul@317 438
  *(--stack_element) = 0x14 << L4_CAP_SHIFT;
paul@317 439
paul@317 440
  printf("Stack L4 aux elements: %p / %lx\n", stack_element, stack.region_address((char *) stack_element));
paul@317 441
paul@317 442
  /* Populate stack with standard capabilities. */
paul@317 443
paul@317 444
  l4re_env_t *env = (l4re_env_t *) stack_element;
paul@317 445
paul@317 446
  env--;
paul@317 447
  env->factory          = L4_BASE_FACTORY_CAP;
paul@317 448
  env->main_thread      = L4_BASE_THREAD_CAP;
paul@317 449
  env->log              = L4_BASE_LOG_CAP;
paul@317 450
  env->scheduler        = L4_BASE_SCHEDULER_CAP;
paul@317 451
  env->rm               = 0x11 << L4_CAP_SHIFT;
paul@317 452
  env->mem_alloc        = 0x12 << L4_CAP_SHIFT;
paul@317 453
  env->first_free_cap   = 0x15;
paul@317 454
  env->caps             = (l4re_env_cap_entry_t *) (stack.region_address(caps_start));
paul@317 455
  env->utcb_area        = utcb_fpage;
paul@317 456
  env->first_free_utcb  = l4_fpage_memaddr(utcb_fpage) + L4_UTCB_OFFSET;
paul@317 457
paul@317 458
  stack_element = (l4_umword_t *) env;
paul@317 459
paul@317 460
  /* Populate stack with AUXV. */
paul@317 461
paul@317 462
  /* AUXV NULL. */
paul@317 463
paul@317 464
  *(--stack_element) = 0;
paul@317 465
  *(--stack_element) = 0;
paul@317 466
paul@317 467
  /* L4Re global environment pointer. */
paul@317 468
paul@317 469
  *(--stack_element) = stack.region_address((char *) env);
paul@317 470
  *(--stack_element) = 0xf1;
paul@317 471
paul@317 472
  /* Apparently required entries. */
paul@317 473
paul@317 474
  *(--stack_element) = L4_PAGESIZE;
paul@317 475
  *(--stack_element) = AT_PAGESZ;
paul@317 476
paul@317 477
  *(--stack_element) = 0;
paul@317 478
  *(--stack_element) = AT_UID;
paul@317 479
paul@317 480
  *(--stack_element) = 0;
paul@317 481
  *(--stack_element) = AT_EUID;
paul@317 482
paul@317 483
  *(--stack_element) = 0;
paul@317 484
  *(--stack_element) = AT_GID;
paul@317 485
paul@317 486
  *(--stack_element) = 0;
paul@317 487
  *(--stack_element) = AT_EGID;
paul@317 488
paul@317 489
  l4_addr_t stack_data_end = (l4_addr_t) stack_element;
paul@317 490
paul@317 491
  printf("Stack L4 data: %lx / %lx\n", stack_data_end, stack.region_address(stack_data_end));
paul@317 492
paul@317 493
  /* No environment pointers. */
paul@317 494
paul@317 495
  *(--stack_element) = 0;
paul@317 496
paul@317 497
  /* Populate stack with argument pointers and count. */
paul@317 498
paul@317 499
  *(--stack_element) = 0;
paul@318 500
paul@318 501
  stack_arg = stack_arg_top;
paul@318 502
paul@318 503
  for (arg = argc - 1; arg >= 0; arg--)
paul@318 504
  {
paul@318 505
    stack_arg -= round(strlen(argv[arg]) + 1, sizeof(l4_umword_t));
paul@318 506
    *(--stack_element) = (l4_umword_t) (stack.region_address(stack_arg));
paul@318 507
  }
paul@318 508
paul@317 509
  *(--stack_element) = argc;
paul@317 510
paul@317 511
  char *stack_adjusted = Ldr::adjust_sp((char *) stack_element, NULL);
paul@317 512
paul@317 513
  /* Adjust the stack alignment. */
paul@317 514
paul@317 515
  if (stack_adjusted != (char *) stack_element)
paul@317 516
    memmove(stack_adjusted, (const void *) stack_element, stack_data_end - (l4_addr_t) stack_element);
paul@317 517
paul@317 518
  l4_umword_t *stack_adjusted_element = (l4_umword_t *) stack_adjusted;
paul@317 519
paul@317 520
  printf("%ld %lx %lx\n", stack_adjusted_element[0], stack_adjusted_element[1], stack_adjusted_element[2]);
paul@317 521
paul@317 522
  l4_addr_t stack_start = stack.region_address(stack_adjusted);
paul@317 523
paul@317 524
  printf("Stack L4 start: %p / %lx\n", stack_adjusted, stack.region_address(stack_adjusted));
paul@317 525
paul@317 526
  return stack_start;
paul@317 527
}
paul@317 528
paul@317 529
paul@317 530
paul@308 531
static ExecPager exec_pager;
paul@308 532
paul@312 533
static void init_pager(ipc_server_config_type *config)
paul@308 534
{
paul@308 535
  ipc_server_init_config(config);
paul@308 536
paul@312 537
  config->expected_items = PagerObject_expected_items;
paul@312 538
  config->handler = (ipc_server_handler_type) handle_PagerObject;
paul@312 539
  config->handler_obj = static_cast<PagerObject *>(&exec_pager);
paul@308 540
}
paul@308 541
paul@308 542
static long start_pager(ipc_server_config_type *config, pthread_t thread)
paul@308 543
{
paul@308 544
  config->config_thread = 1;
paul@308 545
  config->thread = pthread_l4_cap(thread);
paul@308 546
paul@308 547
  printf("Starting pager thread...\n");
paul@308 548
  return ipc_server_start_config(config);
paul@308 549
}
paul@308 550
paul@308 551
paul@308 552
paul@308 553
/* UTCB properties.
paul@308 554
   See: moe/server/src/loader.cc */
paul@308 555
paul@308 556
enum ipc_exec_utcb
paul@308 557
{
paul@308 558
  Default_max_threads = 16,
paul@308 559
#ifdef ARCH_mips
paul@308 560
  Utcb_area_start = 0x73000000,
paul@308 561
#else
paul@308 562
  Utcb_area_start = 0xb3000000,
paul@308 563
#endif
paul@308 564
};
paul@308 565
paul@308 566
paul@308 567
paul@311 568
/* Capability mapping definitions for the new task. */
paul@311 569
paul@311 570
struct mapped_cap
paul@311 571
{
paul@311 572
  l4_cap_idx_t cap;
paul@311 573
  unsigned char rights;
paul@311 574
  l4_umword_t spot;
paul@311 575
};
paul@311 576
paul@311 577
static long map_capabilities(l4_cap_idx_t task, struct mapped_cap mapped_caps[])
paul@308 578
{
paul@311 579
  long err = L4_EOK;
paul@311 580
  int i = 0;
paul@311 581
paul@311 582
  while (l4_is_valid_cap(mapped_caps[i].cap) && !err)
paul@311 583
  {
paul@311 584
    err = l4_error(l4_task_map(task, L4RE_THIS_TASK_CAP,
paul@311 585
                               l4_obj_fpage(mapped_caps[i].cap, 0, mapped_caps[i].rights),
paul@311 586
                               l4_map_obj_control(mapped_caps[i].spot, L4_MAP_ITEM_MAP)));
paul@311 587
    i++;
paul@311 588
  }
paul@311 589
paul@311 590
  return err;
paul@308 591
}
paul@308 592
paul@311 593
paul@311 594
paul@308 595
int main(int argc, char *argv[])
paul@308 596
{
paul@308 597
  long err;
paul@308 598
paul@308 599
  if (argc < 2)
paul@308 600
  {
paul@308 601
    printf("Need a program to run.\n");
paul@308 602
    return 1;
paul@308 603
  }
paul@308 604
paul@308 605
  /* Allocate capabilities for the task and thread. */
paul@308 606
paul@311 607
  l4_cap_idx_t caps[2];
paul@308 608
paul@311 609
  err = ipc_cap_alloc_many(caps, 2);
paul@308 610
paul@311 611
  if (err)
paul@308 612
  {
paul@311 613
    printf("Could not allocate capabilities.\n");
paul@308 614
    return 1;
paul@308 615
  }
paul@308 616
paul@311 617
  l4_cap_idx_t &task = caps[0];
paul@311 618
  l4_cap_idx_t &thread = caps[1];
paul@308 619
paul@308 620
  /* Obtain the payload as a dataspace. */
paul@308 621
paul@308 622
  file_t *file = client_open(argv[1], O_RDONLY);
paul@308 623
paul@308 624
  if (file == NULL)
paul@308 625
  {
paul@308 626
    printf("Could not read file: %s\n", argv[1]);
paul@308 627
    return 1;
paul@308 628
  }
paul@308 629
paul@312 630
  /* Copy the payload regions to new dataspaces.
paul@312 631
     NOTE: This should be directed by the ELF metadata. */
paul@308 632
paul@318 633
  address_t program_start = 0x1000b43;
paul@315 634
paul@318 635
  Segment program(0x1000000, 0x28326, L4_FPAGE_RWX, 0, 0x28326);
paul@316 636
  Segment data(0x1029360, 0x8068, L4_FPAGE_RW, 0x28360, 0x2058);
paul@316 637
  Segment stack(0x80000000, 16 * L4_PAGESIZE, L4_FPAGE_RW);
paul@316 638
  Segment *segments[] = {&program, &data, &stack, NULL};
paul@316 639
  Segment **segment;
paul@316 640
paul@316 641
  for (segment = segments; *segment != NULL; segment++)
paul@316 642
  {
paul@316 643
    err = (*segment)->allocate();
paul@308 644
paul@316 645
    if (err)
paul@316 646
    {
paul@316 647
      printf("Could not reserve memory.\n");
paul@316 648
      return 1;
paul@316 649
    }
paul@308 650
paul@316 651
    err = (*segment)->fill(file);
paul@316 652
paul@316 653
    if (err)
paul@316 654
    {
paul@316 655
      printf("Could not fill segment from file.\n");
paul@316 656
      return 1;
paul@316 657
    }
paul@308 658
  }
paul@308 659
paul@316 660
  if (memcmp(program.buf + program_start - program.region_base, "\x31\xed", 2))
paul@308 661
  {
paul@308 662
    printf("Did not find expected instructions at start.\n");
paul@308 663
    return 1;
paul@308 664
  }
paul@308 665
paul@308 666
  /* UTCB location and size. */
paul@308 667
paul@308 668
  l4_addr_t utcb_start = Utcb_area_start;
paul@311 669
  int utcb_log2size = page_order(Default_max_threads * L4_UTCB_OFFSET);
paul@308 670
paul@308 671
  /* Round up to at least one page. */
paul@308 672
paul@308 673
  if (utcb_log2size < L4_PAGESHIFT)
paul@308 674
    utcb_log2size = L4_PAGESHIFT;
paul@308 675
paul@312 676
  l4_fpage_t utcb_fpage = l4_fpage(utcb_start, utcb_log2size, 0);
paul@312 677
paul@308 678
  /* KIP allocation. */
paul@308 679
paul@308 680
  l4_addr_t kip_start = (l4_addr_t) l4re_kip();
paul@308 681
paul@308 682
  printf("KIP at %lx.\n", kip_start);
paul@308 683
paul@317 684
  /* Populate the stack with argument and environment details. */
paul@308 685
paul@317 686
  l4_addr_t stack_start = populate_stack(stack, argc - 1, argv + 1, utcb_fpage);
paul@312 687
paul@312 688
  /* Create a new task and thread. */
paul@308 689
paul@308 690
  err = l4_error(l4_factory_create_task(l4re_env()->factory, task, utcb_fpage));
paul@308 691
paul@308 692
  if (err)
paul@308 693
  {
paul@308 694
    printf("Could not create task.\n");
paul@308 695
    return 1;
paul@308 696
  }
paul@308 697
paul@308 698
  err = l4_error(l4_factory_create_thread(l4re_env()->factory, thread));
paul@308 699
paul@308 700
  if (err)
paul@308 701
  {
paul@308 702
    printf("Could not create thread.\n");
paul@308 703
    return 1;
paul@308 704
  }
paul@308 705
paul@308 706
  /* Start the pager. */
paul@308 707
paul@308 708
  ipc_server_config_type config;
paul@308 709
  pthread_t pager_thread;
paul@308 710
  pthread_attr_t attr;
paul@308 711
paul@308 712
  pthread_attr_init(&attr);
paul@308 713
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
paul@308 714
paul@312 715
  init_pager(&config);
paul@312 716
paul@316 717
  for (segment = segments; *segment != NULL; segment++)
paul@316 718
    exec_pager.add((*segment)->region());
paul@308 719
paul@308 720
  err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &config);
paul@308 721
paul@308 722
  if (err)
paul@308 723
  {
paul@308 724
    printf("Could not start pager thread.\n");
paul@308 725
    return 1;
paul@308 726
  }
paul@308 727
paul@308 728
  err = start_pager(&config, pager_thread);
paul@308 729
paul@308 730
  if (err)
paul@308 731
  {
paul@308 732
    printf("Could not start pager.\n");
paul@308 733
    return 1;
paul@308 734
  }
paul@308 735
paul@312 736
  /* Define capability mappings for the new task. */
paul@308 737
paul@312 738
  struct mapped_cap mapped_caps[] = {
paul@312 739
    {config.server,         L4_CAP_FPAGE_RWS, 0x10 << L4_CAP_SHIFT},
paul@312 740
    {config.server,         L4_CAP_FPAGE_RWS, 0x11 << L4_CAP_SHIFT},
paul@312 741
    {task,                  L4_CAP_FPAGE_RWS, L4_BASE_TASK_CAP},
paul@312 742
    {thread,                L4_CAP_FPAGE_RWS, L4_BASE_THREAD_CAP},
paul@312 743
    {l4re_env()->factory,   L4_CAP_FPAGE_RWS, L4_BASE_FACTORY_CAP},
paul@312 744
    {l4re_env()->log,       L4_CAP_FPAGE_RWS, L4_BASE_LOG_CAP},
paul@312 745
    {l4re_env()->scheduler, L4_CAP_FPAGE_RWS, L4_BASE_SCHEDULER_CAP},
paul@312 746
    {l4re_env()->mem_alloc, L4_CAP_FPAGE_RWS, 0x12 << L4_CAP_SHIFT},
paul@312 747
    {L4_INVALID_CAP,        0,                0},
paul@312 748
    };
paul@312 749
paul@312 750
  err = map_capabilities(task, mapped_caps);
paul@308 751
paul@308 752
  if (err)
paul@308 753
  {
paul@312 754
    printf("Could not capabilities into task.\n");
paul@308 755
    return 1;
paul@308 756
  }
paul@308 757
paul@308 758
  /* Map the KIP into the task. */
paul@308 759
paul@308 760
  err = l4_error(l4_task_map(task, L4RE_THIS_TASK_CAP,
paul@308 761
                             l4_fpage(kip_start, L4_PAGESHIFT, L4_FPAGE_RX),
paul@308 762
                             kip_start));
paul@308 763
paul@308 764
  if (err)
paul@308 765
  {
paul@308 766
    printf("Could not map KIP into task.\n");
paul@308 767
    return 1;
paul@308 768
  }
paul@308 769
paul@308 770
  /* Configure the thread with the region manager acting as pager and exception
paul@308 771
     handler. The UTCB will be situated at an address supported by a dataspace
paul@308 772
     attached to the new task. */
paul@308 773
paul@308 774
  printf("Configure thread...\n");
paul@308 775
paul@308 776
  l4_thread_control_start();
paul@308 777
  l4_thread_control_pager(0x10 << L4_CAP_SHIFT);
paul@308 778
  l4_thread_control_exc_handler(0x10 << L4_CAP_SHIFT);
paul@308 779
  l4_thread_control_bind((l4_utcb_t *) utcb_start, task);
paul@308 780
  err = l4_error(l4_thread_control_commit(thread));
paul@308 781
paul@308 782
  if (err)
paul@308 783
  {
paul@308 784
    printf("Could not configure thread.\n");
paul@308 785
    return 1;
paul@308 786
  }
paul@308 787
paul@308 788
  /* Start the new thread. */
paul@308 789
paul@308 790
  printf("Schedule thread...\n");
paul@308 791
paul@316 792
  printf("Stack at 0x%lx mapped to region at 0x%lx.\n", stack_start, stack.region_base);
paul@312 793
paul@315 794
  err = l4_error(l4_thread_ex_regs(thread, program_start, stack_start, 0));
paul@308 795
paul@308 796
  if (err)
paul@308 797
  {
paul@308 798
    printf("Could not set thread registers.\n");
paul@308 799
    return 1;
paul@308 800
  }
paul@308 801
paul@308 802
  printf("Run thread...\n");
paul@308 803
paul@308 804
  l4_sched_param_t sp = l4_sched_param(L4RE_MAIN_THREAD_PRIO);
paul@308 805
paul@308 806
  err = l4_error(l4_scheduler_run_thread(l4re_env()->scheduler, thread, &sp));
paul@308 807
paul@308 808
  if (err)
paul@308 809
  {
paul@308 810
    printf("Could not run thread.\n");
paul@308 811
    return 1;
paul@308 812
  }
paul@308 813
paul@308 814
  printf("Finished.\n");
paul@308 815
  while (1);
paul@308 816
paul@308 817
  return 0;
paul@308 818
}
paul@308 819
paul@308 820
/* vim: tabstop=2 expandtab shiftwidth=2
paul@308 821
*/