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