1 /* 2 * Support for executing code in new tasks and threads. 3 * 4 * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/re/env.h> 23 #include <l4/sys/err.h> 24 #include <l4/sys/factory.h> 25 #include <l4/sys/task.h> 26 #include <l4/sys/thread.h> 27 #include <l4/util/elf.h> 28 #include <l4/util/util.h> 29 30 #include <l4/libloader/adjust_stack> 31 32 #include <fsclient/client.h> 33 #include <ipc/cap_alloc.h> 34 #include <ipc/mem_ipc.h> 35 #include <ipc/server.h> 36 #include <mem/memory_utils.h> 37 #include <systypes/fcntl.h> 38 39 #include <map> 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 45 #include <pthread-l4.h> 46 #include <pthread.h> 47 48 #include "pager_object_interface.h" 49 #include "pager_object_server.h" 50 51 52 53 /* UTCB properties. 54 See: moe/server/src/loader.cc */ 55 56 enum ipc_exec_utcb 57 { 58 Default_max_threads = 16, 59 #ifdef ARCH_mips 60 Utcb_area_start = 0x73000000, 61 #else 62 Utcb_area_start = 0xb3000000, 63 #endif 64 }; 65 66 static l4_fpage_t get_utcb_fpage() 67 { 68 /* UTCB location and size. */ 69 70 int utcb_log2size = page_order(Default_max_threads * L4_UTCB_OFFSET); 71 72 /* Round up to at least one page. */ 73 74 if (utcb_log2size < L4_PAGESHIFT) 75 utcb_log2size = L4_PAGESHIFT; 76 77 return l4_fpage(Utcb_area_start, utcb_log2size, 0); 78 } 79 80 81 82 /* Mapped region data structures. */ 83 84 class MappedRegion 85 { 86 public: 87 l4_addr_t start; 88 unsigned int log2size; 89 l4_umword_t flags; 90 l4_addr_t map_start; 91 92 explicit MappedRegion() 93 : start(0), log2size(0), flags(0), map_start(0) 94 { 95 } 96 97 explicit MappedRegion(l4_addr_t start, unsigned int log2size, 98 l4_umword_t flags, l4_addr_t map_start) 99 : start(start), log2size(log2size), flags(flags), map_start(map_start) 100 { 101 } 102 }; 103 104 105 106 /* Program segment abstraction. */ 107 108 class Segment 109 { 110 protected: 111 MappedRegion _region; 112 113 public: 114 /* Allocated memory. */ 115 116 char *buf; 117 l4re_ds_t ds; 118 119 /* Segment base and corresponding region base. */ 120 121 l4_addr_t base, region_base; 122 123 /* Segment size and corresponding region size. */ 124 125 offset_t size, region_size; 126 127 /* Offset of segment content within the region. */ 128 129 offset_t region_offset; 130 131 /* Access flags. */ 132 133 l4re_rm_flags_t flags; 134 135 /* File access details. */ 136 137 offset_t file_offset, file_contents; 138 139 explicit Segment(offset_t base, offset_t size, l4re_rm_flags_t flags, 140 offset_t file_offset = 0, offset_t file_contents = 0) 141 : base(base), size(size), flags(flags), file_offset(file_offset), file_contents(file_contents) 142 { 143 region_base = trunc(base, L4_PAGESIZE); 144 region_offset = base - region_base; 145 region_size = round(size, L4_PAGESIZE); 146 } 147 148 long allocate(); 149 150 long fill(file_t *file); 151 152 MappedRegion ®ion(); 153 154 l4_addr_t region_address(char *address); 155 156 l4_addr_t region_address(l4_addr_t address); 157 }; 158 159 long Segment::allocate() 160 { 161 return ipc_allocate_align(size, L4RE_RM_F_SEARCH_ADDR | flags, 162 L4_PAGESHIFT, (void **) &buf, &ds); 163 } 164 165 long Segment::fill(file_t *file) 166 { 167 if (!file_contents) 168 return L4_EOK; 169 170 memset(buf, 0, region_size); 171 client_seek(file, file_offset, SEEK_SET); 172 offset_t nread = client_read(file, buf + region_offset, file_contents); 173 174 if (nread < file_contents) 175 return -L4_EIO; 176 else 177 return L4_EOK; 178 } 179 180 MappedRegion &Segment::region() 181 { 182 _region = MappedRegion((l4_addr_t) buf, page_order(region_size), flags, region_base); 183 return _region; 184 } 185 186 l4_addr_t Segment::region_address(char *address) 187 { 188 return (l4_addr_t) ((address - buf) + (char *) region_base); 189 } 190 191 l4_addr_t Segment::region_address(l4_addr_t address) 192 { 193 return (address - (l4_addr_t) buf) + region_base; 194 } 195 196 197 198 /* A simple system pager also acting as a region mapper. */ 199 200 typedef std::map<l4_addr_t, MappedRegion> MappedRegions; 201 202 class ExecPager : public PagerObject 203 { 204 protected: 205 MappedRegions _regions; 206 207 public: 208 virtual void add(MappedRegion region) 209 { 210 _regions[region.map_start] = region; 211 } 212 213 /* Notification methods. */ 214 215 virtual long exception(l4_exc_regs_t regs, 216 l4_snd_fpage_t *region); 217 218 virtual long page_fault(l4_umword_t pfa, l4_umword_t pc, 219 l4_snd_fpage_t *region); 220 221 /* Region manager/mapper methods. */ 222 223 virtual long attach(address_t *start, offset_t size, map_flags_t flags, 224 l4_cap_idx_t ds, address_t offset, unsigned char align); 225 226 }; 227 228 /* Handle a general exception. */ 229 230 long ExecPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region) 231 { 232 (void) region; 233 234 printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s)); 235 236 printf("r15 = %lx\n", regs.r15); 237 printf("r14 = %lx\n", regs.r14); 238 printf("r13 = %lx\n", regs.r13); 239 printf("r12 = %lx\n", regs.r12); 240 printf("r11 = %lx\n", regs.r11); 241 printf("r10 = %lx\n", regs.r10); 242 printf("r9 = %lx\n", regs.r9); 243 printf("r8 = %lx\n", regs.r8); 244 printf("rdi = %lx\n", regs.rdi); 245 printf("rsi = %lx\n", regs.rsi); 246 printf("rbp = %lx\n", regs.rbp); 247 printf("pfa = %lx\n", regs.pfa); 248 printf("rbx = %lx\n", regs.rbx); 249 printf("rdx = %lx\n", regs.rdx); 250 printf("rcx = %lx\n", regs.rcx); 251 printf("rax = %lx\n", regs.rax); 252 printf("trapno = %lx\n", regs.trapno); 253 printf("err = %lx\n", regs.err); 254 printf("ip = %lx\n", regs.ip); 255 printf("flags = %lx\n", regs.flags); 256 printf("sp = %lx\n", regs.sp); 257 printf("ss = %lx\n", regs.ss); 258 printf("fs_base = %lx\n", regs.fs_base); 259 printf("gs_base = %lx\n", regs.gs_base); 260 261 return L4_EOK; 262 } 263 264 #define DEBUG 0 265 266 /* Handle a page fault using any configured regions. */ 267 268 long ExecPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region) 269 { 270 l4_umword_t addr = pfa & ~7UL, flags = pfa & 7; 271 272 #if DEBUG 273 printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags); 274 #endif 275 276 MappedRegions::iterator it = _regions.upper_bound(addr); 277 278 if (it != _regions.begin()) 279 it--; 280 else 281 { 282 printf("not mapped!\n"); 283 return -L4_ENOMEM; 284 } 285 286 MappedRegion &r = it->second; 287 288 if ((addr >= r.map_start) && (addr < r.map_start + (1UL << r.log2size))) 289 { 290 l4_addr_t page_addr = trunc(addr, L4_PAGESIZE); 291 292 region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, r.flags); 293 region->snd_base = page_addr; 294 295 #if DEBUG 296 printf("%lx...%lx from %lx...%lx size %d rights %x\n", 297 r.map_start, region->snd_base, 298 r.start, l4_fpage_memaddr(region->fpage), 299 l4_fpage_size(region->fpage), 300 l4_fpage_rights(region->fpage)); 301 printf("%lx -> ", addr); 302 303 for (unsigned int i = 0; i < sizeof(l4_umword_t); i++) 304 printf("%02x", *((unsigned char *)(r.start + (addr - r.map_start) + i))); 305 306 printf("\n"); 307 #endif 308 309 return L4_EOK; 310 } 311 312 #if DEBUG 313 printf("not mapped!\n"); 314 #endif 315 316 return -L4_ENOMEM; 317 } 318 319 /* Attach a region for provision when page faults occur. This is required in 320 the initialisation of a program by the C library which requires a region 321 mapper. */ 322 323 long ExecPager::attach(address_t *start, offset_t size, map_flags_t flags, 324 l4_cap_idx_t ds, address_t offset, unsigned char align) 325 { 326 #if DEBUG 327 printf("attach(%lx, %ld, %lx, ..., %lx, %d)\n", *start, size, flags, offset, align); 328 #endif 329 330 if (align < L4_PAGESHIFT) 331 align = L4_PAGESHIFT; 332 333 offset_t increment = 1UL << align; 334 offset_t region_size = round(size, increment); 335 336 /* Either attempt to find an address for the specified region, starting from 337 any indicated address. */ 338 339 if (flags & L4RE_RM_F_SEARCH_ADDR) 340 { 341 address_t region_start = trunc(*start, increment); 342 MappedRegions::iterator it = _regions.upper_bound(*start); 343 344 if (!region_start) 345 region_start += increment; 346 347 #if DEBUG 348 printf("-> search from %lx -> %lx...\n", *start, region_start); 349 #endif 350 351 /* Before last known region. */ 352 353 while (it != _regions.end()) 354 { 355 MappedRegions::iterator next = it; 356 MappedRegion &r = it->second; 357 address_t start_limit; 358 address_t end_limit = r.map_start; 359 360 /* Consider any preceding region. If no such region exists, choose an 361 address at the start of memory. */ 362 363 if (it == _regions.begin()) 364 start_limit = L4_PAGESIZE; 365 else 366 { 367 it--; 368 MappedRegion &pr = it->second; 369 start_limit = pr.map_start + (1UL << pr.log2size); 370 it = next; 371 } 372 373 /* Test against the limits. */ 374 375 if (region_start < start_limit) 376 region_start = round(start_limit, increment); 377 378 /* Investigate subsequent regions if not enough space exists between the 379 preceding region (or start of memory) and the current region. */ 380 381 if ((region_start + region_size) > end_limit) 382 { 383 it++; 384 if (it == _regions.end()) 385 return -L4_ENOMEM; 386 } 387 else 388 break; 389 } 390 391 /* Attach the provided dataspace. 392 NOTE: This is only done in this implementation to support the paging 393 mechanism. In a region mapper residing within the actual task, the 394 dataspace's map operation would be invoked to obtain mappings. */ 395 396 l4_addr_t ds_start; 397 398 long err = ipc_attach_dataspace(ds, size, (void **) &ds_start); 399 400 if (err) 401 return err; 402 403 l4_touch_rw((const void *) ds_start, size); 404 405 #if DEBUG 406 printf("-> added region for %lx size %ld (%d)\n", region_start, region_size, page_order(region_size)); 407 #endif 408 409 add(MappedRegion(ds_start, page_order(region_size), flags & L4RE_DS_F_RIGHTS_MASK, region_start)); 410 411 *start = region_start; 412 return L4_EOK; 413 } 414 415 /* Or attempt to add the specified region at a specific address. */ 416 417 else 418 { 419 // NOTE: To be implemented. 420 421 return -L4_ENOMEM; 422 } 423 } 424 425 426 427 /* Capability mapping definitions for the new task. */ 428 429 struct mapped_cap 430 { 431 l4_umword_t index; 432 l4_cap_idx_t cap; 433 unsigned char rights; 434 }; 435 436 static long map_capability(l4_cap_idx_t task, struct mapped_cap mapped_cap) 437 { 438 return l4_error(l4_task_map(task, L4RE_THIS_TASK_CAP, 439 l4_obj_fpage(mapped_cap.cap, 0, mapped_cap.rights), 440 l4_map_obj_control(mapped_cap.index, L4_MAP_ITEM_MAP))); 441 } 442 443 static long map_capabilities(l4_cap_idx_t task, struct mapped_cap mapped_caps[]) 444 { 445 long err = L4_EOK; 446 447 for (int i = 0; l4_is_valid_cap(mapped_caps[i].cap) && !err; i++) 448 err = map_capability(task, mapped_caps[i]); 449 450 return err; 451 } 452 453 454 455 /* A stack abstraction. */ 456 457 class Stack 458 { 459 struct auxv_entry 460 { 461 l4_umword_t key, value; 462 }; 463 464 protected: 465 Segment &_segment; 466 467 /* Next element pointer. */ 468 469 l4_umword_t *_element; 470 471 /* Stack section properties. */ 472 473 l4_addr_t _caps; 474 char *_arg_top, *_env_top; 475 char *_auxv_end; 476 int _env_entries; 477 478 /* L4Re environment region. */ 479 480 l4re_env_t *_env; 481 482 public: 483 /* Start address. */ 484 485 l4_addr_t start; 486 487 /* Initialise a stack in a memory segment. */ 488 489 explicit Stack(Segment &segment) 490 : _segment(segment) 491 { 492 _element = (l4_umword_t *) (segment.buf + segment.size); 493 494 /* Add a terminator for any additional initial capabilities. */ 495 496 l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element; 497 498 *(--entry) = l4re_env_cap_entry_t(); 499 _element = (l4_umword_t *) entry; 500 } 501 502 /* Push any additional initial capabilities. */ 503 504 void push_cap_entries(l4re_env_cap_entry_t *entries) 505 { 506 l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element; 507 508 while ((entries != NULL) && (entries->cap != L4_INVALID_CAP)) 509 *(--entry) = *entries; 510 511 _caps = (l4_addr_t) entry; 512 _element = (l4_umword_t *) entry; 513 } 514 515 /* Push environment values in reverse order. */ 516 517 void push_string(char *s) 518 { 519 char *arg = (char *) _element; 520 char *arg_last = arg; 521 522 arg -= round(strlen(s) + 1, sizeof(l4_umword_t)); 523 524 memset(arg, 0, arg_last - arg); 525 memcpy(arg, s, strlen(s)); 526 527 _element = (l4_umword_t *) arg; 528 } 529 530 /* Push environment values in reverse order. */ 531 532 void push_env(char *envp[]) 533 { 534 _env_top = (char *) _element; 535 _env_entries = 0; 536 537 for (; *envp != NULL; envp++, _env_entries++) 538 push_string(*envp); 539 } 540 541 /* Push argument values in reverse order. */ 542 543 void push_args(int argc, char *argv[]) 544 { 545 _arg_top = (char *) _element; 546 547 for (int i = 0; i < argc; i++) 548 push_string(argv[i]); 549 } 550 551 /* Loader flags, debugging flags, and the KIP capability index. 552 See: generate_l4aux in Remote_app_model */ 553 554 void push_l4re_flags() 555 { 556 *(--_element) = 0; 557 *(--_element) = 0; 558 *(--_element) = 0x14 << L4_CAP_SHIFT; 559 } 560 561 void push_l4re_env() 562 { 563 _env = (l4re_env_t *) _element; 564 _env--; 565 _element = (l4_umword_t *) _env; 566 } 567 568 /* Set the common environment, introducing the reference to additional 569 capabilities. */ 570 571 void set_l4re_env(l4re_env_t *env) 572 { 573 memcpy(_env, env, sizeof(l4re_env_t)); 574 _env->caps = (l4re_env_cap_entry_t *) (_segment.region_address(_caps)); 575 } 576 577 /* Push the auxiliary vector. */ 578 579 void push_auxv() 580 { 581 _auxv_end = (char *) _element; 582 583 struct auxv_entry *auxv_base = (struct auxv_entry *) _element; 584 585 /* AUXV NULL. */ 586 587 *(--auxv_base) = {0, 0}; 588 589 /* L4Re global environment pointer. */ 590 591 *(--auxv_base) = {0xf1, _segment.region_address((char *) _env)}; 592 593 /* Apparently required entries. 594 NOTE: The user/group identifiers should be obtained from the broader 595 environment. */ 596 597 *(--auxv_base) = {AT_PAGESZ, L4_PAGESIZE}; 598 *(--auxv_base) = {AT_UID, 0}; 599 *(--auxv_base) = {AT_EUID, 0}; 600 *(--auxv_base) = {AT_GID, 0}; 601 *(--auxv_base) = {AT_EGID, 0}; 602 603 _element = (l4_umword_t *) auxv_base; 604 } 605 606 /* Fill the stack in reverse with an address, returning the size of the 607 value. */ 608 609 offset_t write_address(char *arg, char **addr, char *s) 610 { 611 offset_t size = round(strlen(s) + 1, sizeof(l4_umword_t)); 612 613 *addr = (char *) _segment.region_address(arg - size); 614 return size; 615 } 616 617 /* Populate stack with environment pointers, employing a pointer ordering 618 that is the reverse of the value ordering. */ 619 620 void push_envp(char *envp[]) 621 { 622 /* Write the terminating element. */ 623 624 *(--_element) = 0; 625 626 /* Reserve space and fill the stack from the top inwards. */ 627 628 char **ep = (char **) (_element - _env_entries); 629 char *arg = _env_top; 630 631 for (; *envp != NULL; envp++, ep++) 632 arg -= write_address(arg, ep, *envp); 633 634 _element -= _env_entries; 635 } 636 637 /* Populate stack with argument pointers and count, employing a pointer 638 ordering that is the reverse of the value ordering. */ 639 640 void push_argv(int argc, char *argv[]) 641 { 642 /* Write the terminating element. */ 643 644 *(--_element) = 0; 645 646 /* Reserve space and fill the stack from the top inwards. */ 647 648 char **ap = (char **) (_element - argc); 649 char *arg = _arg_top; 650 651 for (int i = 0; i < argc; i++) 652 arg -= write_address(arg, &ap[i], argv[i]); 653 654 /* Write the count. */ 655 656 _element -= argc; 657 658 *(--_element) = argc; 659 } 660 661 /* Adjust the stack alignment and return the stack address. */ 662 663 l4_addr_t align_stack() 664 { 665 char *current = (char *) _element; 666 char *adjusted = Ldr::adjust_sp(current, NULL); 667 668 if (adjusted != current) 669 memmove(adjusted, (const void *) current, _auxv_end - current); 670 671 _element = (l4_umword_t *) adjusted; 672 673 return _segment.region_address(adjusted); 674 } 675 676 /* Populate the stack with arguments and initial environment. */ 677 678 void populate(int argc, char *argv[], char *envp[]) 679 { 680 /* Populate stack with environment and argument values. */ 681 682 push_env(envp); 683 push_args(argc, argv); 684 685 /* Push L4Re flags, environment and auxiliary vector. */ 686 687 push_l4re_flags(); 688 push_l4re_env(); 689 push_auxv(); 690 691 /* Push environment and argument pointers. */ 692 693 push_envp(envp); 694 push_argv(argc, argv); 695 696 /* Adjust the stack alignment. */ 697 698 start = align_stack(); 699 } 700 }; 701 702 703 704 class Process 705 { 706 protected: 707 l4_cap_idx_t _task = L4_INVALID_CAP; 708 709 /* Capability index definitions. */ 710 711 l4_cap_idx_t _pager_cap = 0x10 << L4_CAP_SHIFT; 712 l4_cap_idx_t _rm_cap = 0x11 << L4_CAP_SHIFT; 713 l4_cap_idx_t _ma_cap = 0x12 << L4_CAP_SHIFT; 714 unsigned int _first_cap = 0x15; 715 716 /* UTCB details. */ 717 718 l4_addr_t _utcb_start; 719 720 /* Common environment details. */ 721 722 l4re_env_t _env; 723 724 /* Task and thread initialisation. */ 725 726 long create_task() 727 { 728 _task = ipc_cap_alloc(); 729 730 if (l4_is_invalid_cap(_task)) 731 return -L4_ENOMEM; 732 733 return l4_error(l4_factory_create_task(l4re_env()->factory, _task, _env.utcb_area)); 734 } 735 736 long create_thread(l4_cap_idx_t *thread) 737 { 738 *thread = ipc_cap_alloc(); 739 740 if (l4_is_invalid_cap(*thread)) 741 return -L4_ENOMEM; 742 743 return l4_error(l4_factory_create_thread(l4re_env()->factory, *thread)); 744 } 745 746 public: 747 explicit Process() 748 { 749 /* Obtain UTCB area details for the task. */ 750 751 l4_fpage_t utcb_fpage = get_utcb_fpage(); 752 753 _utcb_start = l4_fpage_memaddr(utcb_fpage); 754 755 /* Populate the common initial environment for the threads. */ 756 757 _env.factory = L4_BASE_FACTORY_CAP; 758 _env.main_thread = L4_BASE_THREAD_CAP; 759 _env.log = L4_BASE_LOG_CAP; 760 _env.scheduler = L4_BASE_SCHEDULER_CAP; 761 _env.rm = _rm_cap; 762 _env.mem_alloc = _ma_cap; 763 _env.first_free_cap = _first_cap; 764 _env.utcb_area = utcb_fpage; 765 _env.first_free_utcb = l4_fpage_memaddr(utcb_fpage) + L4_UTCB_OFFSET; 766 } 767 768 /* Configure the task environment. */ 769 770 long configure(l4_cap_idx_t server) 771 { 772 long err = create_task(); 773 774 if (err) 775 return err; 776 777 /* Map the KIP into the task. */ 778 779 l4_addr_t kip_start = (l4_addr_t) l4re_kip(); 780 781 err = l4_error(l4_task_map(_task, L4RE_THIS_TASK_CAP, 782 l4_fpage(kip_start, L4_PAGESHIFT, L4_FPAGE_RX), 783 kip_start)); 784 785 if (err) 786 return err; 787 788 /* Define capability mappings for the new task. */ 789 790 struct mapped_cap mapped_caps[] = { 791 {L4_BASE_TASK_CAP, _task, L4_CAP_FPAGE_RWS}, 792 {_pager_cap, server, L4_CAP_FPAGE_RWS}, 793 {_env.rm, server, L4_CAP_FPAGE_RWS}, 794 {_env.factory, l4re_env()->factory, L4_CAP_FPAGE_RWS}, 795 {_env.log, l4re_env()->log, L4_CAP_FPAGE_RWS}, 796 {_env.scheduler, l4re_env()->scheduler, L4_CAP_FPAGE_RWS}, 797 {_env.mem_alloc, l4re_env()->mem_alloc, L4_CAP_FPAGE_RWS}, 798 {0, L4_INVALID_CAP, 0}, 799 }; 800 801 return map_capabilities(_task, mapped_caps); 802 } 803 804 /* Create, initialise and start a thread. */ 805 806 long thread_start(l4_addr_t program_start, Stack &st) 807 { 808 l4_cap_idx_t thread; 809 long err; 810 811 err = create_thread(&thread); 812 813 if (err) 814 return err; 815 816 /* Initialise the thread with pager, UTCB and task details. */ 817 818 l4_thread_control_start(); 819 l4_thread_control_pager(_pager_cap); 820 l4_thread_control_exc_handler(_pager_cap); 821 l4_thread_control_bind((l4_utcb_t *) _utcb_start, _task); 822 823 err = l4_error(l4_thread_control_commit(thread)); 824 825 if (err) 826 { 827 ipc_cap_free(thread); 828 return err; 829 } 830 831 /* Map the thread capability to the task. */ 832 833 map_capability(_task, (struct mapped_cap) {_env.main_thread, thread, L4_CAP_FPAGE_RWS}); 834 835 /* Populate the initial environment in the thread. */ 836 837 st.set_l4re_env(&_env); 838 839 /* Set the start details. */ 840 841 err = l4_error(l4_thread_ex_regs(thread, program_start, st.start, 0)); 842 843 if (err) 844 return err; 845 846 /* Select a new address for the next thread. */ 847 848 _utcb_start += L4_UTCB_OFFSET; 849 850 /* Start the thread. */ 851 852 l4_sched_param_t sp = l4_sched_param(L4RE_MAIN_THREAD_PRIO); 853 854 return l4_error(l4_scheduler_run_thread(l4re_env()->scheduler, thread, &sp)); 855 } 856 }; 857 858 859 860 static ExecPager exec_pager; 861 862 static void init_pager(ipc_server_config_type *config) 863 { 864 ipc_server_init_config(config); 865 866 config->expected_items = PagerObject_expected_items; 867 config->handler = (ipc_server_handler_type) handle_PagerObject; 868 config->handler_obj = static_cast<PagerObject *>(&exec_pager); 869 } 870 871 static long start_pager(ipc_server_config_type *config, pthread_t thread) 872 { 873 config->config_thread = 1; 874 config->thread = pthread_l4_cap(thread); 875 876 printf("Starting pager thread...\n"); 877 return ipc_server_start_config(config); 878 } 879 880 881 882 int main(int argc, char *argv[]) 883 { 884 long err; 885 886 if (argc < 2) 887 { 888 printf("Need a program to run.\n"); 889 return 1; 890 } 891 892 /* Obtain the payload as a dataspace. */ 893 894 file_t *file = client_open(argv[1], O_RDONLY); 895 896 if (file == NULL) 897 { 898 printf("Could not read file: %s\n", argv[1]); 899 return 1; 900 } 901 902 /* Copy the payload regions to new dataspaces. 903 NOTE: This should be directed by the ELF metadata. */ 904 905 address_t program_start = 0x1000b43; 906 offset_t initial_stack_size = 16 * L4_PAGESIZE; 907 908 Segment program(0x1000000, 0x28326, L4_FPAGE_RWX, 0, 0x28326); 909 Segment data(0x1029360, 0x8068, L4_FPAGE_RW, 0x28360, 0x2058); 910 Segment stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW); 911 Segment *segments[] = {&program, &data, &stack, NULL}; 912 Segment **segment; 913 914 for (segment = segments; *segment != NULL; segment++) 915 { 916 err = (*segment)->allocate(); 917 918 if (err) 919 { 920 printf("Could not reserve memory.\n"); 921 return 1; 922 } 923 924 err = (*segment)->fill(file); 925 926 if (err) 927 { 928 printf("Could not fill segment from file.\n"); 929 return 1; 930 } 931 } 932 933 /* Start the pager. */ 934 935 ipc_server_config_type config; 936 pthread_t pager_thread; 937 pthread_attr_t attr; 938 939 pthread_attr_init(&attr); 940 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 941 942 init_pager(&config); 943 944 for (segment = segments; *segment != NULL; segment++) 945 exec_pager.add((*segment)->region()); 946 947 err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &config); 948 949 if (err) 950 { 951 printf("Could not start pager thread.\n"); 952 return 1; 953 } 954 955 err = start_pager(&config, pager_thread); 956 957 if (err) 958 { 959 printf("Could not start pager.\n"); 960 return 1; 961 } 962 963 /* Configure the environment for the task, specifying the pager (and exception 964 handler plus region mapper). */ 965 966 Process process; 967 968 err = process.configure(config.server); 969 970 if (err) 971 { 972 printf("Could not configure task.\n"); 973 return 1; 974 } 975 976 /* Populate a thread stack with argument and environment details. */ 977 978 Stack st(stack); 979 980 /* NOTE: Environment vector is currently not defined. */ 981 982 char *envp[] = {NULL}; 983 984 st.populate(argc - 1, argv + 1, envp); 985 986 /* Start the new thread in the given stack. */ 987 988 printf("Run thread...\n"); 989 990 err = process.thread_start(program_start, st); 991 992 if (err) 993 { 994 printf("Could not run thread.\n"); 995 return 1; 996 } 997 998 printf("Finished.\n"); 999 while (1); 1000 1001 return 0; 1002 } 1003 1004 /* vim: tabstop=2 expandtab shiftwidth=2 1005 */