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/util/util.h> 25 26 #include <exec/elf.h> 27 #include <exec/memory.h> 28 #include <exec/external_pager.h> 29 #include <exec/process.h> 30 #include <ipc/server.h> 31 32 #include <stdio.h> 33 34 #include <pthread-l4.h> 35 #include <pthread.h> 36 37 #include "pager_object_server.h" 38 39 40 41 static ExternalPager exec_pager; 42 43 static const offset_t initial_stack_size = 16 * L4_PAGESIZE; 44 45 46 47 /* Start the system pager in a separate thread. */ 48 49 static long start_pager(ipc_server_config_type &config) 50 { 51 pthread_t pager_thread; 52 pthread_attr_t attr; 53 54 pthread_attr_init(&attr); 55 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 56 57 ipc_server_init_for(&config, PagerObject, &exec_pager); 58 59 long err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &config); 60 61 if (err) 62 return err; 63 64 return ipc_server_start_config_thread(&config, pthread_l4_cap(pager_thread)); 65 } 66 67 68 69 int main(int argc, char *argv[]) 70 { 71 long err; 72 73 if (argc < 2) 74 { 75 printf("Need a program to run.\n"); 76 return 1; 77 } 78 79 /* Initialise the memory of the new task. */ 80 81 ExplicitSegment stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW); 82 Payload *payload; 83 84 if (exec_get_payload(argv[1], &payload, true)) 85 { 86 printf("Could not initialise program.\n"); 87 return 1; 88 } 89 90 if (stack.allocate(true)) 91 { 92 printf("Could not allocate stack.\n"); 93 return 1; 94 } 95 96 /* Initialise pager regions. */ 97 98 for (unsigned int i = 0; i < payload->segments(); i++) 99 { 100 if (payload->segment(i)->loadable()) 101 exec_pager.add(payload->segment(i)->region()); 102 } 103 104 exec_pager.add(stack.region()); 105 106 /* Start the pager in a separate thread. */ 107 108 ipc_server_config_type config; 109 110 printf("Starting pager thread...\n"); 111 112 err = start_pager(config); 113 114 if (err) 115 { 116 printf("Could not start pager.\n"); 117 return 1; 118 } 119 120 /* Configure the environment for the task, specifying the pager (and exception 121 handler plus region mapper). */ 122 123 Process process; 124 125 err = process.configure_task(); 126 127 if (err) 128 { 129 printf("Could not configure task.\n"); 130 return 1; 131 } 132 133 err = process.configure_thread(config.server); 134 135 if (err) 136 { 137 printf("Could not configure thread.\n"); 138 return 1; 139 } 140 141 /* Populate a thread stack with argument and environment details. */ 142 143 Stack program_st(stack); 144 145 /* NOTE: Environment vector is currently not defined. */ 146 147 char *envp[] = {NULL}; 148 149 program_st.populate(argc - 1, argv + 1, envp); 150 151 /* Start the new thread in the given stack. */ 152 153 printf("Run thread...\n"); 154 155 err = process.thread_start(payload->entry_point(), program_st); 156 157 if (err) 158 { 159 printf("Could not run thread.\n"); 160 return 1; 161 } 162 163 printf("Finished.\n"); 164 while (1) 165 l4_sleep_forever(); 166 167 return 0; 168 } 169 170 /* vim: tabstop=2 expandtab shiftwidth=2 171 */