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