xref: /inferno-os/emu/Nt/devarch.c (revision d3641b487cf5cdc46e9b537d30eb37736e5c7b1a)
1 /*
2  *  platform-specific interface
3  */
4 
5 #define Unknown win_Unknown
6 #define UNICODE
7 #include	<windows.h>
8 #include <winbase.h>
9 #include	<winsock.h>
10 #undef Unknown
11 #include	"dat.h"
12 #include	"fns.h"
13 #include	"error.h"
14 #include	"r16.h"
15 
16 enum{
17 	Qdir,
18 	Qarchctl,
19 	Qcputype,
20 	Qregquery,
21 	Qhostmem
22 };
23 
24 static
25 Dirtab archtab[]={
26 	".",		{Qdir, 0, QTDIR},	0,	0555,
27 	"archctl",	{Qarchctl, 0},	0,	0444,
28 	"cputype",	{Qcputype},	0,	0444,
29 	"regquery",	{Qregquery}, 0,	0666,
30 	"hostmem",	{Qhostmem},	0,	0444,
31 };
32 
33 typedef struct Value Value;
34 struct Value {
35 	int	type;
36 	int	size;
37 	union {
38 		ulong	w;
39 		vlong	q;
40 		char	data[1];	/* utf-8 */
41 	};
42 };
43 
44 typedef struct Regroot Regroot;
45 struct Regroot {
46 	char*	name;
47 	HKEY	root;
48 };
49 
50 static Regroot roots[] = {
51 	{"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
52 	{"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG},
53 	{"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
54 	{"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
55 	{"HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA},
56 	{"HKEY_USERS", HKEY_USERS},
57 };
58 
59 static struct {
60 	ulong	mhz;
61 	int ncpu;
62 	char	cpu[64];
63 } arch;
64 
65 static	QLock	reglock;
66 
67 static	Value*	getregistry(HKEY, Rune16*, Rune16*);
68 static int nprocs(void);
69 
70 static void
71 archinit(void)
72 {
73 	Value *v;
74 	char *p;
75 
76 	v = getregistry(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"ProcessorNameString");
77 	if(v != nil){
78 		snprint(arch.cpu, sizeof(arch.cpu), "%s", v->data);
79 		if((p = strrchr(arch.cpu, ' ')) != nil)
80 			for(; p >= arch.cpu && *p == ' '; p--)
81 				*p = '\0';
82 		free(v);
83 	}else{
84 		v = getregistry(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"VendorIdentifier");
85 		if(v != nil){
86 			snprint(arch.cpu, sizeof(arch.cpu), "%s", v->data);
87 			free(v);
88 		}else
89 			snprint(arch.cpu, sizeof(arch.cpu), "unknown");
90 	}
91 	v = getregistry(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"~MHz");
92 	if(v != nil){
93 		arch.mhz = v->w;
94 		free(v);
95 	}
96 	arch.ncpu = nprocs();
97 }
98 
99 static int
100 nprocs(void)
101 {
102 	int n;
103 	char *p;
104 	Rune16 *r;
105 	Value *v;
106 	n = 0;
107 	for(;;){
108 		p = smprint("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", n);
109 		if(waserror()){
110 			free(p);
111 			nexterror();
112 		}
113 		r = widen(p);
114 		free(p);
115 		v = getregistry(HKEY_LOCAL_MACHINE, r, L"~MHz");
116 		free(r);
117 		if(v == nil)
118 			break;
119 		free(v);
120 		n++;
121 	}
122 	return n;
123 }
124 
125 static Chan*
126 archattach(char* spec)
127 {
128 	return devattach('a', spec);
129 }
130 
131 static Walkqid*
132 archwalk(Chan *c, Chan *nc, char **name, int nname)
133 {
134 	return devwalk(c, nc, name, nname, archtab, nelem(archtab), devgen);
135 }
136 
137 static int
138 archstat(Chan* c, uchar *db, int n)
139 {
140 	return devstat(c, db, n, archtab, nelem(archtab), devgen);
141 }
142 
143 static Chan*
144 archopen(Chan* c, int omode)
145 {
146 	return devopen(c, omode, archtab, nelem(archtab), devgen);
147 }
148 
149 static void
150 archclose(Chan* c)
151 {
152 	if((ulong)c->qid.path == Qregquery && c->aux != nil)
153 		free(c->aux);
154 }
155 
156 static long
157 archread(Chan* c, void* a, long n, vlong offset)
158 {
159 	char *p;
160 	Value *v;
161 	int i, l;
162 	MEMORYSTATUS mem;
163 
164 	switch((ulong)c->qid.path){
165 	case Qdir:
166 		return devdirread(c, a, n, archtab, nelem(archtab), devgen);
167 	case Qarchctl:
168 	case Qcputype:
169 		l = 0;
170 		if((ulong)c->qid.path == Qcputype)
171 			l = 4;
172 		p = smalloc(READSTR);
173 		if(waserror()){
174 			free(p);
175 			nexterror();
176 		}
177 		snprint(p, READSTR, "cpu %q %lud %d\n", arch.cpu, arch.mhz, arch.ncpu);
178 		n = readstr(offset, a, n, p+l);
179 		poperror();
180 		free(p);
181 		break;
182 	case Qregquery:
183 		v = c->aux;
184 		if(v == nil)
185 			return 0;
186 		p = smalloc(READSTR);
187 		if(waserror()){
188 			free(p);
189 			nexterror();
190 		}
191 		switch(v->type){
192 		case REG_NONE:
193 			n = readstr(offset, a, n, "nil");
194 			break;
195 		case REG_DWORD:
196 			snprint(p, READSTR, "int %ld", v->w);
197 			n = readstr(offset, a, n, p);
198 			break;
199 #ifdef REG_QWORD
200 		case REG_QWORD:
201 			snprint(p, READSTR, "int %lld", v->q);
202 			n = readstr(offset, a, n, p);
203 			break;
204 #endif
205 		case REG_SZ:
206 		case REG_EXPAND_SZ:
207 			if(v->data[0])
208 				snprint(p, READSTR, "str %q", v->data);
209 			n = readstr(offset, a, n, p);
210 			break;
211 		case REG_MULTI_SZ:
212 			l = snprint(p, READSTR, "str");
213 			for(i=0;;){
214 				l += snprint(p+l, READSTR-l, " %q", v->data+i);
215 				while(v->data[i++] != 0){
216 					/* skip */
217 				}
218 				if(v->data[i] == 0)
219 					break;	/* final terminator */
220 			}
221 			n = readstr(offset, a, n, p);
222 			break;
223 		case REG_BINARY:
224 			l = n;
225 			n = readstr(offset, a, l, "bin");
226 			if(n >= 3){
227 				offset -= 3;
228 				if(offset+l > v->size)
229 					l = v->size - offset;
230 				memmove((char*)a+n, v->data+offset, l);
231 				n += l;
232 			}
233 			break;
234 		default:
235 			error("unknown registry type");
236 			n=0;
237 			break;
238 		}
239 		poperror();
240 		free(p);
241 		c->aux = nil;
242 		free(v);
243 		break;
244 	case Qhostmem:
245 		mem.dwLength = sizeof(mem);
246 		GlobalMemoryStatus(&mem);	/* GlobalMemoryStatusEx isn't on NT */
247 		p = smalloc(READSTR);
248 		if(waserror()){
249 			free(p);
250 			nexterror();
251 		}
252 		snprint(p, READSTR, "load %ld\nphys %lud %lud\nvirt %lud %lud\nswap %lud %lud\n",
253 			mem.dwMemoryLoad,
254 			mem.dwAvailPhys, mem.dwTotalPhys, mem.dwAvailVirtual, mem.dwTotalVirtual,
255 			mem.dwAvailPageFile, mem.dwTotalPageFile);
256 		n = readstr(offset, a, n, p);
257 		poperror();
258 		free(p);
259 		break;
260 	default:
261 		n=0;
262 		break;
263 	}
264 	return n;
265 }
266 
267 static long
268 archwrite(Chan* c, void* a, long n, vlong offset)
269 {
270 	Value *v;
271 	int i;
272 	Cmdbuf *cb;
273 	Rune16 *key, *item;
274 
275 	if((ulong)c->qid.path != Qregquery)
276 		error(Eperm);
277 	USED(offset);
278 	if(c->aux != nil){
279 		free(c->aux);
280 		c->aux = nil;
281 	}
282 	cb = parsecmd(a, n);
283 	if(waserror()){
284 		free(cb);
285 		nexterror();
286 	}
287 	if(cb->nf < 3)
288 		error(Ebadctl);
289 	for(i=0; i<nelem(roots); i++)
290 		if(strcmp(cb->f[0], roots[i].name) == 0)
291 			break;
292 	if(i >= nelem(roots))
293 		errorf("unknown root: %s", cb->f[0]);
294 	key = widen(cb->f[1]);
295 	if(waserror()){
296 		free(key);
297 		nexterror();
298 	}
299 	item = widen(cb->f[2]);
300 	if(waserror()){
301 		free(item);
302 		nexterror();
303 	}
304 	v = getregistry(roots[i].root, key, item);
305 	if(v == nil)
306 		error(up->env->errstr);
307 	c->aux = v;
308 	poperror();
309 	free(item);
310 	poperror();
311 	free(key);
312 	poperror();
313 	free(cb);
314 	return n;
315 }
316 
317 Dev archdevtab = {
318 	'a',
319 	"arch",
320 
321 	archinit,
322 	archattach,
323 	archwalk,
324 	archstat,
325 	archopen,
326 	devcreate,
327 	archclose,
328 	archread,
329 	devbread,
330 	archwrite,
331 	devbwrite,
332 	devremove,
333 	devwstat,
334 };
335 
336 static void
337 regerr(int rc)
338 {
339 	Rune16 err[64];
340 	char emsg[sizeof(err)*UTFmax+1];
341 
342 	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
343 		0, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
344 		err, sizeof(err), 0);
345 	runes16toutf(emsg, err, nelem(err));
346 	error(emsg);
347 }
348 
349 static Value*
350 getregistry(HKEY root, Rune16 *keyname, Rune16 *name)
351 {
352 	long res;
353 	HKEY key;
354 	DWORD dtype, n;
355 	int i, l, nb;
356 	void* vp;
357 	char *p;
358 	Value *val;
359 	Rune16 *rb;
360 
361 	qlock(&reglock);
362 	if(waserror()){
363 		qunlock(&reglock);
364 		return nil;
365 	}
366 	res = RegOpenKey(root, keyname, &key);
367 	if(res != ERROR_SUCCESS)
368 		regerr(res);
369 	if(waserror()){
370 		RegCloseKey(key);
371 		nexterror();
372 	}
373 	n = 0;
374 	res = RegQueryValueEx(key, name, NULL, &dtype, NULL, &n);
375 	if(res != ERROR_SUCCESS)
376 		regerr(res);
377 	nb = n;
378 	if(dtype == REG_SZ || dtype == REG_EXPAND_SZ || dtype == REG_MULTI_SZ){
379 		nb = n*UTFmax + 1;
380 		rb = smalloc((n+2)*sizeof(Rune16));
381 		memset(rb, 0, (n+2)*sizeof(Rune16));
382 	}else
383 		rb = nil;
384 	if(waserror()){
385 		free(rb);
386 		nexterror();
387 	}
388 	val = smalloc(sizeof(Value)+nb);
389 	if(waserror()){
390 		free(val);
391 		nexterror();
392 	}
393 	val->type = dtype;
394 	val->size = n;
395 	switch(dtype){
396 	case REG_DWORD:
397 		vp = &val->w;
398 		break;
399 #ifdef REG_QWORD
400 	case REG_QWORD:
401 		vp = &val->q;
402 		break;
403 #endif
404 	case REG_SZ:
405 	case REG_EXPAND_SZ:
406 	case REG_MULTI_SZ:
407 		vp = rb;
408 		break;
409 	case REG_BINARY:
410 	case REG_NONE:
411 		vp = val->data;
412 		break;
413 	default:
414 		errorf("unsupported registry type: %d", dtype);
415 		return nil;	/* for compiler */
416 	}
417 	res = RegQueryValueEx(key, name, NULL, NULL, vp, &n);
418 	if(res != ERROR_SUCCESS)
419 		regerr(res);
420 	poperror();
421 	if(rb != nil){
422 		if(dtype == REG_MULTI_SZ){
423 			p = val->data;
424 			for(i=0;;){
425 				l = runes16len(rb+i);
426 				runes16toutf(p, rb+i, l);
427 				i += l+1;
428 				if(rb[i] == 0)
429 					break;
430 				p += strlen(p)+1;
431 			}
432 		}else
433 			runes16toutf(val->data, rb, n);
434 		free(rb);
435 	}
436 	poperror();
437 	poperror();
438 	RegCloseKey(key);
439 	poperror();
440 	qunlock(&reglock);
441 	return val;
442 }
443