xref: /inferno-os/emu/port/devdynld.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 #include	<a.out.h>
5 #include	<dynld.h>
6 
7 #define	DBG	if(1) print
8 
9 extern ulong ndevs;
10 
11 enum
12 {
13 	Qdir,
14 	Qdynld,
15 	Qdynsyms,
16 
17 	DEVCHAR	= 'L',
18 };
19 
20 static Dirtab	dltab[] =
21 {
22 	".",			{Qdir, 0, QTDIR},	0,	DMDIR|0555,
23 	"dynld",		{Qdynld},	0,	0644,
24 	"dynsyms",	{Qdynsyms},	0,	0444,
25 };
26 
27 enum
28 {
29 	DLdev,
30 	DLudev,
31 };
32 
33 static Cmdtab	dlcmd[] =
34 {
35 	DLdev,	"dev",	2,
36 	DLudev,	"udev",	2,
37 };
38 
39 typedef struct Dyndev Dyndev;
40 
41 struct Dyndev
42 {
43 	char	*path;
44 	Dynobj	*o;
45 	Dev	*dev;
46 	Dyndev	*next;
47 };
48 
49 static	Dyndev	*loaded;
50 static	QLock	dllock;
51 
52 typedef struct Fd Fd;
53 struct Fd {
54 	int	fd;
55 };
56 
57 static long
readfd(void * a,void * buf,long nbytes)58 readfd(void *a, void *buf, long nbytes)
59 {
60 	return kread(((Fd*)a)->fd, buf, nbytes);
61 }
62 
63 static vlong
seekfd(void * a,vlong off,int t)64 seekfd(void *a, vlong off, int t)
65 {
66 	return kseek(((Fd*)a)->fd, off, t);
67 }
68 
69 static void
errfd(char * s)70 errfd(char *s)
71 {
72 	kstrcpy(up->env->errstr, s, ERRMAX);
73 }
74 
75 static void
dlfree(Dyndev * l)76 dlfree(Dyndev *l)
77 {
78 	if(l != nil){
79 		free(l->path);
80 		dynobjfree(l->o);
81 		free(l);
82 	}
83 }
84 
85 static Dyndev*
dlload(char * path,Dynsym * tab,int ntab)86 dlload(char *path, Dynsym *tab, int ntab)
87 {
88 	Fd f;
89 	Dyndev *l;
90 
91 	f.fd = kopen(path, OREAD);
92 	if(f.fd < 0)
93 		error("cannot open");
94 	if(waserror()){
95 		kclose(f.fd);
96 		nexterror();
97 	}
98 	l = mallocz(sizeof(Dyndev), 1);
99 	if(l == nil)
100 		error(Enomem);
101 	if(waserror()){
102 		dlfree(l);
103 		nexterror();
104 	}
105 	l->path = strdup(path);
106 	if(l->path == nil)
107 		error(Enomem);
108 	l->o = dynloadgen(&f, readfd, seekfd, errfd, tab, ntab, 0);
109 	if(l->o == nil)
110 		error(up->env->errstr);
111 	poperror();
112 	poperror();
113 	kclose(f.fd);
114 	return l;
115 }
116 
117 static void
devload(char * path)118 devload(char *path)
119 {
120 	int i;
121 	Dyndev *l;
122 	Dev *dev;
123 	char devname[32];
124 
125 	l = dlload(path, _exporttab, dyntabsize(_exporttab));
126 	if(waserror()){
127 		dlfree(l);
128 		nexterror();
129 	}
130 	snprint(devname, sizeof(devname), "%sdevtab", "XXX");	/* TO DO */
131 	dev = dynimport(l->o, devname, signof(*dev));
132 	if(dev == nil)
133 		error("no devtab");
134 	if(devno(dev->dc, 1) >= 0)
135 		error("device loaded");
136 	for(i = 0; devtab[i] != nil; i++)
137 		;
138 	if(i >= ndevs || devtab[i+1] != nil)
139 		error("device table full");
140 	l->dev = devtab[i] = dev;
141 	dev->init();
142 	l->next = loaded;
143 	loaded = l;
144 	poperror();
145 }
146 
147 static void
devunload(char * path)148 devunload(char *path)
149 {
150 	int i, dc;
151 	Dyndev *l, **ll;
152 
153 	dc = 0;
154 	if(strlen(path) == 1)
155 		dc = path[0];
156 	for(ll = &loaded; *ll != nil; ll = &(*ll)->next){
157 		if(path != nil && strcmp(path, (*ll)->path) == 0)
158 			break;
159 		if(dc != 0 && (*ll)->dev && dc == (*ll)->dev->dc)
160 			break;
161 	}
162 	if((l = *ll) != nil){
163 		for(i = 0; i < ndevs; i++)
164 			if(l->dev == devtab[i]){
165 				devtab[i] = nil;
166 				break;
167 			}
168 /*
169 		if(l->dev)
170 			l->dev->shutdown();
171 */
172 		*ll = l->next;
173 		dlfree(l);
174 	}
175 }
176 
177 static long
readdl(void * a,ulong n,ulong offset)178 readdl(void *a, ulong n, ulong offset)
179 {
180 	char *p;
181 	Dyndev *l;
182 	int m, len;
183 
184 	m = 0;
185 	for(l = loaded; l != nil; l = l->next)
186 		m++;
187 	m *= 48;
188 	p = malloc(m);
189 	if(p == nil)
190 		error(Enomem);
191 	if(waserror()){
192 		free(p);
193 		nexterror();
194 	}
195 	*p = 0;
196 	len = 0;
197 	for(l = loaded; l != nil; l = l->next)
198 		if(l->dev)
199 			len += snprint(p+len, m-len, "#%C\t%.8p\t%.8lux\t%s\n",
200 					l->dev->dc, l->o->base, l->o->size, l->dev->name);
201 	n = readstr(offset, a, n, p);
202 	poperror();
203 	free(p);
204 	return n;
205 }
206 
207 static long
readsyms(char * a,ulong n,ulong offset)208 readsyms(char *a, ulong n, ulong offset)
209 {
210 	char *p;
211 	Dynsym *t;
212 	long l, nr;
213 
214 	p = malloc(READSTR);
215 	if(p == nil)
216 		error(Enomem);
217 	if(waserror()){
218 		free(p);
219 		nexterror();
220 	}
221 	nr = 0;
222 	for(t = _exporttab; n > 0 && t->name != nil; t++){
223 		l = snprint(p, READSTR, "%.8lux %.8lux %s\n", t->addr, t->sig, t->name);
224 		if(offset >= l){
225 			offset -= l;
226 			continue;
227 		}
228 		l = readstr(offset, a, n, p);
229 		offset = 0;
230 		n -= l;
231 		a += l;
232 		nr += l;
233 	}
234 	poperror();
235 	free(p);
236 	return nr;
237 }
238 
239 static Chan*
dlattach(char * spec)240 dlattach(char *spec)
241 {
242 	return devattach(DEVCHAR, spec);
243 }
244 
245 static Walkqid*
dlwalk(Chan * c,Chan * nc,char ** name,int nname)246 dlwalk(Chan *c, Chan *nc, char **name, int nname)
247 {
248 	return devwalk(c, nc, name, nname, dltab, nelem(dltab), devgen);
249 }
250 
251 static int
dlstat(Chan * c,uchar * db,int n)252 dlstat(Chan *c, uchar *db, int n)
253 {
254 	return devstat(c, db, n, dltab, nelem(dltab), devgen);
255 }
256 
257 static Chan*
dlopen(Chan * c,int omode)258 dlopen(Chan *c, int omode)
259 {
260 	return devopen(c, omode, dltab, nelem(dltab), devgen);
261 }
262 
263 static void
dlclose(Chan * c)264 dlclose(Chan *c)
265 {
266 	USED(c);
267 }
268 
269 static long
dlread(Chan * c,void * a,long n,vlong voffset)270 dlread(Chan *c, void *a, long n, vlong voffset)
271 {
272 	switch((ulong)c->qid.path){
273 	case Qdir:
274 		return devdirread(c, a, n, dltab, nelem(dltab), devgen);
275 	case Qdynld:
276 		return readdl(a, n, (ulong)voffset);
277 	case Qdynsyms:
278 		return readsyms(a, n, (ulong)voffset);
279 	default:
280 		error(Egreg);
281 	}
282 	return n;
283 }
284 
285 static long
dlwrite(Chan * c,void * a,long n,vlong voffset)286 dlwrite(Chan *c, void *a, long n, vlong voffset)
287 {
288 	Cmdbuf *cmd;
289 	Cmdtab *ct;
290 
291 	USED(voffset);
292 	switch((ulong)c->qid.path){
293 	case Qdynld:
294 		cmd = parsecmd(a, n);
295 		qlock(&dllock);
296 		if(waserror()){
297 			qunlock(&dllock);
298 			free(cmd);
299 			nexterror();
300 		}
301 		ct = lookupcmd(cmd, dlcmd, nelem(dlcmd));
302 		switch(ct->index){
303 		case DLdev:
304 			devload(cmd->f[1]);
305 			break;
306 		case DLudev:
307 			devunload(cmd->f[1]);
308 			break;
309 		}
310 		poperror();
311 		qunlock(&dllock);
312 		free(cmd);
313 		break;
314 	default:
315 		error(Egreg);
316 	}
317 	return n;
318 }
319 
320 Dev dynlddevtab = {
321 	DEVCHAR,
322 	"dynld",
323 
324 	devinit,
325 	dlattach,
326 	dlwalk,
327 	dlstat,
328 	dlopen,
329 	devcreate,
330 	dlclose,
331 	dlread,
332 	devbread,
333 	dlwrite,
334 	devbwrite,
335 	devremove,
336 	devwstat,
337 };
338 
339 /* auxiliary routines for dynamic loading of C modules */
340 
341 Dynobj*
dynld(int fd)342 dynld(int fd)
343 {
344 	Fd f;
345 
346 	f.fd = fd;
347 	return dynloadgen(&f, readfd, seekfd, errfd, _exporttab, dyntabsize(_exporttab), 0);
348 }
349 
350 int
dynldable(int fd)351 dynldable(int fd)
352 {
353 	Fd f;
354 
355 	f.fd = fd;
356 	return dynloadable(&f, readfd, seekfd);
357 }
358