/[gxemul]/trunk/src/device.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/device.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 9097 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: device.c,v 1.14 2005/06/22 08:13:38 debug Exp $
29 *
30 * Device registry framework.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "device.h"
38 #include "misc.h"
39
40
41 static struct device_entry *device_entries = NULL;
42 static int device_entries_sorted = 0;
43 static int n_device_entries = 0;
44 static int device_exit_on_error = 1;
45
46
47 /*
48 * device_entry_compar():
49 *
50 * Internal function, used by sort_entries().
51 */
52 static int device_entry_compar(const void *a, const void *b)
53 {
54 struct device_entry *pa = (struct device_entry *) a;
55 struct device_entry *pb = (struct device_entry *) b;
56
57 return strcmp(pa->name, pb->name);
58 }
59
60
61 /*
62 * sort_entries():
63 *
64 * Internal function. Sorts the device_entries array in alphabetic order.
65 */
66 static void sort_entries(void)
67 {
68 qsort(device_entries, n_device_entries, sizeof(struct device_entry),
69 device_entry_compar);
70
71 device_entries_sorted = 1;
72 }
73
74
75 /*
76 * device_register():
77 *
78 * Registers a device. The device is added to the end of the device_entries
79 * array, and the sorted flag is set to zero.
80 *
81 * NOTE: It would be a bad thing if two devices had the same name. However,
82 * that isn't checked here, it is up to the caller!
83 *
84 * Return value is 1 if the device was registered, 0 otherwise.
85 */
86 int device_register(char *name, int (*initf)(struct devinit *))
87 {
88 device_entries = realloc(device_entries, sizeof(struct device_entry)
89 * (n_device_entries + 1));
90 if (device_entries == NULL) {
91 fprintf(stderr, "device_register(): out of memory\n");
92 exit(1);
93 }
94
95 memset(&device_entries[n_device_entries], 0,
96 sizeof(struct device_entry));
97
98 device_entries[n_device_entries].name = strdup(name);
99 device_entries[n_device_entries].initf = initf;
100
101 device_entries_sorted = 0;
102 n_device_entries ++;
103 return 1;
104 }
105
106
107 /*
108 * device_lookup():
109 *
110 * Lookup a device name by scanning the device_entries array (as a binary
111 * search tree).
112 *
113 * Return value is a pointer to the device_entry on success, or a NULL pointer
114 * if there was no such device.
115 */
116 struct device_entry *device_lookup(char *name)
117 {
118 int i, step, r, do_return = 0;
119
120 if (name == NULL) {
121 fprintf(stderr, "device_lookup(): NULL ptr\n");
122 exit(1);
123 }
124
125 if (!device_entries_sorted)
126 sort_entries();
127
128 if (n_device_entries == 0)
129 return NULL;
130
131 i = n_device_entries / 2;
132 step = i/2 + 1;
133
134 for (;;) {
135 if (i < 0)
136 i = 0;
137 if (i >= n_device_entries)
138 i = n_device_entries - 1;
139
140 /* printf("device_lookup(): i=%i step=%i\n", i, step);
141 printf(" name='%s', '%s'\n", name,
142 device_entries[i].name); */
143
144 r = strcmp(name, device_entries[i].name);
145
146 if (r < 0) {
147 /* Go left: */
148 i -= step;
149 if (step == 0)
150 i --;
151 } else if (r > 0) {
152 /* Go right: */
153 i += step;
154 if (step == 0)
155 i ++;
156 } else {
157 /* Found it! */
158 return &device_entries[i];
159 }
160
161 if (do_return)
162 return NULL;
163
164 if (step == 0)
165 do_return = 1;
166
167 if (step & 1)
168 step = (step/2) + 1;
169 else
170 step /= 2;
171 }
172 }
173
174
175 /*
176 * device_unregister():
177 *
178 * Unregisters a device.
179 *
180 * Return value is 1 if a device was unregistered, 0 otherwise.
181 */
182 int device_unregister(char *name)
183 {
184 size_t i;
185 struct device_entry *p = device_lookup(name);
186
187 if (p == NULL) {
188 fatal("device_unregister(): no such device (\"%s\")\n", name);
189 return 0;
190 }
191
192 i = (size_t)p - (size_t)device_entries;
193 i /= sizeof(struct device_entry);
194
195 free(device_entries[i].name);
196 device_entries[i].name = NULL;
197
198 if (i == n_device_entries-1) {
199 /* Do nothing if we're removing the last array element. */
200 } else {
201 /* Remove array element i by copying the last element
202 to i's position: */
203 device_entries[i] = device_entries[n_device_entries-1];
204
205 /* The array is not sorted anymore: */
206 device_entries_sorted = 0;
207 }
208
209 n_device_entries --;
210
211 /* TODO: realloc? */
212 return 1;
213 }
214
215
216 /*
217 * device_add():
218 *
219 * Add a device to a machine. For example: "kn210 addr=0x12340000" adds a
220 * device called "kn210" at a specific address.
221 *
222 * TODO: This function is quite ugly, and should be cleaned up.
223 */
224 void *device_add(struct machine *machine, char *name_and_params)
225 {
226 struct device_entry *p;
227 struct devinit devinit;
228 char *s2, *s3;
229 size_t len;
230
231 memset(&devinit, 0, sizeof(struct devinit));
232 devinit.machine = machine;
233
234 /* Default values: */
235 devinit.addr_mult = 1;
236
237 /* Get the device name first: */
238 s2 = name_and_params;
239 while (s2[0] != ',' && s2[0] != ' ' && s2[0] != '\0')
240 s2 ++;
241
242 len = (size_t)s2 - (size_t)name_and_params;
243 devinit.name = malloc(len + 1);
244 if (devinit.name == NULL) {
245 fprintf(stderr, "device_add(): out of memory\n");
246 exit(1);
247 }
248 memcpy(devinit.name, name_and_params, len);
249 devinit.name[len] = '\0';
250
251 p = device_lookup(devinit.name);
252 if (p == NULL) {
253 fatal("no such device (\"%s\")\n", devinit.name);
254 if (device_exit_on_error)
255 exit(1);
256 else
257 goto return_fail;
258 }
259
260 /* Get params from name_and_params: */
261 while (*s2 != '\0') {
262 /* Skip spaces, commas, and semicolons: */
263 while (*s2 == ' ' || *s2 == ',' || *s2 == ';')
264 s2 ++;
265
266 if (*s2 == '\0')
267 break;
268
269 /* s2 now points to the next param. eg "addr=1234" */
270
271 /* Get a word (until there is a '=' sign): */
272 s3 = s2;
273 while (*s3 != '=' && *s3 != '\0')
274 s3 ++;
275 if (s3 == s2) {
276 fatal("weird param: %s\n", s2);
277 if (device_exit_on_error)
278 exit(1);
279 else
280 goto return_fail;
281 }
282 s3 ++;
283 /* s3 now points to the parameter value ("1234") */
284
285 if (strncmp(s2, "addr=", 5) == 0) {
286 devinit.addr = mystrtoull(s3, NULL, 0);
287 } else if (strncmp(s2, "len=", 4) == 0) {
288 devinit.len = mystrtoull(s3, NULL, 0);
289 } else if (strncmp(s2, "addr_mult=", 10) == 0) {
290 devinit.addr_mult = mystrtoull(s3, NULL, 0);
291 } else if (strncmp(s2, "irq=", 4) == 0) {
292 devinit.irq_nr = mystrtoull(s3, NULL, 0);
293 } else {
294 fatal("unknown param: %s\n", s2);
295 if (device_exit_on_error)
296 exit(1);
297 else
298 goto return_fail;
299 }
300
301 /* skip to the next param: */
302 s2 = s3;
303 while (*s2 != '\0' && *s2 != ' ' && *s2 != ',' && *s2 != ';')
304 s2 ++;
305 }
306
307
308 /*
309 * Call the init function for this device:
310 */
311
312 devinit.return_ptr = NULL;
313
314 if (!p->initf(&devinit)) {
315 fatal("error adding device (\"%s\")\n", name_and_params);
316 if (device_exit_on_error)
317 exit(1);
318 else
319 goto return_fail;
320 }
321
322 free(devinit.name);
323 return devinit.return_ptr;
324
325 return_fail:
326 free(devinit.name);
327 return NULL;
328 }
329
330
331 /*
332 * device_dumplist():
333 *
334 * Dump a list of all registered devices. (If the list is not sorted when
335 * this function is called, it is implicitly sorted.)
336 */
337 void device_dumplist(void)
338 {
339 int i;
340
341 if (!device_entries_sorted)
342 sort_entries();
343
344 for (i=0; i<n_device_entries; i++) {
345 debug(" %s", device_entries[i].name);
346
347 /* TODO: flags? */
348
349 debug("\n");
350 }
351 }
352
353
354 /*
355 * device_set_exit_on_error():
356 *
357 * This function selects the behaviour of the emulator when a device is not
358 * found. During startup, it is nicest to abort the whole emulator session,
359 * but if a device addition is attempted from within the debugger, then it is
360 * nicer to just print a warning and continue.
361 */
362 void device_set_exit_on_error(int exit_on_error)
363 {
364 device_exit_on_error = exit_on_error;
365 }
366
367
368 /*
369 * device_init():
370 *
371 * Initialize the device registry, and call autodev_init() to automatically
372 * add all normal devices (from the src/devices/ directory).
373 *
374 * This function should be called before any other device_*() function is used.
375 */
376 void device_init(void)
377 {
378 device_entries = NULL;
379 device_entries_sorted = 0;
380 n_device_entries = 0;
381
382 autodev_init();
383 }
384

  ViewVC Help
Powered by ViewVC 1.1.26