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