1 /* 2 * Support for initialising programs 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/sys/err.h> 23 #include <l4/sys/scheduler.h> 24 25 #include <exec/process.h> 26 #include <ipc/cap_alloc.h> 27 #include <ipc/map.h> 28 #include <mem/memory_utils.h> 29 30 31 32 /* Obtain a flexpage defining the UTCB area location and size in a new task. */ 33 34 static l4_fpage_t get_utcb_fpage() 35 { 36 /* UTCB location and size. */ 37 38 int utcb_log2size = page_order(Default_max_threads * L4_UTCB_OFFSET); 39 40 /* Round up to at least one page. */ 41 42 if (utcb_log2size < L4_PAGESHIFT) 43 utcb_log2size = L4_PAGESHIFT; 44 45 return l4_fpage(Utcb_area_start, utcb_log2size, 0); 46 } 47 48 49 50 /* Initialise a new process, this being an abstraction for a new task with some 51 threads. */ 52 53 Process::Process(int reserved_threads) 54 { 55 /* Obtain UTCB area details for the task. */ 56 57 l4_fpage_t utcb_fpage = get_utcb_fpage(); 58 59 _utcb_start = l4_fpage_memaddr(utcb_fpage); 60 61 /* Populate the common initial environment for the threads. */ 62 63 _env.factory = L4_BASE_FACTORY_CAP; 64 _env.main_thread = L4_BASE_THREAD_CAP; 65 _env.log = L4_BASE_LOG_CAP; 66 _env.scheduler = L4_BASE_SCHEDULER_CAP; 67 _env.rm = L4_EXEC_RM_CAP; 68 _env.mem_alloc = L4_EXEC_MA_CAP; 69 _env.first_free_cap = L4_EXEC_FIRST_FREE_CAP_INDEX; 70 _env.utcb_area = utcb_fpage; 71 _env.first_free_utcb = l4_fpage_memaddr(utcb_fpage) + reserved_threads * L4_UTCB_OFFSET; 72 73 /* Populate auxiliary information. */ 74 75 _aux.kip_ds = L4_EXEC_KIP_CAP; 76 _aux.dbg_lvl = 0; 77 _aux.ldr_flags = 0; 78 } 79 80 /* Task and thread initialisation. */ 81 82 long Process::create_task() 83 { 84 _task = ipc_cap_alloc(); 85 86 if (l4_is_invalid_cap(_task)) 87 return -L4_ENOMEM; 88 89 return l4_error(l4_factory_create_task(l4re_env()->factory, _task, _env.utcb_area)); 90 } 91 92 long Process::create_thread(l4_cap_idx_t *thread) 93 { 94 *thread = ipc_cap_alloc(); 95 96 if (l4_is_invalid_cap(*thread)) 97 return -L4_ENOMEM; 98 99 return l4_error(l4_factory_create_thread(l4re_env()->factory, *thread)); 100 } 101 102 /* Configure the task environment. */ 103 104 long Process::configure_task() 105 { 106 long err = create_task(); 107 108 if (err) 109 return err; 110 111 /* Map the KIP into the task. */ 112 113 l4_addr_t kip_start = (l4_addr_t) l4re_kip(); 114 115 err = l4_error(l4_task_map(_task, L4RE_THIS_TASK_CAP, 116 l4_fpage(kip_start, L4_PAGESHIFT, L4_FPAGE_RX), 117 kip_start)); 118 119 if (err) 120 return err; 121 122 /* Define capability mappings for the new task. */ 123 124 struct ipc_mapped_cap mapped_caps[] = { 125 {L4_BASE_TASK_CAP, _task, L4_CAP_FPAGE_RWS}, 126 {_env.factory, l4re_env()->factory, L4_CAP_FPAGE_RWS}, 127 {_env.log, l4re_env()->log, L4_CAP_FPAGE_RWS}, 128 {_env.scheduler, l4re_env()->scheduler, L4_CAP_FPAGE_RWS}, 129 {_env.mem_alloc, l4re_env()->mem_alloc, L4_CAP_FPAGE_RWS}, 130 {0, L4_INVALID_CAP, 0}, 131 }; 132 133 return map_capabilities(mapped_caps, false); 134 } 135 136 /* Configure the thread environment. */ 137 138 long Process::configure_thread(l4_cap_idx_t server) 139 { 140 struct ipc_mapped_cap mapped_caps[] = { 141 {L4_EXEC_PAGER_CAP, server, L4_CAP_FPAGE_RWS}, 142 {_env.rm, server, L4_CAP_FPAGE_RWS}, 143 {0, L4_INVALID_CAP, 0}, 144 }; 145 146 return map_capabilities(mapped_caps, false); 147 } 148 149 /* Map capabilities into the task, counting them if indicated. */ 150 151 long Process::map_capabilities(struct ipc_mapped_cap mapped_caps[], 152 bool to_count) 153 { 154 return ipc_map_capabilities(_task, mapped_caps, to_count ? &_num_mapped_caps : NULL); 155 } 156 157 /* Create, initialise and start a thread. */ 158 159 long Process::thread_start(l4_addr_t program_start, Stack &st) 160 { 161 l4_cap_idx_t thread; 162 long err; 163 164 err = create_thread(&thread); 165 166 if (err) 167 return err; 168 169 /* Initialise the thread with pager, UTCB and task details. */ 170 171 l4_thread_control_start(); 172 l4_thread_control_pager(L4_EXEC_PAGER_CAP); 173 l4_thread_control_exc_handler(L4_EXEC_PAGER_CAP); 174 l4_thread_control_bind((l4_utcb_t *) _utcb_start, _task); 175 176 err = l4_error(l4_thread_control_commit(thread)); 177 178 if (err) 179 { 180 ipc_cap_free(thread); 181 return err; 182 } 183 184 /* Map the thread capability to the task. */ 185 186 ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.main_thread, thread, L4_CAP_FPAGE_RWS}); 187 188 /* Update the environment for any mapped capabilities. */ 189 190 _env.first_free_cap = L4_EXEC_FIRST_FREE_CAP_INDEX + _num_mapped_caps; 191 192 /* Populate the initial environment in the thread. */ 193 194 st.set_l4re_aux(&_aux); 195 st.set_l4re_env(&_env); 196 197 /* Set the start details. */ 198 199 err = l4_error(l4_thread_ex_regs(thread, program_start, st.start_address(), 0)); 200 201 if (err) 202 return err; 203 204 /* Select a new address for the next thread. */ 205 206 _utcb_start += L4_UTCB_OFFSET; 207 208 /* Start the thread. */ 209 210 l4_sched_param_t sp = l4_sched_param(L4RE_MAIN_THREAD_PRIO); 211 212 return l4_error(l4_scheduler_run_thread(l4re_env()->scheduler, thread, &sp)); 213 } 214 215 /* vim: tabstop=2 expandtab shiftwidth=2 216 */