/[gxemul]/trunk/src/promemul/pc_bios.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

Annotation of /trunk/src/promemul/pc_bios.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (hide annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 54080 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


1 dpavlin 14 /*
2 dpavlin 22 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 dpavlin 30 * $Id: pc_bios.c,v 1.7 2006/07/26 23:21:48 debug Exp $
29 dpavlin 14 *
30     * Generic PC BIOS emulation.
31     *
32     * See http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/INT.HTM for
33     * details on what different BIOS interrupts do.
34     *
35     *
36     * The BIOS address space is used as follows:
37     *
38     * 0xf1000 GDT + PD + PTs used for booting in pmode
39     * 0xf8yy0 real mode interrupt handler (int 0xyy)
40     * 0xf9000 SMP tables
41     * 0xfefc7 disk table
42     * 0xff66e 8x8 font (chars 128..255)
43     * 0xffa6e 8x8 font (chars 0..127)
44     * 0xfffd0 System Configuration Parameters (8 bytes)
45     * 0xffff0 Reboot "code".
46     *
47     * TODO: Keep the "BIOS data area" in synch. (Such as keyboard shift state,
48     * disk access, video mode, error codes, x and y charcell resolution...)
49     */
50    
51     #include <stdio.h>
52     #include <stdlib.h>
53     #include <string.h>
54     #include <time.h>
55    
56     #include "cpu.h"
57     #include "misc.h"
58    
59     #ifndef ENABLE_X86
60    
61     /* Don't include PC bios support if we don't have x86 cpu support. */
62     /* These are just do-nothing functions. */
63    
64     void pc_bios_simple_pmode_setup(struct cpu *cpu) { }
65     void pc_bios_init(struct cpu *cpu) { }
66     int pc_bios_emul(struct cpu *cpu) { return 0; }
67    
68    
69     #else
70    
71    
72     #include "console.h"
73     #include "cpu_x86.h"
74     #include "devices.h"
75     #include "diskimage.h"
76     #include "machine.h"
77     #include "memory.h"
78    
79    
80     extern int quiet_mode;
81    
82     extern unsigned char font8x8[];
83    
84     #define dec_to_bcd(x) ( (((x) / 10) << 4) + ((x) % 10) )
85    
86    
87     /*
88     * add_disk():
89     */
90     static struct pc_bios_disk *add_disk(struct machine *machine, int biosnr,
91     int id, int type)
92     {
93     struct pc_bios_disk *p = malloc(sizeof(struct pc_bios_disk));
94    
95     if (p == NULL) {
96     fprintf(stderr, "add_disk(): out of memory\n");
97     exit(1);
98     }
99    
100     p->next = machine->md.pc.first_disk;
101     machine->md.pc.first_disk = p;
102    
103     p->nr = biosnr; p->id = id; p->type = type;
104    
105     p->size = diskimage_getsize(machine, id, type);
106     diskimage_getchs(machine, id, type, &p->cylinders, &p->heads,
107     &p->sectorspertrack);
108    
109     return p;
110     }
111    
112    
113     static struct pc_bios_disk *get_disk(struct machine *machine, int biosnr)
114     {
115     struct pc_bios_disk *p = machine->md.pc.first_disk;
116     while (p != NULL) {
117     if (p->nr == biosnr)
118     break;
119     p = p->next;
120     }
121     return p;
122     }
123    
124    
125     /*
126     * output_char():
127     */
128     static void output_char(struct cpu *cpu, int x, int y, int ch, int color)
129     {
130     uint64_t addr = (y * cpu->machine->md.pc.columns + x) * 2 + 0xb8000;
131     unsigned char w[2];
132     int len = 2;
133    
134     w[0] = ch; w[1] = color;
135     if (color < 0)
136     len = 1;
137    
138     cpu->memory_rw(cpu, cpu->mem, addr, &w[0], len, MEM_WRITE,
139     CACHE_NONE | PHYSICAL);
140     }
141    
142    
143     /*
144     * cmos_write():
145     */
146     static void cmos_write(struct cpu *cpu, int addr, int value)
147     {
148     unsigned char c;
149     c = addr;
150     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x70, &c, 1, MEM_WRITE,
151     CACHE_NONE | PHYSICAL);
152     c = value;
153     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x71, &c, 1, MEM_WRITE,
154     CACHE_NONE | PHYSICAL);
155     }
156    
157    
158     /*
159     * set_cursor_pos():
160     */
161     static void set_cursor_pos(struct cpu *cpu, int x, int y)
162     {
163     int addr = y * cpu->machine->md.pc.columns + x;
164     unsigned char byte;
165     uint64_t ctrlregs = X86_IO_BASE + 0x3c0;
166    
167     byte = 0x0e;
168     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14,
169     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
170     byte = (addr >> 8) & 255;
171     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15,
172     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
173     byte = 0x0f;
174     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14,
175     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
176     byte = addr & 255;
177     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15,
178     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
179     }
180    
181    
182     /*
183     * set_cursor_scanlines():
184     */
185     static void set_cursor_scanlines(struct cpu *cpu, int start, int end)
186     {
187     unsigned char byte;
188     uint64_t ctrlregs = X86_IO_BASE + 0x3c0;
189    
190     byte = 0x0a;
191     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14,
192     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
193     byte = start;
194     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15,
195     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
196     byte = 0x0b;
197     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14,
198     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
199     byte = end;
200     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15,
201     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
202     }
203    
204    
205     /*
206     * get_cursor_pos():
207     */
208     static void get_cursor_pos(struct cpu *cpu, int *x, int *y)
209     {
210     int addr;
211     unsigned char byte;
212     uint64_t ctrlregs = X86_IO_BASE + 0x3c0;
213    
214     byte = 0x0e;
215     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14,
216     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
217     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15,
218     &byte, sizeof(byte), MEM_READ, CACHE_NONE | PHYSICAL);
219     addr = byte;
220    
221     byte = 0x0f;
222     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14,
223     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
224     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15,
225     &byte, sizeof(byte), MEM_READ, CACHE_NONE | PHYSICAL);
226     addr = addr*256 + byte;
227    
228     *x = addr % cpu->machine->md.pc.columns;
229     *y = addr / cpu->machine->md.pc.columns;
230     }
231    
232    
233     /*
234     * set_palette():
235     */
236     static void set_palette(struct cpu *cpu, int n, int r, int g, int b)
237     {
238     unsigned char byte = n;
239     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x3c8,
240     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
241     byte = r;
242     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x3c9,
243     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
244     byte = g;
245     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x3c9,
246     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
247     byte = b;
248     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x3c9,
249     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
250     }
251    
252    
253     /*
254     * get_palette():
255     */
256     static void get_palette(struct cpu *cpu, int n, unsigned char *rgb)
257     {
258     unsigned char byte = n;
259     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x3c8,
260     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
261     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x3c9,
262     &rgb[0], 1, MEM_READ, CACHE_NONE | PHYSICAL);
263     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x3c9,
264     &rgb[1], 1, MEM_READ, CACHE_NONE | PHYSICAL);
265     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x3c9,
266     &rgb[2], 1, MEM_READ, CACHE_NONE | PHYSICAL);
267     }
268    
269    
270     /*
271     * scroll_up():
272     */
273     static void scroll_up(struct cpu *cpu, int x1, int y1, int x2, int y2, int attr)
274     {
275     int x, y;
276    
277     if (x1 < 0) x1 = 0;
278     if (y1 < 0) y1 = 0;
279     if (x2 >= cpu->machine->md.pc.columns)
280     x2 = cpu->machine->md.pc.columns - 1;
281     if (y2 >= cpu->machine->md.pc.rows)
282     y2 = cpu->machine->md.pc.rows - 1;
283    
284     /* Scroll up by copying lines: */
285     for (y=y1; y<=y2-1; y++) {
286     int addr = (cpu->machine->md.pc.columns*y + x1) * 2 + 0xb8000;
287     int len = (x2-x1+1) * 2;
288     unsigned char w[160];
289     addr += (cpu->machine->md.pc.columns * 2);
290     cpu->memory_rw(cpu, cpu->mem, addr, &w[0], len,
291     MEM_READ, CACHE_NONE | PHYSICAL);
292     addr -= (cpu->machine->md.pc.columns * 2);
293     cpu->memory_rw(cpu, cpu->mem, addr, &w[0], len,
294     MEM_WRITE, CACHE_NONE | PHYSICAL);
295     }
296    
297     /* Clear lowest line: */
298     for (x=x1; x<=x2; x++)
299     output_char(cpu, x, y2, ' ', attr);
300     }
301    
302    
303     /*
304     * scroll_down():
305     */
306     static void scroll_down(struct cpu *cpu, int x1, int y1, int x2, int y2,
307     int attr)
308     {
309     int x, y;
310    
311     if (x1 < 0) x1 = 0;
312     if (y1 < 0) y1 = 0;
313     if (x2 >= cpu->machine->md.pc.columns)
314     x2 = cpu->machine->md.pc.columns - 1;
315     if (y2 >= cpu->machine->md.pc.rows)
316     y2 = cpu->machine->md.pc.rows - 1;
317    
318     /* Scroll down by copying lines: */
319     for (y=y2; y>=y1+1; y--) {
320     int addr = (cpu->machine->md.pc.columns*y + x1) * 2 + 0xb8000;
321     int len = (x2-x1+1) * 2;
322     unsigned char w[160];
323     addr -= cpu->machine->md.pc.columns * 2;
324     cpu->memory_rw(cpu, cpu->mem, addr, &w[0], len,
325     MEM_READ, CACHE_NONE | PHYSICAL);
326     addr += cpu->machine->md.pc.columns * 2;
327     cpu->memory_rw(cpu, cpu->mem, addr, &w[0], len,
328     MEM_WRITE, CACHE_NONE | PHYSICAL);
329     }
330    
331     /* Clear the uppermost line: */
332     for (x=x1; x<=x2; x++)
333     output_char(cpu, x, y1, ' ', attr);
334     }
335    
336    
337     /*
338     * pc_bios_putchar():
339     */
340     static void pc_bios_putchar(struct cpu *cpu, char ch, int attr,
341     int linewrap_and_scroll)
342     {
343     int x, y;
344    
345     get_cursor_pos(cpu, &x, &y);
346    
347     if (!linewrap_and_scroll) {
348     if (x < cpu->machine->md.pc.columns &&
349     y < cpu->machine->md.pc.rows) {
350     output_char(cpu, x, y, ch, attr);
351     x++;
352     set_cursor_pos(cpu, x, y);
353     }
354     return;
355     }
356    
357     /* Put the character on the screen, move cursor, and so on: */
358     switch (ch) {
359     case '\r': x = -1; break;
360     case '\n': x = cpu->machine->md.pc.columns; break;
361     case '\b': x -= 2; break;
362     default: output_char(cpu, x, y, ch, attr);
363     }
364     x++;
365     if (x < 0)
366     x = 0;
367     if (x >= cpu->machine->md.pc.columns) {
368     x=0; y++;
369     }
370    
371     if (attr < 0)
372     attr = cpu->machine->md.pc.curcolor;
373    
374     if (y >= cpu->machine->md.pc.rows) {
375     scroll_up(cpu, 0,0, cpu->machine->md.pc.columns-1,
376     cpu->machine->md.pc.rows-1, attr);
377     x = 0; y = cpu->machine->md.pc.rows - 1;
378     }
379     set_cursor_pos(cpu, x, y);
380     }
381    
382    
383     /*
384     * pc_bios_printstr():
385     */
386     static void pc_bios_printstr(struct cpu *cpu, char *s, int attr)
387     {
388     while (*s)
389     pc_bios_putchar(cpu, *s++, attr, 1);
390     }
391    
392    
393     /*
394     * set_video_mode():
395     */
396     static void set_video_mode(struct cpu *cpu, int al)
397     {
398     uint64_t ctrlregs = X86_IO_BASE + 0x3c0;
399     int x, y, text;
400     unsigned char byte = 0xff;
401    
402     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14, &byte, sizeof(byte),
403     MEM_WRITE, CACHE_NONE | PHYSICAL);
404     byte = al;
405     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15, &byte, sizeof(byte),
406     MEM_WRITE, CACHE_NONE | PHYSICAL);
407    
408     text = 0;
409    
410     switch (al) {
411     case 0x00: /* 40x25 non-color textmode */
412     case 0x01: /* 40x25 color textmode */
413     cpu->machine->md.pc.columns = 40;
414     cpu->machine->md.pc.rows = 25;
415     text = 1;
416     break;
417     case 0x02: /* 80x25 non-color textmode */
418     case 0x03: /* 80x25 color textmode */
419     cpu->machine->md.pc.columns = 80;
420     cpu->machine->md.pc.rows = 25;
421     text = 1;
422     break;
423     case 0x19: /* ? */
424     break;
425     case 0x0d: /* 320x200 x 16 colors graphics */
426     set_cursor_scanlines(cpu, 0x40, 0);
427     break;
428     case 0x12: /* 640x480 x 16 colors graphics */
429     set_cursor_scanlines(cpu, 0x40, 0);
430     break;
431     case 0x13: /* 320x200 x 256 colors graphics */
432     set_cursor_scanlines(cpu, 0x40, 0);
433     break;
434     default:
435     fatal("[ set_video_mode(): unimplemented video mode "
436     "0x%02x ]\n", al);
437     cpu->running = 0;
438     }
439    
440     cpu->machine->md.pc.curcolor = 0x07;
441     cpu->machine->md.pc.videomode = al;
442    
443     if (text) {
444     /* Simply clear the screen and home the cursor
445     for now. TODO: More advanced stuff. */
446     set_cursor_pos(cpu, 0, 0);
447     for (y=0; y<cpu->machine->md.pc.rows; y++)
448     for (x=0; x<cpu->machine->md.pc.columns; x++)
449     output_char(cpu, x,y, ' ',
450     cpu->machine->md.pc.curcolor);
451     }
452     }
453    
454    
455     /*
456     * pc_bios_int8():
457     *
458     * Interrupt handler for the timer.
459     */
460     static int pc_bios_int8(struct cpu *cpu)
461     {
462     unsigned char ticks[4];
463     unsigned char tmpbyte;
464    
465     /* TODO: ack the timer interrupt some other way? */
466     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x43,
467     &tmpbyte, 1, MEM_READ, CACHE_NONE | PHYSICAL);
468    
469     /* EOI the interrupt. */
470     cpu->machine->isa_pic_data.pic1->isr &= ~0x01;
471    
472     /* "Call" INT 0x1C: */
473     /* TODO: how about non-real-mode? */
474     cpu->memory_rw(cpu, cpu->mem, 0x1C * 4,
475     ticks, 4, MEM_READ, CACHE_NONE | PHYSICAL);
476     cpu->pc = ticks[0] + (ticks[1] << 8);
477     reload_segment_descriptor(cpu, X86_S_CS, ticks[2] + (ticks[3] << 8),
478     NULL);
479     return 0;
480     }
481    
482    
483     /*
484     * pc_bios_int9():
485     *
486     * Interrupt handler for the keyboard.
487     */
488     static void pc_bios_int9(struct cpu *cpu)
489     {
490     uint8_t byte;
491    
492     /* Read a key from the keyboard: */
493     cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + 0x60,
494     &byte, sizeof(byte), MEM_READ, CACHE_NONE | PHYSICAL);
495    
496     /* (The read should have acknowdledged the interrupt.) */
497    
498     /* Add the key to the keyboard buffer: */
499     cpu->machine->md.pc.kbd_buf_scancode[
500     cpu->machine->md.pc.kbd_buf_tail] = byte;
501    
502     /* TODO: The shift state should be located in the BIOS
503     data area. */
504    
505     if (byte == 0x2a) {
506     cpu->machine->md.pc.shift_state |= PC_KBD_SHIFT;
507     byte = 0;
508     }
509     if (byte == 0x1d) {
510     cpu->machine->md.pc.shift_state |= PC_KBD_CTRL;
511     byte = 0;
512     }
513     if (byte == 0x2a + 0x80) {
514     cpu->machine->md.pc.shift_state &= ~PC_KBD_SHIFT;
515     byte = 0;
516     }
517     if (byte == 0x1d + 0x80) {
518     cpu->machine->md.pc.shift_state &= ~PC_KBD_CTRL;
519     byte = 0;
520     }
521    
522     /* Convert scancode into ASCII: */
523     /* (TODO: Maybe this should be somewhere else?) */
524     switch (cpu->machine->md.pc.shift_state) {
525     case 0: if (byte >= 1 && byte <= 0xf)
526     byte = "\0331234567890-=\b\t"[byte-1];
527     else if (byte >= 0x10 && byte <= 0x1b)
528     byte = "qwertyuiop[]"[byte-0x10];
529     else if (byte >= 0x1c && byte <= 0x2b)
530     byte = "\r\000asdfghjkl;'`\000\\"[byte-0x1c];
531     else if (byte >= 0x2c && byte <= 0x35)
532     byte = "zxcvbnm,./"[byte-0x2c];
533     else if (byte >= 0x37 && byte <= 0x39)
534     byte = "*\000 "[byte-0x37];
535     else
536     byte = 0;
537     break;
538     case PC_KBD_SHIFT:
539     if (byte >= 1 && byte <= 0xf)
540     byte = "\033!@#$%^&*()_+\b\t"[byte-1];
541     else if (byte >= 0x10 && byte <= 0x1b)
542     byte = "QWERTYUIOP{}"[byte-0x10];
543     else if (byte >= 0x1c && byte <= 0x2b)
544     byte = "\r\000ASDFGHJKL:\"~\000|"[byte-0x1c];
545     else if (byte >= 0x2c && byte <= 0x35)
546     byte = "ZXCVBNM<>?"[byte-0x2c];
547     else if (byte >= 0x37 && byte <= 0x39)
548     byte = "*\000 "[byte-0x37];
549     else
550     byte = 0;
551     break;
552     default:
553     byte = 0;
554     }
555    
556     cpu->machine->md.pc.kbd_buf[cpu->machine->md.pc.kbd_buf_tail] = byte;
557    
558     cpu->machine->md.pc.kbd_buf_tail ++;
559     cpu->machine->md.pc.kbd_buf_tail %= PC_BIOS_KBD_BUF_SIZE;
560    
561     /* EOI the interrupt. */
562     cpu->machine->isa_pic_data.pic1->isr &= ~0x02;
563     }
564    
565    
566     /*
567     * pc_bios_int10():
568     *
569     * Video functions.
570     */
571     static void pc_bios_int10(struct cpu *cpu)
572     {
573     uint64_t ctrlregs = X86_IO_BASE + 0x3c0;
574     unsigned char byte;
575     unsigned char rgb[3];
576     int x,y, oldx,oldy;
577     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
578     int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
579     int dh = (cpu->cd.x86.r[X86_R_DX] >> 8) & 0xff;
580     int dl = cpu->cd.x86.r[X86_R_DX] & 0xff;
581     int ch = (cpu->cd.x86.r[X86_R_CX] >> 8) & 0xff;
582     int cl = cpu->cd.x86.r[X86_R_CX] & 0xff;
583     int bh = (cpu->cd.x86.r[X86_R_BX] >> 8) & 0xff;
584     int bl = cpu->cd.x86.r[X86_R_BX] & 0xff;
585     int cx = cpu->cd.x86.r[X86_R_CX] & 0xffff;
586     int dx = cpu->cd.x86.r[X86_R_DX] & 0xffff;
587     int bp = cpu->cd.x86.r[X86_R_BP] & 0xffff;
588    
589     switch (ah) {
590     case 0x00: /* Switch video mode. */
591     set_video_mode(cpu, al);
592     break;
593     case 0x01:
594     /* ch = starting line, cl = ending line */
595     /* TODO: it seems that FreeDOS uses start=6 end=7. hm */
596     if (ch == 6 && cl == 7)
597     ch = 12, cl = 14;
598     set_cursor_scanlines(cpu, ch, cl);
599     break;
600     case 0x02: /* set cursor position */
601     set_cursor_pos(cpu, dl, dh);
602     break;
603     case 0x03: /* read cursor position */
604     get_cursor_pos(cpu, &x, &y);
605     cpu->cd.x86.r[X86_R_DX] = (y << 8) + x;
606     /* ch/cl = cursor start end... TODO */
607     cpu->cd.x86.r[X86_R_CX] = 0x000f;
608     break;
609     case 0x05: /* set active display page */
610     if (al != 0)
611     fatal("WARNING: int 0x10, func 0x05, al = 0x%02\n", al);
612     break;
613     case 0x06:
614     if (al < 1)
615     al = 25;
616     while (al-- > 0)
617     scroll_up(cpu, cl, ch, dl, dh, bh);
618     break;
619     case 0x07:
620     if (al < 1)
621     al = 25;
622     while (al-- > 0)
623     scroll_down(cpu, cl, ch, dl, dh, bh);
624     break;
625     case 0x08: /* read char and attr at cur position */
626     /* TODO: return AH=attr, AL=char */
627     break;
628     case 0x09: /* write character and attribute(todo) */
629     case 0x0a: /* write character only */
630     get_cursor_pos(cpu, &oldx, &oldy);
631     while (cx-- > 0)
632     pc_bios_putchar(cpu, al, ah==9? bl : -1, 0);
633     if (ah == 9)
634     cpu->machine->md.pc.curcolor = bl;
635     set_cursor_pos(cpu, oldx, oldy);
636     break;
637     case 0x0b: /* set background palette */
638     fatal("WARNING: int 0x10, func 0x0b: TODO\n");
639     /* cpu->running = 0; */
640     break;
641     case 0x0e: /* tty output */
642     pc_bios_putchar(cpu, al, -1, 1);
643     break;
644     case 0x0f: /* get video mode */
645     cpu->cd.x86.r[X86_R_AX] = cpu->machine->md.pc.columns << 8;
646    
647     byte = 0xff;
648     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14,
649     &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL);
650     cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15,
651     &byte, sizeof(byte), MEM_READ, CACHE_NONE | PHYSICAL);
652     cpu->cd.x86.r[X86_R_AX] |= byte;
653    
654     cpu->cd.x86.r[X86_R_BX] &= ~0xff00; /* BH = pagenr */
655     break;
656     case 0x10: /* Palette stuff */
657     switch (al) {
658     case 0x00:
659     /* Hm. Is this correct? How about the upper 4
660     bits of bh? TODO */
661     set_palette(cpu, bl,
662     ((bh >> 2) & 1) * 0xaa + (bh&8? 0x55 : 0),
663     ((bh >> 1) & 1) * 0xaa + (bh&8? 0x55 : 0),
664     ((bh >> 0) & 1) * 0xaa + (bh&8? 0x55 : 0));
665     break;
666     case 0x01: /* TODO: Set border color. */
667     fatal("TODO int 10,ah=10,al=01\n");
668     break;
669     case 0x02: /* Set all palette registers. */
670     /* Load from ES:DX */
671     fatal("TODO: int10,10,02\n");
672     break;
673     case 0x03: /* TODO: intensity/blinking bit */
674     debug("TODO int 10,ah=10,al=03\n");
675     break;
676     case 0x10:
677     set_palette(cpu, bl, dh, cl, ch);
678     break;
679     case 0x12: /* Set block of palette registers. */
680     /* Load from ES:DX, BX=start color, CX =
681     nr of registers to load */
682     while (cx-- > 0) {
683     cpu->cd.x86.cursegment = X86_S_ES;
684     cpu->memory_rw(cpu, cpu->mem, dx, rgb, 3,
685     MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
686     set_palette(cpu, bl, rgb[0],rgb[1],rgb[2]);
687     dx += 3;
688     bl ++;
689     }
690     break;
691     case 0x17: /* Read block of palette registers. */
692     /* Load into ES:DX, BX=start color, CX =
693     nr of registers to load */
694     while (cx-- > 0) {
695     get_palette(cpu, bl, rgb);
696     cpu->cd.x86.cursegment = X86_S_ES;
697     cpu->memory_rw(cpu, cpu->mem, dx, rgb, 3,
698     MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS);
699     dx += 3;
700     bl ++;
701     }
702     break;
703     case 0x1a: /* Get DAC State: TODO */
704     cpu->cd.x86.r[X86_R_BX] &= ~0xff;
705     break;
706     default:fatal("Unimplemented INT 0x10,AH=0x10,AL=0x%02x\n", al);
707     cpu->running = 0;
708     }
709     break;
710     case 0x11: /* Character generator */
711     /* TODO */
712     switch (al) {
713     case 0x12:
714     break;
715     case 0x14:
716     break;
717     case 0x30:
718     switch (bh) {
719     case 0x03: /* 8x8 font */
720     cpu->cd.x86.r[X86_R_BP] &= ~0xffff;
721     cpu->cd.x86.r[X86_R_BP] |= 0xfa6e;
722     reload_segment_descriptor(cpu, X86_S_ES,
723     0xf000, NULL);
724     /* TODO: cx and dl, better values? */
725     cpu->cd.x86.r[X86_R_CX] &= ~0xffff;
726     cpu->cd.x86.r[X86_R_CX] |= 16;
727     cpu->cd.x86.r[X86_R_DX] &= ~0xff;
728     cpu->cd.x86.r[X86_R_DX] |= 24;
729     break;
730     default:
731     fatal("[ pc_bios: Get Font: TODO ]\n");
732     }
733     break;
734     default:fatal("Unimplemented INT 0x10,AH=0x11,AL=0x%02x\n", al);
735     cpu->running = 0;
736     }
737     break;
738     case 0x12: /* Video Subsystem Configuration */
739     /* TODO */
740     switch (bl) {
741     case 0x10:
742     cpu->cd.x86.r[X86_R_BX] &= ~0xffff;
743     cpu->cd.x86.r[X86_R_BX] |= 0x0003;
744     break;
745     case 0x30: /* select nr of scanlines (200 + 50*al) */
746     debug("[ pc_bios: %i scanlines ]\n", 200+50*al);
747     cpu->cd.x86.r[X86_R_AX] &= ~0xff;
748     cpu->cd.x86.r[X86_R_AX] |= 0x12;
749     break;
750     case 0x34: /* TODO */
751     break;
752     default:fatal("Unimplemented INT 0x10,AH=0x12,BL=0x%02x\n", bl);
753     cpu->running = 0;
754     }
755     break;
756     case 0x13: /* write string */
757     /* TODO: other flags in al */
758     get_cursor_pos(cpu, &oldx, &oldy);
759     set_cursor_pos(cpu, dl, dh);
760     while (cx-- > 0) {
761     int len = 1;
762     unsigned char byte[2];
763     byte[1] = 0x07;
764     if (al & 2)
765     len = 2;
766     cpu->cd.x86.cursegment = X86_S_ES;
767     cpu->memory_rw(cpu, cpu->mem, bp, &byte[0], len,
768     MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
769     bp += len;
770     pc_bios_putchar(cpu, byte[0], byte[1], 1);
771     cpu->machine->md.pc.curcolor = byte[1];
772     }
773     if (!(al & 1))
774     set_cursor_pos(cpu, oldx, oldy);
775     break;
776     case 0x1a: /* get/set video display combination */
777     if (al != 0) {
778     fatal("FATAL: Unimplemented BIOS int 0x10 function"
779     " 0x%02x, al=0x%02\n", ah, al);
780     cpu->running = 0;
781     }
782     cpu->cd.x86.r[X86_R_AX] &= ~0xff;
783     cpu->cd.x86.r[X86_R_AX] |= 0x1a;
784     cpu->cd.x86.r[X86_R_BX] &= ~0xffff;
785     cpu->cd.x86.r[X86_R_BX] |= 0x0008;
786     break;
787     case 0x1b: /* State Information: TODO */
788     fatal("TODO: int10,1b\n");
789     break;
790     case 0x4f: /* VESA */
791     /* TODO: See http://www.uv.tietgen.dk/staff/mlha/PC/
792     Prog/asm/int/INT10.htm#4F for more info. */
793     switch (al) {
794     case 0x00: /* Detect VESA */
795     #if 0
796     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
797     cpu->cd.x86.r[X86_R_AX] |= 0x004f;
798     /* TODO: the VESA struct at ES:DI */
799     #endif
800     break;
801     case 0x01: /* Return mode info */
802     fatal("TODO: VESA mode 0x%04x\n", cx);
803     break;
804     default:
805     fatal("TODO: int 0x10, function 0x4f, al=0x%02x\n", al);
806     }
807     break;
808     case 0xef: /* Hercules Detection */
809     case 0xfa: /* EGA Register Interface Library */
810     /* TODO: How to accurately return failure? */
811     debug("TODO: int10,ah=0x%02x\n", ah);
812     break;
813     default:
814     fatal("FATAL: Unimplemented PC BIOS interrupt 0x10 function"
815     " 0x%02x.\n", ah);
816     cpu->running = 0;
817     }
818     }
819    
820    
821     /*
822     * pc_bios_int13():
823     *
824     * Disk-related functions. These usually return CF on error.
825     */
826     static void pc_bios_int13(struct cpu *cpu)
827     {
828     struct pc_bios_disk *disk;
829     int res, nread, err;
830     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
831     int al = (cpu->cd.x86.r[X86_R_AX] >> 0) & 0xff;
832     int dh = (cpu->cd.x86.r[X86_R_DX] >> 8) & 0xff;
833     int dl = (cpu->cd.x86.r[X86_R_DX] >> 0) & 0xff;
834     int ch = (cpu->cd.x86.r[X86_R_CX] >> 8) & 0xff;
835     int cl = (cpu->cd.x86.r[X86_R_CX] >> 0) & 0xff;
836     int bx = cpu->cd.x86.r[X86_R_BX] & 0xffff;
837     uint64_t offset;
838    
839     switch (ah) {
840     case 0x00: /* Reset disk, dl = drive */
841     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
842     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
843     /* Do nothing. :-) */
844     break;
845     case 0x02: /* Read sector */
846     case 0x03: /* Write sector */
847     /*
848     * Read/Write sector(s). al = nr of sectors
849     * dh = head, dl = disk id (0-based),
850     * ch = cyl, cl = 1-based starting sector nr
851     * es:bx = destination buffer; return carryflag = error
852     */
853     cpu->cd.x86.rflags |= X86_FLAGS_CF;
854     disk = get_disk(cpu->machine, cpu->cd.x86.r[X86_R_DX] & 0xff);
855     if (disk != NULL) {
856     unsigned char *buf;
857    
858     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
859     ch = ch + ((cl >> 6) << 8);
860     cl = (cl & 0x3f) - 1;
861     offset = (cl + disk->sectorspertrack * dh +
862     disk->sectorspertrack * disk->heads * ch) * 512;
863     nread = 0; err = 0;
864     debug("[ pc_bios_int13(): reading from disk 0x%x, "
865     "CHS=%i,%i,%i ]\n", dl, ch, dh, cl);
866    
867     buf = malloc(512 * al);
868    
869     if (cl+al > disk->sectorspertrack ||
870     dh >= disk->heads || ch > disk->cylinders) {
871     al = 0; err = 4; /* sector not found */
872     fatal("[ pc_bios: attempt to %s outside the d"
873     "isk? bios id=0x%02x, chs=%i,%i,%i, acces"
874     "s at %i,%i,%i ]\n", ah==2? "read" :
875     "write", dl, disk->cylinders, disk->heads,
876     disk->sectorspertrack, ch, dh, cl);
877     }
878    
879     debug("[ pc_bios_int13(): %s biosdisk 0x%02x (offset="
880 dpavlin 24 "0x%"PRIx64") mem=0x%04x:0x%04x ]\n", ah==2?
881     "read from" : "write to", dl, (uint64_t) offset,
882 dpavlin 14 cpu->cd.x86.s[X86_S_ES], bx);
883    
884     if (ah == 3) {
885     fatal("TODO: bios disk write\n");
886     /* cpu->running = 0; */
887     /* TODO */
888     al = 0;
889     }
890     if (al > 0)
891     res = diskimage_access(cpu->machine, disk->id,
892     disk->type, 0, offset, buf, al * 512);
893     else
894     res = 0;
895     nread = al;
896     if (!res) {
897     err = 4;
898     fatal("[ pc_bios_int13(): FAILED to %s"
899 dpavlin 24 " biosdisk 0x%02x (offset=0x%"PRIx64")"
900 dpavlin 14 " ]\n", ah==2? "read from" :
901 dpavlin 24 "write to", dl, (uint64_t) offset);
902 dpavlin 14 } else if (ah == 2) {
903     cpu->cd.x86.cursegment = X86_S_ES;
904     if (bx + 512*al > 0x10000) {
905     /* DMA overrun */
906     fatal("[ pc_bios: DMA overrun ]\n");
907     err = 9;
908     nread = al = (0x10000 - bx) / 512;
909     }
910     store_buf(cpu, bx, (char *)buf, 512 * al);
911     }
912     free(buf);
913     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
914     cpu->cd.x86.r[X86_R_AX] |= nread;
915     } else
916     err = 0x80;
917     if (err) {
918     cpu->cd.x86.rflags |= X86_FLAGS_CF;
919     cpu->cd.x86.r[X86_R_AX] |= (err << 8);
920     }
921     break;
922     case 4: /* verify disk sectors */
923     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
924     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
925     /* Do nothing. :-) */
926     break;
927     case 8: /* get drive status: TODO */
928     cpu->cd.x86.rflags |= X86_FLAGS_CF;
929     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
930     cpu->cd.x86.r[X86_R_AX] |= 0x8080;
931     disk = get_disk(cpu->machine, cpu->cd.x86.r[X86_R_DX] & 0xff);
932     if (disk != NULL) {
933     int cyl_hi, cyl_lo;
934    
935     cyl_lo = disk->cylinders & 255;
936     cyl_hi = ((disk->cylinders >> 8) & 3) << 6;
937     cyl_hi |= disk->sectorspertrack;
938    
939     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
940     cpu->cd.x86.r[X86_R_BX] &= ~0xffff;
941     if (disk->type == DISKIMAGE_FLOPPY)
942     cpu->cd.x86.r[X86_R_BX] |= 4;
943     cpu->cd.x86.r[X86_R_CX] &= ~0xffff;
944     cpu->cd.x86.r[X86_R_CX] |= (cyl_lo << 8) | cyl_hi;
945     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
946     cpu->cd.x86.r[X86_R_DX] |= 0x01 |
947     ((disk->heads - 1) << 8);
948     /* TODO: dl = nr of drives */
949     /* TODO: es:di? */
950     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
951     }
952     break;
953     case 0x15: /* Read DASD Type */
954     /* TODO: generalize */
955     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
956     cpu->cd.x86.r[X86_R_AX] |= 0x0100;
957     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
958     break;
959     case 0x41: /* Check for Extended Functions */
960     /* There is no such support. :) */
961     cpu->cd.x86.rflags |= X86_FLAGS_CF;
962     break;
963     case 0x42: /* Extended Read: */
964     /* TODO */
965     cpu->cd.x86.rflags |= X86_FLAGS_CF;
966     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
967     cpu->cd.x86.r[X86_R_AX] |= 0x0100;
968     break;
969     case 0x48: /* ? */
970     /* TODO */
971     cpu->cd.x86.rflags |= X86_FLAGS_CF;
972     break;
973     case 0x4b: /* CDROM emulation (TODO) */
974     cpu->cd.x86.rflags |= X86_FLAGS_CF;
975     break;
976     case 0xfa: /* ? */
977     cpu->cd.x86.rflags |= X86_FLAGS_CF;
978     break;
979     default:
980     fatal("FATAL: Unimplemented PC BIOS interrupt 0x13 function"
981     " 0x%02x.\n", ah);
982     cpu->running = 0;
983     }
984     }
985    
986    
987     /*
988     * pc_bios_int14():
989     *
990     * Serial port stuff.
991     */
992     static void pc_bios_int14(struct cpu *cpu)
993     {
994     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
995    
996     switch (ah) {
997     case 0: debug("[ pc_bios_14(): TODO ]\n");
998     break;
999     default:
1000     fatal("FATAL: Unimplemented PC BIOS interrupt 0x14 function"
1001     " 0x%02x.\n", ah);
1002     cpu->running = 0;
1003     }
1004     }
1005    
1006    
1007     /*
1008     * pc_bios_int15():
1009     */
1010     static void pc_bios_int15(struct cpu *cpu)
1011     {
1012     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
1013     int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
1014     int cx = cpu->cd.x86.r[X86_R_CX] & 0xffff;
1015     int si = cpu->cd.x86.r[X86_R_SI] & 0xffff;
1016     int m;
1017     unsigned char src_entry[8];
1018     unsigned char dst_entry[8];
1019     uint32_t src_addr, dst_addr;
1020    
1021     switch (ah) {
1022     case 0x00: /* TODO? */
1023     fatal("[ PC BIOS int 0x15,0x00: TODO ]\n");
1024     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1025     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1026     cpu->cd.x86.r[X86_R_AX] |= 0x8600; /* TODO */
1027     break;
1028     case 0x06: /* TODO */
1029     fatal("[ PC BIOS int 0x15,0x06: TODO ]\n");
1030     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1031     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1032     cpu->cd.x86.r[X86_R_AX] |= 0x8600; /* TODO */
1033     break;
1034     case 0x24: /* TODO */
1035     fatal("[ PC BIOS int 0x15,0x24: TODO ]\n");
1036     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1037     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1038     cpu->cd.x86.r[X86_R_AX] |= 0x8600; /* TODO */
1039     break;
1040     case 0x41: /* TODO */
1041     fatal("[ PC BIOS int 0x15,0x41: TODO ]\n");
1042     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1043     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1044     cpu->cd.x86.r[X86_R_AX] |= 0x8600; /* TODO */
1045     break;
1046     case 0x4f: /* Keyboard Scancode Intercept (TODO) */
1047     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1048     break;
1049     case 0x53: /* TODO */
1050     fatal("[ PC BIOS int 0x15,0x53: TODO ]\n");
1051     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1052     break;
1053     case 0x86: /* Wait */
1054     /* No. :-) */
1055     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1056     break;
1057     case 0x87: /* Move to/from extended memory, via a GDT */
1058     cpu->cd.x86.cursegment = X86_S_ES;
1059     cpu->memory_rw(cpu, cpu->mem, si + 0x10, src_entry, 8,
1060     MEM_READ, CACHE_DATA);
1061     cpu->memory_rw(cpu, cpu->mem, si + 0x18, dst_entry, 8,
1062     MEM_READ, CACHE_DATA);
1063     src_addr = src_entry[2]+(src_entry[3]<<8)+(src_entry[4]<<16);
1064     dst_addr = dst_entry[2]+(dst_entry[3]<<8)+(dst_entry[4]<<16);
1065     if (src_entry[5] != 0x92 && src_entry[5] != 0x93)
1066     fatal("WARNING: int15,87: bad src access right?"
1067     " (0x%02x, should be 0x93)\n", src_entry[5]);
1068     if (dst_entry[5] != 0x92 && dst_entry[5] != 0x93)
1069     fatal("WARNING: int15,87: bad dst access right?"
1070     " (0x%02x, should be 0x93)\n", dst_entry[5]);
1071     debug("[ pc_bios: INT15: copying %i bytes from 0x%x to 0x%x"
1072     " ]\n", cx*2, src_addr, dst_addr);
1073     if (cx > 0x8000)
1074     fatal("WARNING! INT15 func 0x87 cx=0x%04x, max allowed"
1075     " is supposed to be 0x8000!\n", cx);
1076     while (cx*2 > 0) {
1077     unsigned char buf[2];
1078     cpu->memory_rw(cpu, cpu->mem, src_addr, buf, 2,
1079     MEM_READ, NO_SEGMENTATION | CACHE_DATA);
1080     cpu->memory_rw(cpu, cpu->mem, dst_addr, buf, 2,
1081     MEM_WRITE, NO_SEGMENTATION | CACHE_DATA);
1082     src_addr += 2; dst_addr += 2; cx --;
1083     }
1084     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1085     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1086     cpu->cd.x86.rflags |= X86_FLAGS_ZF;
1087     break;
1088     case 0x88: /* Extended Memory Size Determination */
1089     /* TODO: Max 16 or 64 MB? */
1090     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1091     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
1092     if (cpu->machine->physical_ram_in_mb <= 64)
1093     cpu->cd.x86.r[X86_R_AX] |= (cpu->machine->
1094     physical_ram_in_mb - 1) * 1024;
1095     else
1096     cpu->cd.x86.r[X86_R_AX] |= 63*1024;
1097     break;
1098     case 0x8A: /* Get "Big" memory size */
1099     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1100     m = (cpu->machine->physical_ram_in_mb - 1) * 1024;
1101     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
1102     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
1103     cpu->cd.x86.r[X86_R_DX] |= ((m >> 16) & 0xffff);
1104     cpu->cd.x86.r[X86_R_AX] |= (m & 0xffff);
1105     break;
1106     case 0x91: /* Interrupt Complete (bogus) */
1107     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1108     break;
1109     case 0xc0: /* System Config: (at 0xfffd:0) */
1110     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1111     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1112     cpu->cd.x86.r[X86_R_BX] &= ~0xffff;
1113     cpu->cd.x86.s[X86_S_ES] = 0xfffd;
1114     reload_segment_descriptor(cpu, X86_S_ES, 0xfffd, NULL);
1115     break;
1116     case 0xc1: /* Extended Bios Data-seg (TODO) */
1117     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1118     break;
1119     case 0xe8: /* TODO */
1120     switch (al) {
1121     case 0x01:
1122     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1123     m = cpu->machine->physical_ram_in_mb;
1124     if (m > 16)
1125     m = 16;
1126     m = (m - 1) * 1024;
1127     /* between 1MB and 16MB: (1KB blocks) */
1128     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
1129     cpu->cd.x86.r[X86_R_AX] |= (m & 0xffff);
1130     /* mem above 16MB, 64K blocks: */
1131     m = cpu->machine->physical_ram_in_mb;
1132     if (m < 16)
1133     m = 0;
1134     else
1135     m = (m-16) / 16;
1136     cpu->cd.x86.r[X86_R_BX] &= ~0xffff;
1137     cpu->cd.x86.r[X86_R_BX] |= (m & 0xffff);
1138     /* CX and DX are "configured" memory */
1139     cpu->cd.x86.r[X86_R_CX] &= ~0xffff;
1140     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
1141     cpu->cd.x86.r[X86_R_CX] |= (
1142     cpu->cd.x86.r[X86_R_AX] & 0xffff);
1143     cpu->cd.x86.r[X86_R_DX] |= (
1144     cpu->cd.x86.r[X86_R_BX] & 0xffff);
1145     break;
1146     case 0x20: /* Get memory map: TODO */
1147     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1148     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1149     cpu->cd.x86.r[X86_R_AX] |= 0x8600;
1150     break;
1151     default:fatal("[ PC BIOS int 0x15,0xe8: al=0x%02x "
1152     " TODO ]\n", al);
1153     cpu->running = 0;
1154     }
1155     break;
1156     default:
1157     fatal("FATAL: Unimplemented PC BIOS interrupt 0x15 function"
1158     " 0x%02x.\n", ah);
1159     cpu->running = 0;
1160     }
1161     }
1162    
1163    
1164     /*
1165     * pc_bios_int16():
1166     *
1167     * Keyboard-related functions.
1168     */
1169     static int pc_bios_int16(struct cpu *cpu, int *enable_ints_after_returnp)
1170     {
1171     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
1172     /* int al = cpu->cd.x86.r[X86_R_AX] & 0xff; */
1173     int scancode, asciicode;
1174     unsigned char tmpchar;
1175    
1176     switch (ah) {
1177     case 0x00: /* getchar */
1178     scancode = asciicode = 0;
1179     if (cpu->machine->md.pc.kbd_buf_head !=
1180     cpu->machine->md.pc.kbd_buf_tail) {
1181     asciicode = cpu->machine->md.pc.kbd_buf[
1182     cpu->machine->md.pc.kbd_buf_head];
1183     scancode = cpu->machine->md.pc.kbd_buf_scancode[
1184     cpu->machine->md.pc.kbd_buf_head];
1185     if (asciicode != 0) {
1186     cpu->cd.x86.r[X86_R_AX] =
1187     (scancode << 8) | asciicode;
1188     }
1189     cpu->machine->md.pc.kbd_buf_head ++;
1190     cpu->machine->md.pc.kbd_buf_head %=
1191     PC_BIOS_KBD_BUF_SIZE;
1192     }
1193     *enable_ints_after_returnp = 1;
1194     if (asciicode == 0)
1195     return 0;
1196     break;
1197     case 0x01: /* non-destructive "isavail" */
1198     cpu->cd.x86.rflags |= X86_FLAGS_ZF;
1199     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
1200     scancode = asciicode = 0;
1201     if (cpu->machine->md.pc.kbd_buf_head !=
1202     cpu->machine->md.pc.kbd_buf_tail) {
1203     asciicode = cpu->machine->md.pc.kbd_buf[
1204     cpu->machine->md.pc.kbd_buf_head];
1205     scancode = cpu->machine->md.pc.kbd_buf_scancode[
1206     cpu->machine->md.pc.kbd_buf_head];
1207     cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
1208     cpu->cd.x86.r[X86_R_AX] |= (scancode << 8) | asciicode;
1209     }
1210     *enable_ints_after_returnp = 1;
1211     break;
1212     case 0x02: /* read keyboard flags */
1213     /* TODO: keep this byte updated */
1214     cpu->memory_rw(cpu, cpu->mem, 0x417, &tmpchar, 1,
1215     MEM_READ, PHYSICAL);
1216     cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff)
1217     | tmpchar;
1218     break;
1219     case 0x03: /* Set Keyboard Typematic Rate: TODO */
1220     break;
1221     case 0x55: /* Microsoft stuff: Ignore :-) */
1222     break;
1223     case 0x92: /* Keyboard "Capabilities Check": TODO */
1224     break;
1225     default:
1226     fatal("FATAL: Unimplemented PC BIOS interrupt 0x16 function"
1227     " 0x%02x.\n", ah);
1228     cpu->running = 0;
1229     }
1230    
1231     return 1;
1232     }
1233    
1234    
1235     /*
1236     * pc_bios_int17():
1237     *
1238     * Printer port stuff.
1239     */
1240     static void pc_bios_int17(struct cpu *cpu)
1241     {
1242     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
1243    
1244     switch (ah) {
1245     case 0x01:
1246     debug("[ PC BIOS int 0x17,0x01: TODO ]\n");
1247     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1248     break;
1249     default:
1250     fatal("FATAL: Unimplemented PC BIOS interrupt 0x17 function"
1251     " 0x%02x.\n", ah);
1252     cpu->running = 0;
1253     }
1254     }
1255    
1256    
1257     /*
1258     * pc_bios_int1a():
1259     *
1260     * Time of Day stuff.
1261     */
1262     static void pc_bios_int1a(struct cpu *cpu)
1263     {
1264     unsigned char ticks[4];
1265     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
1266     time_t tim;
1267     struct tm *tm;
1268    
1269     switch (ah) {
1270     case 0x00: /* Read tick count. */
1271     cpu->memory_rw(cpu, cpu->mem, 0x46C,
1272     ticks, sizeof(ticks), MEM_READ, CACHE_NONE | PHYSICAL);
1273     cpu->cd.x86.r[X86_R_CX] = (ticks[3] << 8) | ticks[2];
1274     cpu->cd.x86.r[X86_R_DX] = (ticks[1] << 8) | ticks[0];
1275     break;
1276     case 0x01: /* Set tick count. */
1277     ticks[0] = cpu->cd.x86.r[X86_R_DX];
1278     ticks[1] = cpu->cd.x86.r[X86_R_DX] >> 8;
1279     ticks[2] = cpu->cd.x86.r[X86_R_CX];
1280     ticks[3] = cpu->cd.x86.r[X86_R_CX] >> 8;
1281     cpu->memory_rw(cpu, cpu->mem, 0x46C,
1282     ticks, sizeof(ticks), MEM_WRITE, CACHE_NONE | PHYSICAL);
1283     break;
1284     case 0x02: /* Read real time clock time (AT,PS/2) */
1285     tim = time(NULL);
1286     tm = gmtime(&tim);
1287     cpu->cd.x86.r[X86_R_CX] &= ~0xffff;
1288     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
1289     cpu->cd.x86.r[X86_R_CX] |= (dec_to_bcd(tm->tm_hour) << 8) |
1290     dec_to_bcd(tm->tm_min);
1291     cpu->cd.x86.r[X86_R_DX] |= dec_to_bcd(tm->tm_sec) << 8;
1292     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1293     break;
1294     case 0x04: /* Read real time clock date (AT,PS/2) */
1295     tim = time(NULL);
1296     tm = gmtime(&tim);
1297     cpu->cd.x86.r[X86_R_CX] &= ~0xffff;
1298     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
1299     cpu->cd.x86.r[X86_R_CX] |=
1300     (dec_to_bcd((tm->tm_year+1900)/100) << 8) |
1301     dec_to_bcd(tm->tm_year % 100);
1302     cpu->cd.x86.r[X86_R_DX] |= (dec_to_bcd(tm->tm_mon+1) << 8) |
1303     dec_to_bcd(tm->tm_mday);
1304     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1305     break;
1306     case 0xb1: /* Intel PCI Bios */
1307     /* ... not installed :) */
1308     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1309     break;
1310     default:
1311     fatal("FATAL: Unimplemented PC BIOS interrupt 0x1a function"
1312     " 0x%02x.\n", ah);
1313     cpu->running = 0;
1314     }
1315     }
1316    
1317    
1318     /*
1319     * pc_bios_int1c():
1320     *
1321     * Increase the timer-tick word at 0x40:0x6C.
1322     */
1323     static void pc_bios_int1c(struct cpu *cpu)
1324     {
1325     unsigned char ticks[4];
1326 dpavlin 22 size_t i;
1327 dpavlin 14
1328     /* Increase word at 0x0040:0x006C */
1329     cpu->memory_rw(cpu, cpu->mem, 0x46C,
1330     ticks, sizeof(ticks), MEM_READ, CACHE_NONE | PHYSICAL);
1331     for (i=0; i<sizeof(ticks); i++) {
1332     ticks[i] ++;
1333     if (ticks[i] != 0)
1334     break;
1335     }
1336     cpu->memory_rw(cpu, cpu->mem, 0x46C,
1337     ticks, sizeof(ticks), MEM_WRITE, CACHE_NONE | PHYSICAL);
1338     }
1339    
1340    
1341     /*
1342     * pc_bios_smp_init():
1343     *
1344     * Initialize the "_MP_" struct in BIOS memory.
1345     *
1346     * TODO: Don't use hardcoded values like this.
1347     */
1348     void pc_bios_smp_init(struct cpu *cpu)
1349     {
1350     int i, chksum;
1351    
1352     reload_segment_descriptor(cpu, X86_S_FS, 0xf000, NULL);
1353     store_buf(cpu, 0x9000, "_MP_", 4);
1354     store_byte(cpu, 0x9004, 0x10); /* ptr to table */
1355     store_byte(cpu, 0x9005, 0x90);
1356     store_byte(cpu, 0x9006, 0x0f);
1357     store_byte(cpu, 0x9007, 0x00);
1358     store_byte(cpu, 0x9008, 0x01); /* length. should be 1 */
1359     store_byte(cpu, 0x9009, 0x04); /* version. 4 means "1.4" */
1360     /* Byte at 0x0a is checksum. TODO: make this automagic */
1361     chksum = '_' + 'M' + 'P' + '_' + 0x10 + 0x90 + 0xf + 1 + 4;
1362     store_byte(cpu, 0x900a, 0 - chksum);
1363    
1364     /* PCMP struct, at addr 0x9010. */
1365     store_buf(cpu, 0x9010, "PCMP", 4);
1366     store_16bit_word(cpu, 0x9014, 43);
1367     store_byte(cpu, 0x9016, 4); /* rev 1.4 */
1368     /* 9017 is checksum */
1369     store_buf(cpu, 0x9018, "GXemul ", 8);
1370     store_buf(cpu, 0x9020, "SMP ", 12);
1371    
1372     /* Nr of entries (one per cpu): */
1373     store_16bit_word(cpu, 0x9010 + 34, cpu->machine->ncpus);
1374    
1375     if (cpu->machine->ncpus > 16)
1376     fatal("WARNING: More than 16 CPUs?\n");
1377    
1378     for (i=0; i<cpu->machine->ncpus; i++) {
1379     int ofs = 44 + 20*i;
1380     /* 20 bytes per CPU: */
1381     store_byte(cpu, 0x9010 + ofs + 0, 0x00); /* cpu */
1382     store_byte(cpu, 0x9010 + ofs + 1, i); /* id */
1383     store_byte(cpu, 0x9010 + ofs + 3, 1 | /* enable */
1384     ((i == cpu->machine->bootstrap_cpu)? 2 : 0));
1385     }
1386     }
1387    
1388    
1389     /*
1390     * pc_bios_simple_pmode_setup():
1391     *
1392     * This function is called from emul.c before loading a 32-bit or 64-bit ELF.
1393     * Loading ELFs when the emulation is set to 16-bit real mode is not a good
1394     * thing, so this function sets up a simple GDT which maps every 0xZyyyyyyy
1395     * to 0x0yyyyyyy.
1396     *
1397     * 0xf4000 GDT:
1398     * 00 = NULL
1399     * 08 = code
1400     * 10 = data
1401     */
1402     void pc_bios_simple_pmode_setup(struct cpu *cpu)
1403     {
1404     int i, j, addr = 0, npts;
1405     uint32_t pt_base;
1406     cpu->cd.x86.cursegment = X86_S_FS;
1407     reload_segment_descriptor(cpu, X86_S_FS, 0xf100, NULL);
1408    
1409     /* 0x00 = NULL descriptor. */
1410     addr += 8;
1411    
1412     /* 0x08 = Code descriptor. */
1413     store_byte(cpu, addr + 0, 0xff);
1414     store_byte(cpu, addr + 1, 0xff);
1415     store_byte(cpu, addr + 2, 0x00);
1416     store_byte(cpu, addr + 3, 0x00);
1417     store_byte(cpu, addr + 4, 0x00);
1418     store_byte(cpu, addr + 5, 0x9f);
1419     store_byte(cpu, addr + 6, 0xcf);
1420     store_byte(cpu, addr + 7, 0x00);
1421     addr += 8;
1422    
1423     /* 0x10 = Data descriptor. */
1424     store_byte(cpu, addr + 0, 0xff);
1425     store_byte(cpu, addr + 1, 0xff);
1426     store_byte(cpu, addr + 2, 0x00);
1427     store_byte(cpu, addr + 3, 0x00);
1428     store_byte(cpu, addr + 4, 0x00);
1429     store_byte(cpu, addr + 5, 0x93);
1430     store_byte(cpu, addr + 6, 0xcf);
1431     store_byte(cpu, addr + 7, 0x00);
1432     addr += 8;
1433    
1434     cpu->cd.x86.gdtr = 0xf1000;
1435     cpu->cd.x86.gdtr_limit = 0xfff;
1436    
1437     addr = 0x1000;
1438     cpu->cd.x86.cr[3] = 0xf2000;
1439    
1440     npts = 4;
1441     pt_base = 0xf3000; /* 0xf3000, f4000, f5000, f6000 */
1442    
1443     /* Set up the page directory: */
1444     for (i=0; i<1024; i++) {
1445     uint32_t pde = pt_base + 0x03 + ((i & (npts-1)) << 12);
1446     store_32bit_word(cpu, addr + i*4, pde);
1447     }
1448     addr += 4096;
1449    
1450     /* Set up the page tables: */
1451     for (i=0; i<npts; i++) {
1452     for (j=0; j<1024; j++) {
1453     uint32_t pte = (i << 22) + (j << 12) + 0x03;
1454     store_32bit_word(cpu, addr + j*4, pte);
1455     }
1456     addr += 4096;
1457     }
1458    
1459     cpu->cd.x86.cr[0] |= X86_CR0_PE | X86_CR0_PG;
1460    
1461     /* Interrupts are dangerous when we start in pmode! */
1462     cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
1463    
1464     reload_segment_descriptor(cpu, X86_S_CS, 0x08, NULL);
1465     reload_segment_descriptor(cpu, X86_S_DS, 0x10, NULL);
1466     reload_segment_descriptor(cpu, X86_S_ES, 0x10, NULL);
1467     reload_segment_descriptor(cpu, X86_S_SS, 0x10, NULL);
1468     cpu->cd.x86.r[X86_R_SP] = 0x7000;
1469     cpu->cd.x86.cursegment = X86_S_DS;
1470     }
1471    
1472    
1473     /*
1474     * pc_bios_init():
1475     */
1476     void pc_bios_init(struct cpu *cpu)
1477     {
1478     char t[81];
1479     int x, y, nboxlines, i, any_disk = 0, disknr, tmp;
1480 dpavlin 20 int old_cursegment = cpu->cd.x86.cursegment;
1481 dpavlin 14 int boot_id, boot_type, bios_boot_id = 0, nfloppies = 0, nhds = 0;
1482    
1483     /* Go to real mode: */
1484     cpu->cd.x86.cr[0] &= ~X86_CR0_PE;
1485    
1486     boot_id = diskimage_bootdev(cpu->machine, &boot_type);
1487    
1488     if (cpu->machine->md.pc.initialized) {
1489     fatal("ERROR: pc_bios_init(): Already initialized.\n");
1490     return;
1491     }
1492    
1493     if (cpu->machine->isa_pic_data.pic1 == NULL) {
1494     fatal("ERROR: No interrupt controller?\n");
1495     exit(1);
1496     } else
1497     cpu->machine->isa_pic_data.pic1->irq_base = 0x08;
1498    
1499     /* pic2 can be NULL when emulating an original XT: */
1500     if (cpu->machine->isa_pic_data.pic2 != NULL)
1501     cpu->machine->isa_pic_data.pic2->irq_base = 0x70;
1502    
1503     /* Disk Base Table (11 or 12 bytes?) at F000h:EFC7: */
1504     cpu->cd.x86.cursegment = X86_S_FS;
1505     reload_segment_descriptor(cpu, X86_S_FS, 0xf000, NULL);
1506     store_byte(cpu, 0xefc7 + 0, 0xcf);
1507     store_byte(cpu, 0xefc7 + 1, 0xb8);
1508     store_byte(cpu, 0xefc7 + 2, 1); /* timer ticks till shutoff */
1509     store_byte(cpu, 0xefc7 + 3, 2); /* 512 bytes per sector */
1510     store_byte(cpu, 0xefc7 + 4, 17);
1511     store_byte(cpu, 0xefc7 + 5, 0xd8);
1512     store_byte(cpu, 0xefc7 + 6, 0xff);
1513     store_byte(cpu, 0xefc7 + 7, 0);
1514     store_byte(cpu, 0xefc7 + 8, 0xf6);
1515     store_byte(cpu, 0xefc7 + 9, 1); /* head bounce delay in msec */
1516     store_byte(cpu, 0xefc7 + 10, 1);/* motor start time in 1/8 secs */
1517     store_byte(cpu, 0xefc7 + 11, 1);/* motor stop time in 1/4 secs */
1518    
1519     /* BIOS System Configuration Parameters (8 bytes) at 0xfffd:0: */
1520     reload_segment_descriptor(cpu, X86_S_FS, 0xfffd, NULL);
1521     store_byte(cpu, 0, 8); store_byte(cpu, 1, 0); /* len */
1522     store_byte(cpu, 2, 0xfc); /* model */
1523     store_byte(cpu, 3, 0); /* sub-model */
1524     store_byte(cpu, 4, 0); /* bios revision */
1525     store_byte(cpu, 5, 0x60); /* features */
1526     /* see http://members.tripod.com/~oldboard/assembly/
1527     int_15-c0.html for details */
1528    
1529     /* Some info in the last paragraph of the BIOS: */
1530     reload_segment_descriptor(cpu, X86_S_FS, 0xffff, NULL);
1531     /* TODO: current date :-) */
1532     store_byte(cpu, 0x05, '0'); store_byte(cpu, 0x06, '1');
1533     store_byte(cpu, 0x07, '/');
1534     store_byte(cpu, 0x08, '0'); store_byte(cpu, 0x09, '1');
1535     store_byte(cpu, 0x0a, '/');
1536     store_byte(cpu, 0x0b, '0'); store_byte(cpu, 0x0c, '5');
1537     store_byte(cpu, 0x0e, 0xfc);
1538    
1539     /* Copy the first 128 chars of the 8x8 VGA font into 0xf000:0xfa6e */
1540     reload_segment_descriptor(cpu, X86_S_FS, 0xf000, NULL);
1541     store_buf(cpu, 0xfa6e, (char *)font8x8, 8*128);
1542     store_buf(cpu, 0xfa6e - 1024, (char *)font8x8 + 1024, 8*128);
1543    
1544     /*
1545     * Initialize all real-mode interrupt vectors to point to somewhere
1546     * within the PC BIOS area (0xf000:0x8yy0), and place an IRET
1547     * instruction (too fool someone who really reads the BIOS memory).
1548     */
1549     for (i=0; i<256; i++) {
1550     if (i == 0x20)
1551     i = 0x70;
1552     if (i == 0x78)
1553     break;
1554     reload_segment_descriptor(cpu, X86_S_FS, 0x0000, NULL);
1555     store_16bit_word(cpu, i*4, 0x8000 + i*16);
1556     store_16bit_word(cpu, i*4 + 2, 0xf000);
1557    
1558     /* Exceptions: int 0x1e = ptr to disk table, 1f=fonthigh */
1559     if (i == 0x1e)
1560     store_16bit_word(cpu, i*4, 0xefc7);
1561     if (i == 0x1f)
1562     store_16bit_word(cpu, i*4, 0xfa6e - 1024);
1563    
1564     reload_segment_descriptor(cpu, X86_S_FS, 0xf000, NULL);
1565     store_byte(cpu, 0x8000 + i*16, 0xCF); /* IRET */
1566     }
1567    
1568     /* For SMP emulation, create an "MP" struct in BIOS memory: */
1569     if (cpu->machine->ncpus > 1)
1570     pc_bios_smp_init(cpu);
1571    
1572     /* Prepare for text mode: (0x03 = 80x25, 0x01 = 40x25) */
1573     set_video_mode(cpu, 0x03);
1574    
1575     cmos_write(cpu, 0x15, 640 & 255);
1576     cmos_write(cpu, 0x16, 640 >> 8);
1577     tmp = cpu->machine->physical_ram_in_mb / 1024;
1578     if (tmp > 63*1024)
1579     tmp = 63*1024;
1580     cmos_write(cpu, 0x17, tmp & 255);
1581     cmos_write(cpu, 0x18, tmp >> 8);
1582    
1583     /* Clear the screen first: */
1584     set_cursor_pos(cpu, 0, 0);
1585     for (y=0; y<cpu->machine->md.pc.rows; y++)
1586     for (x=0; x<cpu->machine->md.pc.columns; x++)
1587     output_char(cpu, x,y, ' ', 0x07);
1588    
1589     nboxlines = cpu->machine->md.pc.columns <= 40? 4 : 3;
1590    
1591     /* Draw a nice box at the top: */
1592     for (y=0; y<nboxlines; y++)
1593     for (x=0; x<cpu->machine->md.pc.columns; x++) {
1594     unsigned char ch = ' ';
1595     if (cpu->machine->use_x11) {
1596     if (y == 0) {
1597     ch = 196;
1598     if (x == 0)
1599     ch = 218;
1600     if (x == cpu->machine->md.pc.columns-1)
1601     ch = 191;
1602     } else if (y == nboxlines-1) {
1603     ch = 196;
1604     if (x == 0)
1605     ch = 192;
1606     if (x == cpu->machine->md.pc.columns-1)
1607     ch = 217;
1608     } else if (x == 0 || x ==
1609     cpu->machine->md.pc.columns-1)
1610     ch = 179;
1611     } else {
1612     if (y == 0 || y == nboxlines-1) {
1613     ch = '-';
1614     if (x == 0 || x ==
1615     cpu->machine->md.pc.columns-1)
1616     ch = '+';
1617     } else {
1618     if (x == 0 || x ==
1619     cpu->machine->md.pc.columns-1)
1620     ch = '|';
1621     }
1622     }
1623     output_char(cpu, x,y, ch, 0x19);
1624     }
1625    
1626     snprintf(t, sizeof(t), "GXemul");
1627     #ifdef VERSION
1628     snprintf(t + strlen(t), sizeof(t)-strlen(t), " "VERSION);
1629     #endif
1630     set_cursor_pos(cpu, 2, 1);
1631     pc_bios_printstr(cpu, t, 0x1f);
1632    
1633     snprintf(t, sizeof(t), "%i cpu%s (%s), %i MB memory",
1634     cpu->machine->ncpus, cpu->machine->ncpus > 1? "s" : "",
1635     cpu->cd.x86.model.name, cpu->machine->physical_ram_in_mb);
1636     if (cpu->machine->md.pc.columns <= 40)
1637     set_cursor_pos(cpu, 2, 2);
1638     else
1639     set_cursor_pos(cpu, 78 - strlen(t), 1);
1640     pc_bios_printstr(cpu, t, 0x17);
1641     if (cpu->machine->md.pc.columns <= 40)
1642     set_cursor_pos(cpu, 0, 5);
1643     else
1644     set_cursor_pos(cpu, 0, 4);
1645    
1646     cpu->machine->md.pc.curcolor = 0x07;
1647    
1648     /* "Detect" Floppies, IDE disks, and SCSI disks: */
1649     for (i=0; i<4; i++) {
1650     if (diskimage_exist(cpu->machine, i, DISKIMAGE_FLOPPY)) {
1651     struct pc_bios_disk *p;
1652     p = add_disk(cpu->machine, i, i, DISKIMAGE_FLOPPY);
1653     snprintf(t, sizeof(t), "%c%c", i<2? ('A'+i):' ',
1654     i<2? ':':' ');
1655     pc_bios_printstr(cpu, t, 0xf);
1656     if (i < 2)
1657     nfloppies ++;
1658     snprintf(t, sizeof(t), " (bios disk %02x) FLOPPY", i);
1659     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1660     snprintf(t, sizeof(t), ", %i KB", (int)(p->size/1024));
1661     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1662     if (cpu->machine->md.pc.columns <= 40)
1663     pc_bios_printstr(cpu, "\n ", 0x07);
1664     snprintf(t, sizeof(t), " (CHS=%i,%i,%i)", p->cylinders,
1665     p->heads, p->sectorspertrack);
1666     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1667     if (boot_id == i && boot_type == DISKIMAGE_FLOPPY) {
1668     bios_boot_id = i;
1669     pc_bios_printstr(cpu, " [boot device]", 0xf);
1670     }
1671     pc_bios_printstr(cpu, "\n",
1672     cpu->machine->md.pc.curcolor);
1673     any_disk = 1;
1674     }
1675     }
1676     disknr = 0x80;
1677     for (i=0; i<8; i++) {
1678     if (diskimage_exist(cpu->machine, i, DISKIMAGE_IDE)) {
1679     struct pc_bios_disk *p;
1680     p = add_disk(cpu->machine, disknr, i, DISKIMAGE_IDE);
1681     snprintf(t, sizeof(t), "%s", disknr==0x80? "C:" : " ");
1682     pc_bios_printstr(cpu, t, 0xf);
1683     nhds ++;
1684     snprintf(t, sizeof(t),
1685     " (bios disk %02x) IDE %s, id %i",
1686     disknr, diskimage_is_a_cdrom(cpu->machine, i,
1687     DISKIMAGE_IDE)? "cdrom" : (
1688     diskimage_is_a_tape(cpu->machine, i,
1689     DISKIMAGE_IDE)? "tape" : "disk"),
1690     i);
1691     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1692     if (cpu->machine->md.pc.columns <= 40)
1693     pc_bios_printstr(cpu, "\n ", 0x07);
1694     else
1695     pc_bios_printstr(cpu, ", ",
1696     cpu->machine->md.pc.curcolor);
1697     snprintf(t, sizeof(t), "%lli MB", (long long)
1698     (p->size >> 20));
1699     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1700     if (boot_id == i && boot_type == DISKIMAGE_IDE) {
1701     bios_boot_id = disknr;
1702     pc_bios_printstr(cpu, " [boot device]", 0xf);
1703     }
1704     pc_bios_printstr(cpu, "\n",
1705     cpu->machine->md.pc.curcolor);
1706     disknr++;
1707     any_disk = 1;
1708     }
1709     }
1710     for (i=0; i<8; i++) {
1711     if (diskimage_exist(cpu->machine, i, DISKIMAGE_SCSI)) {
1712     struct pc_bios_disk *p;
1713     p = add_disk(cpu->machine, disknr, i, DISKIMAGE_SCSI);
1714     snprintf(t, sizeof(t), "%s", disknr==0x80? "C:" : " ");
1715     pc_bios_printstr(cpu, t, 0xf);
1716     nhds ++;
1717     snprintf(t, sizeof(t),
1718     " (bios disk %02x) SCSI disk, id %i", disknr, i);
1719     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1720     if (cpu->machine->md.pc.columns <= 40)
1721     pc_bios_printstr(cpu, "\n ", 0x07);
1722     else
1723     pc_bios_printstr(cpu, ", ",
1724     cpu->machine->md.pc.curcolor);
1725     snprintf(t, sizeof(t), "%lli MB", (long long)
1726     (p->size >> 20));
1727     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1728     if (boot_id == i && boot_type == DISKIMAGE_SCSI) {
1729     bios_boot_id = disknr;
1730     pc_bios_printstr(cpu, " [boot device]", 0xf);
1731     }
1732     pc_bios_printstr(cpu, "\n",
1733     cpu->machine->md.pc.curcolor);
1734     disknr++;
1735     any_disk = 1;
1736     }
1737     }
1738    
1739     if (any_disk)
1740     pc_bios_printstr(cpu, "\n", cpu->machine->md.pc.curcolor);
1741     else
1742     pc_bios_printstr(cpu, "No disks attached!\n\n", 0x0f);
1743    
1744     /* See http://members.tripod.com/~oldboard/assembly/bios_data_area.html
1745     for more info. */
1746     if (nfloppies > 0)
1747     nfloppies --;
1748    
1749     reload_segment_descriptor(cpu, X86_S_FS, 0x0000, NULL);
1750     store_16bit_word(cpu, 0x400, 0x03F8); /* COM1 */
1751     store_16bit_word(cpu, 0x402, 0x0378); /* COM2 */
1752     store_byte(cpu, 0x410, (nfloppies << 6) | 0x0f); /* nfloppies etc */
1753     store_byte(cpu, 0x411, 2 << 1); /* nserials etc */
1754     store_16bit_word(cpu, 0x413, 640); /* KB of low RAM */
1755     store_byte(cpu, 0x449, cpu->machine->md.pc.videomode); /* video mode */
1756     store_16bit_word(cpu, 0x44a, cpu->machine->md.pc.columns);/* columns */
1757     store_16bit_word(cpu, 0x463, 0x3D4); /* CRT base port */
1758     store_byte(cpu, 0x475, nhds); /* nr of harddisks */
1759     store_byte(cpu, 0x484, cpu->machine->md.pc.rows-1);/* nr of lines-1 */
1760     store_byte(cpu, 0x485, 16); /* font height */
1761    
1762     /* Registers passed to the bootsector code: */
1763     reload_segment_descriptor(cpu, X86_S_CS, 0x0000, NULL);
1764     reload_segment_descriptor(cpu, X86_S_DS, 0x0000, NULL);
1765     reload_segment_descriptor(cpu, X86_S_ES, 0x0000, NULL);
1766     reload_segment_descriptor(cpu, X86_S_SS, 0x0000, NULL);
1767    
1768     cpu->cd.x86.r[X86_R_AX] = 0xaa55;
1769     cpu->cd.x86.r[X86_R_CX] = 0x0001;
1770     cpu->cd.x86.r[X86_R_DI] = 0xffe4;
1771     cpu->cd.x86.r[X86_R_SP] = 0xfffe;
1772     cpu->cd.x86.r[X86_R_DX] = bios_boot_id;
1773    
1774     cpu->cd.x86.rflags |= X86_FLAGS_IF;
1775     cpu->pc = 0x7c00;
1776    
1777     cpu->machine->md.pc.initialized = 1;
1778 dpavlin 20
1779     cpu->cd.x86.cursegment = old_cursegment;
1780 dpavlin 14 }
1781    
1782    
1783     /*
1784     * pc_bios_emul():
1785     */
1786     int pc_bios_emul(struct cpu *cpu)
1787     {
1788     uint32_t addr = (cpu->cd.x86.s[X86_S_CS] << 4) + cpu->pc;
1789     int int_nr, flags;
1790     int enable_ints_after_return = 0;
1791     unsigned char w[2];
1792    
1793     if (addr == 0xffff0) {
1794     fatal("[ bios reboot ]\n");
1795     cpu->running = 0;
1796     return 0;
1797     }
1798    
1799     int_nr = (addr >> 4) & 0xff;
1800    
1801     if (cpu->cd.x86.cr[0] & X86_CR0_PE) {
1802     fatal("TODO: BIOS interrupt 0x%02x, but we're not in real-"
1803     "mode?\n", int_nr);
1804     cpu->running = 0;
1805     return 0;
1806     }
1807    
1808     switch (int_nr) {
1809     case 0x02: /* NMI? */
1810     debug("[ pc_bios: NMI? TODO ]\n");
1811     break;
1812     case 0x08:
1813     if (pc_bios_int8(cpu) == 0)
1814     return 0;
1815     break;
1816     case 0x09: pc_bios_int9(cpu); break;
1817     case 0x10: pc_bios_int10(cpu); break;
1818     case 0x11:
1819     /* return bios equipment data in ax */
1820     cpu->memory_rw(cpu, cpu->mem, 0x410, &w[0], sizeof(w),
1821     MEM_READ, CACHE_NONE | PHYSICAL);
1822     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
1823     cpu->cd.x86.r[X86_R_AX] |= (w[1] << 8) | w[0];
1824     break;
1825     case 0x12: /* return memory size in KBs */
1826     cpu->cd.x86.r[X86_R_AX] = 640;
1827     break;
1828     case 0x13:
1829     pc_bios_int13(cpu);
1830     enable_ints_after_return = 1;
1831     break;
1832     case 0x14: pc_bios_int14(cpu); break;
1833     case 0x15: pc_bios_int15(cpu); break;
1834     case 0x16:
1835     if (pc_bios_int16(cpu, &enable_ints_after_return) == 0) {
1836     if (enable_ints_after_return)
1837     cpu->cd.x86.rflags |= X86_FLAGS_IF;
1838     return 0;
1839     }
1840     break;
1841     case 0x17: pc_bios_int17(cpu); break;
1842     case 0x18:
1843     pc_bios_printstr(cpu, "Disk boot failed. (INT 0x18 called.)\n",
1844     0x07);
1845     cpu->running = 0;
1846     break;
1847     case 0x19:
1848     pc_bios_printstr(cpu, "Rebooting. (INT 0x19 called.)\n", 0x07);
1849     cpu->running = 0;
1850     break;
1851     case 0x1a: pc_bios_int1a(cpu); break;
1852     case 0x1c: pc_bios_int1c(cpu); break;
1853     default:
1854     fatal("FATAL: Unimplemented PC BIOS interrupt 0x%02x.\n",
1855     int_nr);
1856     cpu->running = 0;
1857     return 0;
1858     }
1859    
1860     /*
1861     * Return from the interrupt: Pop ip (pc), cs, and flags.
1862     */
1863     cpu->cd.x86.cursegment = X86_S_SS;
1864     cpu->pc = load_16bit_word(cpu, cpu->cd.x86.r[X86_R_SP]);
1865     reload_segment_descriptor(cpu, X86_S_CS,
1866     load_16bit_word(cpu, cpu->cd.x86.r[X86_R_SP] + 2), NULL);
1867    
1868     /* Actually, don't pop flags, because they contain result bits
1869     from interrupt calls. Only pop the Interrupt Flag. */
1870     flags = load_16bit_word(cpu, cpu->cd.x86.r[X86_R_SP] + 4);
1871     cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
1872     cpu->cd.x86.rflags |= (flags & X86_FLAGS_IF);
1873    
1874     if (enable_ints_after_return)
1875     cpu->cd.x86.rflags |= X86_FLAGS_IF;
1876    
1877     cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] & ~0xffff)
1878     | ((cpu->cd.x86.r[X86_R_SP] + 6) & 0xffff);
1879    
1880     return 1;
1881     }
1882    
1883    
1884     #endif /* ENABLE_X86 */

  ViewVC Help
Powered by ViewVC 1.1.26