/[gxemul]/trunk/doc/technical.html
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/doc/technical.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (show annotations)
Mon Oct 8 16:18:19 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/html
File size: 21755 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.777 2005/06/12 12:31:52 debug Exp $
==============  RELEASE 0.3.3.1  ==============

20050609	Adding simple MIPS IPIs (to dev_mp).
20050611	Adding an ugly hack to track down low-reference bugs
		(define TRACE_NULL_CRASHES, or configure --tracenull).
		Other minor updates.
20050612	Adding a dummy evbmips mode.

==============  RELEASE 0.3.3.2  ==============


1 <html><head><title>GXemul documentation: Technical details</title>
2 <meta name="robots" content="noarchive,nofollow,noindex"></head>
3 <body bgcolor="#f8f8f8" text="#000000" link="#4040f0" vlink="#404040" alink="#ff0000">
4 <table border=0 width=100% bgcolor="#d0d0d0"><tr>
5 <td width=100% align=center valign=center><table border=0 width=100%><tr>
6 <td align="left" valign=center bgcolor="#d0efff"><font color="#6060e0" size="6">
7 <b>GXemul documentation:</b></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
8 <font color="#000000" size="6"><b>Technical details</b>
9 </font></td></tr></table></td></tr></table><p>
10
11 <!--
12
13 $Id: technical.html,v 1.51 2005/06/04 22:47:49 debug Exp $
14
15 Copyright (C) 2004-2005 Anders Gavare. All rights reserved.
16
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions are met:
19
20 1. Redistributions of source code must retain the above copyright
21 notice, this list of conditions and the following disclaimer.
22 2. Redistributions in binary form must reproduce the above copyright
23 notice, this list of conditions and the following disclaimer in the
24 documentation and/or other materials provided with the distribution.
25 3. The name of the author may not be used to endorse or promote products
26 derived from this software without specific prior written permission.
27
28 THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 SUCH DAMAGE.
39
40 -->
41
42
43 <a href="./">Back to the index</a>
44
45 <p><br>
46 <h2>Technical details</h2>
47
48 <p>
49 This page describes some of the internals of GXemul.
50
51 <p>
52 <font color="#e00000"><b>NOTE: This page is probably not
53 very up-to-date by now.</b></font>
54
55 <p>
56 <ul>
57 <li><a href="#overview">Overview</a>
58 <li><a href="#speed">Speed</a>
59 <li><a href="#net">Networking</a>
60 <li><a href="#devices">Emulation of hardware devices</a>
61 <li><a href="#regtest">Regression tests</a>
62 </ul>
63
64
65
66
67 <p><br>
68 <a name="overview"></a>
69 <h3>Overview</h3>
70
71 In simple terms, GXemul is just a simple fetch-and-execute
72 loop; an instruction is fetched from memory, and executed.
73
74 <p>
75 In reality, a lot of things need to be handled. Before each instruction is
76 executed, the emulator checks to see if any interrupts are asserted which
77 are not masked away. If so, then an INT exception is generated. Exceptions
78 cause the program counter to be set to a specific value, and some of the
79 system coprocessor's registers to be set to values signifying what kind of
80 exception it was (an interrupt exception in this case).
81
82 <p>
83 Reading instructions from memory is done through a TLB, a translation
84 lookaside buffer. The TLB on MIPS is software controlled, which means that
85 the program running inside the emulator (for example an operating system
86 kernel) has to take care of manually updating the TLB. Some memory
87 addresses are translated into physical addresses directly, some are
88 translated into valid physical addresses via the TLB, and some memory
89 references are not valid. Invalid memory references cause exceptions.
90
91 <p>
92 After an instruction has been read from memory, the emulator checks which
93 opcode it contains and executes the instruction. Executing an instruction
94 usually involves reading some register and writing some register, or perhaps a
95 load from memory (or a store to memory). The program counter is increased
96 for every instruction.
97
98 <p>
99 Some memory references point to physical addresses which are not in the
100 normal RAM address space. They may point to hardware devices. If that is
101 the case, then loads and stores are converted into calls to a device
102 access function. The device access function is then responsible for
103 handling these reads and writes. For example, a graphical framebuffer
104 device may put a pixel on the screen when a value is written to it, or a
105 serial controller device may output a character to stdout when written to.
106
107
108
109
110 <p><br>
111 <a name="speed"></a>
112 <h3>Speed</h3>
113
114 There are two modes in which the emulator can run, <b>a</b>) a straight forward
115 loop which fetches one instruction from emulated RAM and executes it
116 (described in the previous section), and <b>b</b>)
117 using dynamic binary translation.
118
119 <p>
120 Mode <b>a</b> is very slow. On a 2.8 GHz Intel Xeon host the resulting
121 emulated machine is rougly equal to a 7 MHz R3000 (or a 3.5 MHz R4000).
122 The actual performance varies a lot, maybe between 5 and 10 million
123 instructions per second, depending on workload.
124
125 <p>
126 Mode <b>b</b> ("bintrans") is still to be considered experimental, but
127 gives higher performance than mode <b>a</b>. It translates MIPS machine
128 code into machine code that can be executed on the host machine
129 on-the-fly. The translation itself obviously takes some time, but this is
130 usually made up for by the fact that the translated code chunks are
131 executed multiple times.
132 To run the emulator with binary translation enabled, just add
133 <tt><b>-b</b></tt> to the command line.
134
135 <p>
136 Only small pieces of MIPS machine code are translated, usually the size of
137 a function, or less. There is no "intermediate representation" code, so
138 all translations are done directly from MIPS to host machine code.
139
140 <p>
141 The default bintrans cache size is 16 MB, but you can change this by adding
142 <tt>-DDEFAULT_BINTRANS_SIZE_IN_MB=<i>xx</i></tt> to your CFLAGS environment
143 variable before running the configure script, or by using the
144 <tt>bintrans_size()</tt> configuration file option when running the emulator.
145
146 <p>
147 By default, an emulated OS running under DECstation emulation which listens to
148 interrupts from the mc146818 clock will get interrupts that are close to the
149 host's clock. That is, if the emulated OS says it wants 100 interrupts per
150 second, it will get approximately 100 interrupts per real second.
151
152 <p>
153 There is however a <tt><b>-I</b></tt> option, which sets the number of
154 emulated cycles per seconds to a fixed value. Let's say you wish to make the
155 emulated OS think it is running on a 40 MHz DECstation, and not a 7 MHz one,
156 then you can add <tt><b>-I 40000000</b></tt> to the command line. This will not
157 make the emulation faster, of course. It might even make it seem slower; for
158 example, if NetBSD/pmax waits 2 seconds for SCSI devices to settle during
159 bootup, those 2 seconds will take 2*40000000 cycles (which will take more
160 time than 2*7000000).
161
162 <p>
163 The <b><tt>-I</tt></b> option is also necessary if you want to run
164 deterministic experiments, if a mc146818 (or similar) device is present.
165
166 <p>
167 Some emulators make claims such as "x times slowdown," but in the case of
168 GXemul, the host is often not a MIPS-based machine, and hence comparing
169 one MIPS instruction to a host instruction doesn't work. Performance depends on
170 a lot of factors, including (but not limited to) host architecture, host speed,
171 which compiler and compiler flags were used to build GXemul, what the
172 workload is, and so on. For example, if an emulated operating system tries
173 to read a block from disk, from its point of view the read was instantaneous
174 (no waiting). So 1 MIPS in an emulated OS might have taken more than one
175 million instructions on a real machine. Because of this, imho it is best
176 to measure performance as the actual (real-world) time it takes to perform
177 a task with the emulator.
178
179
180
181
182 <p><br>
183 <a name="net"></a>
184 <h3>Networking</h3>
185
186 Running an entire operating system under emulation is very interesting in
187 itself, but for several reasons, running a modern OS without access to
188 TCP/IP networking is a bit akward. Hence, I feel the need to implement TCP/IP
189 (networking) support in the emulator.
190
191 <p>
192 As far as I have understood it, there seems to be two different ways to go:
193
194 <ol>
195 <li>Forward ethernet packets from the emulated ethernet controller to
196 the host machine's ethernet controller, and capture incoming
197 packets on the host's controller, giving them back to the
198 emulated OS. Characteristics are:
199 <ul>
200 <li>Requires <i>direct</i> access to the host's NIC, which
201 means on most platforms that the emulator cannot be
202 run as a normal user!
203 <li>Reduced portability, as not every host operating system
204 uses the same programming interface for dealing with
205 hardware ethernet controllers directly.
206 <li>When run on a switched network, it might be problematic to
207 connect from the emulated OS to the OS running on the
208 host, as packets sent out on the host's NIC are not
209 received by itself. (?)
210 <li>All specific networking protocols will be handled by the
211 physical network.
212 </ul>
213 <p>
214 or
215 <p>
216 <li>Whenever the emulated ethernet controller wishes to send a packet,
217 the emulator looks at the packet and creates a response. Packets
218 that can have an immediate response never go outside the emulator,
219 other packet types have to be converted into suitable other
220 connection types (UDP, TCP, etc). Characteristics:
221 <ul>
222 <li>Each packet type sent out on the emulated NIC must be handled.
223 This means that I have to do a lot of coding.
224 (I like this, because it gives me an opportunity to
225 learn about networking protocols.)
226 <li>By not relying on access to the host's NIC directly,
227 portability is maintained. (It would be sad if the networking
228 portion of a portable emulator isn't as portable as the
229 rest of the emulator.)
230 <li>The emulator can be run as a normal user process, does
231 not require root privilegies.
232 <li>Connecting from the emulated OS to the host's OS should
233 not be problematic.
234 <li>The emulated OS will experience the network just as a single
235 machine behind a NAT gateway/firewall would. The emulated
236 OS is thus automatically protected from the outside world.
237 </ul>
238 </ol>
239
240 <p>
241 Some emulators/simulators use the first approach, while others use the
242 second. I think that SIMH and QEMU are examples of emulators using the
243 first and second approach, respectively.
244
245 <p>
246 Since I have choosen the second kind of implementation, I have to write
247 support explicitly for any kind of network protocol that should be
248 supported. As of 2004-07-09, the following has been implemented and seems
249 to work under at least NetBSD/pmax and OpenBSD/pmax under DECstation 5000/200
250 emulation (-E dec -e 3max):
251
252 <p>
253 <ul>
254 <li>ARP requests sent out from the emulated NIC are interpreted,
255 and converted to ARP responses. (This is used by the emulated OS
256 to find out the MAC address of the gateway.)
257 <li>ICMP echo requests (that is the kind of packet produced by the
258 <b><tt>ping</tt></b> program) are interpreted and converted to ICMP echo
259 replies, <i>regardless of the IP address</i>. This means that
260 running ping from within the emulated OS will <i>always</i>
261 receive a response. The ping packets never leave the emulated
262 environment.
263 <li>UDP packets are interpreted and passed along to the outside world.
264 If the emulator receives an UDP packet from the outside world, it
265 is converted into an UDP packet for the emulated OS. (This is not
266 implemented very well yet, but seems to be enough for nameserver
267 lookups, tftp file transfers, and NFS mounts using UDP.)
268 <li>TCP packets are interpreted one at a time, similar to how UDP
269 packets are handled (but more state is kept for each connection).
270 <font color="#ff0000">NOTE: Much of the TCP handling code is very
271 ugly and hardcoded.</font>
272 <!--
273 <li>RARP is not implemented yet. (I haven't needed it so far.)
274 -->
275 </ul>
276
277 <p>
278 The gateway machine, which is the only "other" machine that the emulated
279 OS sees on its emulated network, works as a NAT-style firewall/gateway. It
280 usually has a fixed IPv4 address of <tt>10.0.0.254</tt>. An OS running in
281 the emulator would usually have an address of the form <tt>10.x.x.x</tt>;
282 a typical choice would be <tt>10.0.0.1</tt>.
283
284 <p>
285 Inside emulated NetBSD/pmax or OpenBSD/pmax, running the following
286 commands should configure the emulated NIC:
287 <pre>
288 # <b>ifconfig le0 10.0.0.1</b>
289 # <b>route add default 10.0.0.254</b>
290 add net default: gateway 10.0.0.254
291 </pre>
292
293 <p>
294 If you want nameserver lookups to work, you need a valid /etc/resolv.conf
295 as well:
296 <pre>
297 # <b>echo nameserver 129.16.1.3 > /etc/resolv.conf</b>
298 </pre>
299 (But replace <tt>129.16.1.3</tt> with the actual real-world IP address of
300 your nearest nameserver.)
301
302 <p>
303 Now, host lookups should work:
304 <pre>
305 # <b>host -a www.netbsd.org</b>
306 Trying null domain
307 rcode = 0 (Success), ancount=2
308 The following answer is not authoritative:
309 The following answer is not verified as authentic by the server:
310 www.netbsd.org 86400 IN AAAA 2001:4f8:4:7:290:27ff:feab:19a7
311 www.netbsd.org 86400 IN A 204.152.184.116
312 For authoritative answers, see:
313 netbsd.org 83627 IN NS uucp-gw-2.pa.dec.com
314 netbsd.org 83627 IN NS ns.netbsd.org
315 netbsd.org 83627 IN NS adns1.berkeley.edu
316 netbsd.org 83627 IN NS adns2.berkeley.edu
317 netbsd.org 83627 IN NS uucp-gw-1.pa.dec.com
318 Additional information:
319 ns.netbsd.org 83627 IN A 204.152.184.164
320 uucp-gw-1.pa.dec.com 172799 IN A 204.123.2.18
321 uucp-gw-2.pa.dec.com 172799 IN A 204.123.2.19
322 </pre>
323
324 <p>
325 At this point, UDP and TCP should (mostly) work.
326
327 <p>
328 Here is an example of how to configure a server machine and an emulated
329 client machine for sharing files via NFS:
330
331 <p>
332 (This is very useful if you want to share entire directory trees
333 between the emulated environment and another machine. These instruction
334 will work for FreeBSD, if you are running something else, use your
335 imagination to modify them.)
336
337 <p>
338 <ul>
339 <li>On the server, add a line to your /etc/exports file, exporting
340 the files you wish to use in the emulator:<pre>
341 <b>/tftpboot -mapall=nobody -ro 123.11.22.33</b>
342 </pre>
343 where 123.11.22.33 is the IP address of the machine running the
344 emulator process, as seen from the outside world.
345 <p>
346 <li>Then start up the programs needed to serve NFS via UDP. Note the
347 -n argument to mountd. This is needed to tell mountd to accept
348 connections from unprivileged ports (because the emulator does
349 not need to run as root).<pre>
350 # <b>portmap</b>
351 # <b>nfsd -u</b> &lt;--- u for UDP
352 # <b>mountd -n</b>
353 </pre>
354 <li>In the guest OS in the emulator, once you have ethernet and IPv4
355 configured so that you can use UDP, mounting the filesystem
356 should now be possible: (this example is for NetBSD/pmax
357 or OpenBSD/pmax)<pre>
358 # <b>mount -o ro,-r=1024,-w=1024,-U,-3 my.server.com:/tftpboot /mnt</b>
359 or
360 # <b>mount my.server.com:/tftpboot /mnt</b>
361 </pre>
362 If you don't supply the read and write sizes, there is a risk
363 that the default values are too large. The emulator currently
364 does not handle fragmentation/defragmentation of <i>outgoing</i>
365 packets, so going above the ethernet frame size (1518) is a very
366 bad idea. Incoming packets (reading from nfs) should work, though,
367 for example during an NFS install.
368 </ul>
369
370 The example above uses read-only mounts. That is enough for things like
371 letting NetBSD/pmax or OpenBSD/pmax install via NFS, without the need for
372 a CDROM ISO image. You can use a read-write mount if you wish to share
373 files in both directions, but then you should be aware of the
374 fragmentation issue mentioned above.
375
376
377
378
379
380 <p><br>
381 <a name="devices"></a>
382 <h3>Emulation of hardware devices</h3>
383
384 Each file in the device/ directory is responsible for one hardware device.
385 These are used from src/machine.c, when initializing which hardware a
386 particular machine model will be using, or when adding devices to a
387 machine using the <b>device()</b> command in configuration files.
388
389 <p>
390 <font color="#ff0000">NOTE: 2005-02-26: I'm currently rewriting the
391 device registry subsystem.</font>
392
393 <p>
394 (I'll be using the name 'foo' as the name of the device in all these
395 examples. This is pseudo code, it might need some modification to
396 actually compile and run.)
397
398 <p>
399 Each device should have the following:
400
401 <p>
402 <ul>
403 <li>A devinit function in dev_foo.c. It would typically look
404 something like this:
405 <pre>
406 /*
407 * devinit_foo():
408 */
409 int devinit_foo(struct devinit *devinit)
410 {
411 struct foo_data *d = malloc(sizeof(struct foo_data));
412
413 if (d == NULL) {
414 fprintf(stderr, "out of memory\n");
415 exit(1);
416 }
417 memset(d, 0, sizeof(struct foon_data));
418
419 /*
420 * Set up stuff here, for example fill d with useful
421 * data. devinit contains settings like address, irq_nr,
422 * and other things.
423 *
424 * ...
425 */
426
427 memory_device_register(devinit->machine->memory, devinit->name,
428 devinit->addr, DEV_FOO_LENGTH,
429 dev_foo_access, (void *)d, MEM_DEFAULT, NULL);
430
431 /* This should only be here if the device
432 has a tick function: */
433 machine_add_tickfunction(machine, dev_foo_tick, d,
434 FOO_TICKSHIFT);
435
436 /* Return 1 if the device was successfully added. */
437 return 1;
438 }
439 </pre><br>
440
441 <li>At the top of dev_foo.c, the foo_data struct should be defined.
442 <pre>
443 struct foo_data {
444 int irq_nr;
445 /* ... */
446 }
447 </pre><br>
448
449 <li>If foo has a tick function (that is, something that needs to be
450 run at regular intervals) then FOO_TICKSHIFT and a tick function
451 need to be defined as well:
452 <pre>
453 #define FOO_TICKSHIFT 10
454
455 void dev_foo_tick(struct cpu *cpu, void *extra)
456 {
457 struct foo_data *d = (struct foo_data *) extra;
458
459 if (.....)
460 cpu_interrupt(cpu, d->irq_nr);
461 else
462 cpu_interrupt_ack(cpu, d->irq_nr);
463 }
464 </pre><br>
465
466 <li>And last but not least, the device should have an access function.
467 The access function is called whenever there is a load or store
468 to an address which is in the device' memory mapped region.
469 <pre>
470 int dev_foo_access(struct cpu *cpu, struct memory *mem,
471 uint64_t relative_addr, unsigned char *data, size_t len,
472 int writeflag, void *extra)
473 {
474 struct foo_data *d = extra;
475 uint64_t idata = 0, odata = 0;
476
477 idata = memory_readmax64(cpu, data, len);
478 switch (relative_addr) {
479 /* .... */
480 }
481
482 if (writeflag == MEM_READ)
483 memory_writemax64(cpu, data, len, odata);
484
485 /* Perhaps interrupts need to be asserted or
486 deasserted: */
487 dev_foo_tick(cpu, extra);
488
489 /* Return successfully. */
490 return 1;
491 }
492 </pre><br>
493 </ul>
494
495 <p>
496 The return value of the access function has until 2004-07-02 been a
497 true/false value; 1 for success, or 0 for device access failure. A device
498 access failure (on MIPS) will result in a DBE exception.
499
500 <p>
501 Some devices are converted to support arbitrary memory latency
502 values. The return value is the number of cycles that the read or
503 write access took. A value of 1 means one cycle, a value of 10 means 10
504 cycles. Negative values are used for device access failures, and the
505 absolute value of the value is then the number of cycles; a value of -5
506 means that the access failed, and took 5 cycles.
507
508 <p>
509 To be compatible with pre-20040702 devices, a return value of 0 is treated
510 by the caller (in <tt>src/memory_rw.c</tt>) as a value of -1.
511
512
513
514
515
516 <p><br>
517 <a name="regtest"></a>
518 <h3>Regression tests</h3>
519
520 In order to make sure that the emulator actually works like it is supposed
521 to, it must be tested. For this purpose, there is a simple regression
522 testing framework in the <tt>tests/</tt> directory.
523
524 <p>
525 <i>NOTE: The regression testing framework is basically just a skeleton so far.
526 Regression tests are very good to have. However, the fact that complete
527 operating systems can run in the emulator indicate that the emulation is
528 probably not too incorrect. This makes it less of a priority to write
529 regression tests.</i>
530
531 <p>
532 To run all the regression tests, type <tt>make regtest</tt>. Each assembly
533 language file matching the pattern <tt>test_*.S</tt> will be compiled and
534 linked into a 64-bit MIPS ELF (using a gcc cross compiler), and run in the
535 emulator. If everything goes well, you should see something like this:
536
537 <pre>
538 $ make regtest
539 cd tests; make run_tests; cd ..
540 gcc33 -Wall -fomit-frame-pointer -fmove-all-movables -fpeephole -O2
541 -mcpu=ev5 -I/usr/X11R6/include -lm -L/usr/X11R6/lib -lX11 do_tests.c
542 -o do_tests
543 do_tests.c: In function `main':
544 do_tests.c:173: warning: unused variable `s'
545 /var/tmp//ccFOupvD.o: In function `do_tests':
546 /var/tmp//ccFOupvD.o(.text+0x3a8): warning: tmpnam() possibly used
547 unsafely; consider using mkstemp()
548 mips64-unknown-elf-gcc -g -O3 -fno-builtin -fschedule-insns -mips64
549 -mabi=64 test_common.c -c -o test_common.o
550 ./do_tests "mips64-unknown-elf-gcc -g -O3 -fno-builtin -fschedule-insns
551 -mips64 -mabi=64" "mips64-unknown-elf-as -mabi=64 -mips64"
552 "mips64-unknown-elf-ld -Ttext 0xa800000000030000 -e main
553 --oformat=elf64-bigmips" "../gxemul"
554
555 Starting tests:
556 test_addu.S (-a)
557 test_addu.S (-a -b)
558 test_clo_clz.S (-a)
559 test_clo_clz.S (-a -b)
560 ..
561 test_unaligned.S (-a)
562 test_unaligned.S (-a -b)
563
564 Done. (12 tests done)
565 PASS: 12
566 FAIL: 0
567
568 ----------------
569
570 All tests OK
571
572 ----------------
573 </pre>
574
575 <p>
576 Each test writes output to stdout, and there is a <tt>test_*.good</tt> for
577 each <tt>.S</tt> file which contains the wanted output. If the actual
578 output matches the <tt>.good</tt> file, then the test passes, otherwise it
579 fails.
580
581 <p>
582 Read <tt>tests/README</tt> for more information.
583
584
585
586
587 </body>
588 </html>

  ViewVC Help
Powered by ViewVC 1.1.26