L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
vmm.lua
Go to the documentation of this file.
1--! \file vmm.lua
2
3local L4 = require "L4";
4
5local l = L4.Loader.new({mem = L4.Env.user_factory});
6loader = l;
7
8--[[!
9 \internal
10
11 Utility function to merge several lua tables
12
13 \param ... one or more tables
14
15 \note Later tables are given more priority when merging
16
17 \return a new combined table
18]]
19function table_override(...)
20 local combined = {}
21 for _, tab in ipairs({...}) do
22 for k, v in pairs(tab) do
23 combined[k] = v
24 end
25 end
26 return combined
27end
28
29--[[!
30 Creates a new scheduler proxy at moe.
31
32 \param prio Base priority of the threads running in the scheduler proxy
33 \param cpu_mask First of a list of CPU masks for the first 64 CPUs to use for
34 the scheduler proxy
35 \param ... more CPU masks
36
37 \return created scheduler
38]]
39function new_sched(prio, cpu_mask, ...)
40 return L4.Env.user_factory:create(L4.Proto.Scheduler, prio + 10, prio,
41 cpu_mask, ...);
42end
43
44--[[!
45 Start IO service with the given options
46
47 \param[in,out] busses table of vBus names as keys. Uses io config
48 `<name>.vbus` to fill vBus `<name>`.
49 \param cmdline io command line parameters
50 \param opts Option table for loader.start function, e.g. scheduler
51 or ext_caps. Entries from ext_caps have precedence over
52 default caps created by this function.
53
54 After this function returns the created vBusses are located in the table
55 passed as `busses`.
56]]
57function start_io(busses, cmdline, opts)
58 if opts == nil then opts = {} end
59
60 if opts.caps ~= nil then
61 print("Warning: use opts.ext_caps to pass custom/additional capabilities.")
62 end
63
64 if opts.scheduler == nil then
65 print("IO started with base priority. Risk of priority related deadlocks! "
66 .. "Provide an opts.scheduler entry.")
67 end
68
69 local caps = {
70 sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0);
71 icu = L4.Env.icu;
72 iommu = L4.Env.iommu;
73 dma_mgr = L4.Env.dma_mgr;
74 };
75
76 local files = "";
77
78 for k, v in pairs(busses) do
79 if caps[k] ~= nil then
80 print("Warning: overwriting caps." .. k .. " with vbus of same name.")
81 end
82 local c = l:new_channel();
83 busses[k] = c
84 caps[k] = c:svr();
85 files = files .. " rom/" .. k .. ".vbus";
86 end
87
88 opts.caps = table_override(caps, opts.caps or {}, opts.ext_caps or {})
89 opts.log = opts.log or { "io", "red" }
90
91 return l:start(opts, "rom/io " .. cmdline .. files)
92end
93
94--[[!
95 Create scheduler proxy and add it into the `opts` table under
96 the key `scheduler`.
97
98 \param[in,out] opts option table
99 \param prio thread priority (or `nil`)
100 \param cpus cpu mask (or `nil`)
101 \param ... more CPU masks
102
103 There are four possibilities for values of prio and cpus:
104
105 \li No prio and no cpus: No scheduler proxy created.
106 \li A prio, but no cpus: Create a scheduler proxy with only a priority limit.
107 \li No Prio, but cpus: Create a scheduler proxy with default prio and cpus
108 limit.
109 \li A prio and cpus: Create a scheduler proxy with given limits.
110]]
111function set_sched(opts, prio, cpus, ...)
112 if cpus == nil and prio == nil then
113 return
114 end
115
116 if prio == nil then
117 -- Default to zero to use the L4Re Default_thread_prio
118 prio = 0
119 end
120
121 local sched = new_sched(prio, cpus, ...);
122 opts["scheduler"] = sched;
123end
124
125--[[!
126 Start virtio network application.
127
128 \deprecated This function exists for backwards compatiblity reasons and calls
129 \ref start_virtio_switch_tbl with an appropriate `options` table
130
131 \param[in,out] ports table with port names as keys
132 \param prio priority for started thread
133 \param cpus cpu mask for started thread
134 \param switch_type Selects application to start. Either `switch` or `p2p`
135 \param ext_caps Extra capabilities to pass to the started application
136
137 The switch_type `switch` can take additional arguments to create a port at the
138 switch. To pass these arguments for a specific port, pass a table as value for
139 a key in the ports table.
140
141]]
142function start_virtio_switch(ports, prio, cpus, switch_type, ext_caps)
143 local opts = {
144 ports = ports,
145 switch_type = switch_type,
146 ext_caps = ext_caps,
147 }
148 set_sched(opts, prio, cpus)
149 return start_virtio_switch_tbl(opts)
150end
151
152--[[!
153 Start virtio network application.
154
155 \param options A table of parameters
156
157 The following keys are supported in the `options` table:
158
159 | table key | value |
160 | ------------ | ---------------------------------------------------------------- |
161 | `ports` | table with port names as keys |
162 | `scheduler` | scheduler (e.g. created with new_sched) |
163 | `switch_type`| selects application to start. Either `switch` or `p2p` |
164 | `ext_caps` | Extra capabilities to pass to the started application |
165 | `svr_cap` | cap slot to be used for the server interface |
166 | `port_limit` | the maximum number of dynamic ports the switch shall support |
167
168 The switch_type `switch` can take additional arguments to create a port at the
169 switch. To pass these arguments for a specific port, pass a table as value for
170 a key in the ports table.
171
172 \note The `svr_cap` capability requires server rights, use ":svr()".
173]]
174function start_virtio_switch_tbl(options)
175 local ports = options.ports;
176 local scheduler = options.scheduler;
177 local switch_type = options.switch_type;
178 local ext_caps = options.ext_caps;
179 local svr_cap = options.svr_cap;
180 local port_limit = options.port_limit;
181
182 if svr_cap and port_limit == nil then
183 print("Warning: start_virtio_switch_tbl(): 'svr_cap' defined, but no "..
184 "'port_limit' set. The svr_cap will not support dynamic port "..
185 "creation.")
186 end
187
188 if port_limit and svr_cap == nil then
189 error("start_virtio_switch_tbl(): 'port_limit' set, but no 'svr_cap'. "..
190 "This is not supported")
191 end
192
193 local switch
194
195 if svr_cap then
196 switch = svr_cap:svr()
197 else
198 switch = l:new_channel()
199 end
200
201 local opts = {
202 log = { "switch", "Blue" },
203 caps = table_override({ svr = switch:svr() }, ext_caps or {});
204 };
205
206 if scheduler then
207 opts["scheduler"] = scheduler;
208 end
209
210 if switch_type == "switch" then
211 local port_count = 0;
212 for k, v in pairs(ports) do
213 port_count = port_count + 1;
214 end
215 if port_limit then
216 port_count = port_count + port_limit
217 end
218
219 svr = l:start(opts, "rom/l4vio_switch -v -p " .. port_count );
220
221 for k, extra_opts in pairs(ports) do
222 if type(extra_opts) ~= "table" then
223 extra_opts = {}
224 end
225
226 ports[k] = L4.cast(L4.Proto.Factory, switch):create(
227 0,
228 "ds-max=4",
229 "name=" .. k,
230 table.unpack(extra_opts)
231 )
232 end
233 else
234 svr = l:start(opts, "rom/l4vio_net_p2p");
235
236 for k, v in pairs(ports) do
237 ports[k] = L4.cast(L4.Proto.Factory, switch):create(0, "ds-max=4");
238 end
239 end
240
241 return svr;
242end
243
244--[[!
245 Start UVMM
246
247 \param options A table of parameters
248
249 The following keys are supported in the `options` table:
250
251 | table key | value |
252 | ----------- | ---------------------------------------------------------------- |
253 | `bootargs` | command line for guest kernel |
254 | `cpus` | cpu mask |
255 | `ext_args` | additional arguments to pass to UVMM |
256 | `fdt` | file name of the device tree |
257 | `id` | an integer identifying the VM |
258 | `jdb` | jdb capability |
259 | `kernel` | file name of the guest kernel binary |
260 | `mem` | RAM size in MiB \e or dataspace cap for guest memory. |
261 | `mem_align` | alignment for the guest memory in bits. Ignored if mem is a cap. |
262 | `mon` | monitor application file name |
263 | `net` | a virtio cap, e.g. for network |
264 | `prio` | thread priority |
265 | `ram_base` | start of guest memory |
266 | `rd` | file name of the ramdisk |
267 | `scheduler` | a scheduler cap. If used, prio and cpus are ignored. |
268 | `vbus` | the vBus to attach to the VM |
269]]
270function start_vm(options)
271 local nr = options.id;
272 local size_mb = 0;
273 local vbus = options.vbus;
274 local vnet = options.net;
275 local prio = options.prio;
276 local cpus = options.cpus;
277 local scheduler = options.scheduler;
278 local nonidentmem = options.nonidentmem;
279
280 local align = 10;
281 if L4.Info.arch() == "arm" then
282 align = 28;
283 elseif L4.Info.arch() == "arm64" then
284 align = 21;
285 end
286 align = options.mem_align or align;
287
288 local cmdline = {};
289 if options.fdt then
290 if type(options.fdt) ~= "table" then
291 options.fdt = { options.fdt }
292 end
293 for _,v in ipairs(options.fdt) do
294 cmdline[#cmdline+1] = "-d" .. v;
295 end
296 end
297
298 if options.bootargs then
299 cmdline[#cmdline+1] = "-c" .. options.bootargs;
300 end
301
302 if options.rd then
303 cmdline[#cmdline+1] = "-r" .. options.rd;
304 end
305
306 if options.kernel then
307 cmdline[#cmdline+1] = "-k" .. options.kernel;
308 end
309
310 if options.ram_base then
311 cmdline[#cmdline+1] = "-b" .. options.ram_base;
312 end
313
314 if L4.Info.arch() == "arm" or L4.Info.arch() == "arm64" then
315 if not options.nonidentmem then
316 cmdline[#cmdline+1] = "-i";
317 end
318 end
319
320 local keyb_shortcut = nil;
321 if nr ~= nil then
322 keyb_shortcut = "key=" .. nr;
323 end
324
325 local vm_ram;
326 if type(options.mem) == "userdata" then
327 -- User gave us a cap. Using this as dataspace for guest RAM.
328 vm_ram = options.mem
329 elseif type(options.mem) == "number" then
330 -- User gave us a number. Using this as size for a new Dataspace.
331 size_mb = options.mem
332 elseif type(options.mem) == "string" then
333 print("start_vm: mem parameter '" .. options.mem .. "' is of type string, "
334 .. "please use integer.");
335 size_mb = tonumber(options.mem)
336 else
337 -- User did not give us any valid value.
338 size_mb = 16
339 end
340
341 if size_mb > 0 then
342 local mem_flags = L4.Mem_alloc_flags.Continuous
343 | L4.Mem_alloc_flags.Pinned
344 | L4.Mem_alloc_flags.Super_pages;
345
346 vm_ram = L4.Env.user_factory:create(L4.Proto.Dataspace,
347 size_mb * 1024 * 1024,
348 mem_flags, align):m("rw");
349 end
350
351 local caps = {
352 net = vnet;
353 vbus = vbus;
354 ram = vm_ram;
355 };
356
357 if options.jdb then
358 caps["jdb"] = L4.Env.jdb
359 end
360
361 if options.ext_args then
362 for _,v in ipairs(options.ext_args) do
363 cmdline[#cmdline+1] = v
364 end
365 end
366
367 local opts = {
368 log = options.log or l.log_fab:create(L4.Proto.Log, "vm" .. nr, "w",
369 keyb_shortcut);
370 caps = table_override(caps, options.ext_caps or {});
371 };
372
373 if scheduler then
374 opts["scheduler"] = scheduler;
375 else
376 set_sched(opts, prio, cpus);
377 end
378
379 if type(options.mon) == 'string' then
380 -- assume 'mon' is the name of a server binary which implements the uvmm
381 -- CLI interface
382 mon = l:new_channel()
383
384 l:start({
385 scheduler = opts.scheduler;
386 log = l.log_fab:create(L4.Proto.Log, "mon" .. nr),
387 caps = { mon = mon:svr() }
388 }, "rom/" .. options.mon)
389
390 opts.caps["mon"] = mon
391 elseif options.mon ~= false then
392 opts.caps["mon"] = l.log_fab:create(L4.Proto.Log, "mon" .. nr, "g");
393 end
394
395 return l:startv(opts, "rom/uvmm", table.unpack(cmdline));
396end
397
398return _ENV
C++ Factory interface, see Factory for the C interface.
Definition factory:39
L4Re C++ Interfaces.
Definition cmd_control:14
L4 low-level kernel interface.
start_vm(​ options)
start_virtio_switch_tbl(​ options)
new_sched(​ prio, ​ cpu_mask, ​ ...)
start_virtio_switch(​ ports, ​ prio, ​ cpus, ​ switch_type, ​ ext_caps)
set_sched(​ opts, ​ prio, ​ cpus, ​ ...)
start_io(​ busses, ​ cmdline, ​ opts)