1-- vim:set ft=lua: 2local require = require 3local pairs = pairs 4local setmetatable = setmetatable 5local getmetatable = getmetatable 6local error = error 7local type = type 8 9local _ENV = require "L4" 10local string = require "string" 11local table = require "table" 12 13-- Add this alias, it sounds better for some cases 14Env.user_factory = Env.mem_alloc; 15 16-- L4 protocol constants 17Proto = { 18 Dataspace = 0x4000, 19 Namespace = 0x4001, 20 Goos = 0x4003, 21 Mem_alloc = 0x4004, 22 Rm = 0x4005, 23 Event = 0x4006, 24 Inhibitor = 0x4007, 25 Sigma0 = -6, 26 Log = -13, 27 Scheduler = -14, 28 Factory = -15, 29 Vm = -16, 30 Dma_space = -17, 31 Irq_sender = -18, 32 Semaphore = -20, 33 Iommu = -22, 34 Ipc_gate = 0, 35} 36 37-- L4 rights flags 38Rights = { 39 s = 2, 40 w = 1, 41 r = 4, 42 d = 8, 43 n = 16, 44 c = 32, 45 ro = 4, 46 rw = 5, 47 rws = 7, 48} 49 50-- Ldr flags 51Ldr_flags = { 52 eager_map = 0x1, -- L4RE_AUX_LDR_FLAG_EAGER_MAP 53 all_segs_cow = 0x2, -- L4RE_AUX_LDR_FLAG_ALL_SEGS_COW 54 pinned_segs = 0x4, -- L4RE_AUX_LDR_FLAG_PINNED_SEGS 55} 56 57-- Flags for dataspace allocation via user_factory 58-- NOTE: keep constants in sync with l4re/include/mem_alloc 59Mem_alloc_flags = { 60 Continuous = 1, 61 Pinned = 2, 62 Super_pages = 4, 63} 64 65-- L4Re debug constants 66Dbg = { 67 Info = 1, 68 Warn = 2, 69 Boot = 4, 70 Server = 0x10, 71 Exceptions = 0x20, 72 Cmd_line = 0x40, 73 Loader = 0x80, 74 Name_space = 0x400, 75 All = 0xffffffff, 76} 77 78-- Loader class, encapsulates a loader instance. 79-- * A memory allocator 80-- * A factory used for name-space creation (ns_fab) 81-- * A factory used for region-map creation (rm_fab) 82-- * A factory used for log creation (log_fab) 83 84Loader = {}; 85Loader.__index = Loader; 86 87Class = {}; 88 89function Class.check(obj, class) 90 if not obj or getmetatable(obj) ~= class then 91 error("method called with incompatible object", 3); 92 end 93end 94 95function Loader.new(proto) 96 local f = proto or {}; 97 98 do 99 local lfab = f.loader or f.mem; 100 f.log_fab = f.log_fab or lfab; 101 f.ns_fab = f.ns_fab or lfab; 102 f.rm_fab = f.rm_fab or lfab; 103 f.factory = f.factory or Env.factory; 104 end 105 106 setmetatable(f, Loader); 107 return f; 108end 109 110function mangle_class(n) 111 local m = "N"; 112 for i in string.gmatch(n, "([^:%s]+)") do 113 m = m .. #i .. i; 114 end 115 return m .. "E"; 116end 117 118function cast(to, cap) 119 if type(to) == 'number' then 120 return __cast(to, cap) 121 elseif type(to) == 'string' then 122 return __cast(mangle_class(to), cap) 123 end 124 return nil 125end 126 127function get_cap_class(id) 128 local t = type(id); 129 if t == "number" then 130 return _CAP_TYPES[id]; 131 elseif t == "string" then 132 return _CAP_TYPES[mangle_class(id)]; 133 else 134 return nil; 135 end 136end 137 138local ns_class = get_cap_class("L4Re::Namespace"); 139if ns_class then 140 ns_class.register = function (self, key, value, fab) 141 if type(value) == "string" then 142 local res = Env 143 for i in string.gmatch(value, "([^/]+)") do 144 if type(res) == "table" then 145 res = res[i] 146 elseif res then 147 res = res:query(i)() 148 else 149 break 150 end 151 end 152 if res == nil then 153 error("Could not resolve: '" .. value .. "'", 5) 154 end 155 value = res 156 end 157 158 if type(value) == "function" then 159 value = value(self, key); 160 end 161 162 if value ~= nil then 163 if type(value) ~= "table" then 164 self:__register(key, value); 165 elseif (fab) then 166 self:__register(key, fab(value)); 167 end 168 end 169 end 170 ns_class.r = ns_class.register; 171else 172 error("Could not find type information for L4Re::Namespace"); 173end 174 175ns_class = nil; 176 177function Loader:fill_namespace(ns, tmpl, fab) 178 local function cns(value) 179 return self:create_namespace(value, fab); 180 end 181 182 for k, v in pairs(tmpl) do 183 ns:r(k, v, cns); 184 end 185end 186 187 188function Loader:create_namespace(n, fab) 189 Class.check(self, Loader); 190 191 if type(n) ~= "table" then 192 return n; 193 end 194 195 local ns_fab = fab or self.ns_fab; 196 local ns = ns_fab:create(Proto.Namespace); 197 self:fill_namespace(ns, n, ns_fab); 198 return ns; 199end 200 201 202 203App_env = {} 204App_env.__index = App_env; 205 206function App_env.new(proto) 207 local f = proto or {}; 208 209 f.loader = f.loader or default_loader; 210 f.rm_fab = f.rm_fab or f.loader.rm_fab; 211 f.factory = f.factory or f.loader.factory or Env.factory; 212 -- f.scheduler = f.scheduler or f.loader.scheduler; 213 214 f.mem = f.mem or f.loader.mem; 215 216 if type(f.log) == "table" then 217 f.log_args = f.log; 218 f.log = nil; 219 elseif type(f.log) == "function" then 220 f.log = f.log() 221 f.log_args = {} 222 else 223 f.log_args = {} 224 end 225 226 setmetatable(f, App_env); 227 228 if type(f.ns) == "table" then 229 f.ns = f.loader:create_namespace(f.ns, f.ns_fab); 230 end 231 232 return f; 233end 234 235function App_env:log() 236 Class.check(self, App_env); 237 if self.loader.log_fab == nil or self.loader.log_fab.create == nil then 238 error ("Starting an application without valid log factory", 4); 239 end 240 return self.loader.log_fab:create(Proto.Log, table.unpack(self.log_args)); 241end 242 243function App_env:start(...) 244 Class.check(self, App_env); 245 246 local function fa(a) 247 return string.gsub(a, ".*/", ""); 248 end 249 local old_log_tag = self.log_args[1]; 250 self.log_args[1] = self.log_args[1] or fa(...); 251 local res = exec(self, ...); 252 self.log_args[1] = old_log_tag; 253 return res; 254end 255 256function App_env:set_ns(tmpl) 257 Class.check(self, App_env); 258 self.ns = Namespace.new(tmpl, self.ns_fab); 259end 260 261function App_env:set_loader_fab(fab) 262 Class.check(self, App_env); 263 self.log_fab = fab; 264 self.ns_fab = fab; 265 self.rm_fab = fab; 266end 267 268function App_env:set_mem_alloc(mem) 269 Class.check(self, App_env); 270 self.mem = mem; 271end 272 273function Loader:startv(env, ...) 274 Class.check(self, Loader); 275 276 local caps = env.caps or {}; 277 278 if (type(caps) == "table") then 279 for k, v in pairs(caps) do 280 if type(v) == "table" and getmetatable(v) == nil then 281 caps[k] = self:create_namespace(v) 282 end 283 end 284 285 local defcaps = self.default_caps or { rom = Env.rom:m("r") } 286 287 for k, v in pairs(defcaps) do 288 caps[k] = caps[k] or v 289 end 290 end 291 292 env.loader = self; 293 env.caps = caps; 294 env.l4re_dbg = env.l4re_dbg or Dbg.Warn; 295 local e = App_env.new(env); 296 return e:start(...); 297end 298 299-- Create a new IPC gate for a client-server connection 300function Loader:new_channel() 301 return self.factory:create(Proto.Ipc_gate); 302end 303 304function Loader.split_args(cmd, posix_env) 305 local a = {}; 306 local i = 1; 307 for w in string.gmatch(cmd, "[^%s]+") do 308 a[i] = w; 309 i = i + 1; 310 end 311 a[i] = posix_env; 312 return table.unpack(a); 313end 314 315function Loader:start(env, cmd, posix_env) 316 Class.check(self, Loader); 317 return self:startv(env, self.split_args(cmd, posix_env)); 318end 319 320default_loader = Loader.new({factory = Env.factory, mem = Env.mem_alloc}); 321 322return _ENV 323