/[gxemul]/upstream/0.3.3.1/src/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 /upstream/0.3.3.1/src/pc_bios.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide annotations)
Mon Oct 8 16:18:14 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 53876 byte(s)
0.3.3.1
1 dpavlin 4 /*
2     * Copyright (C) 2005 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 6 * $Id: pc_bios.c,v 1.97 2005/06/02 17:11:34 debug Exp $
29 dpavlin 4 *
30     * Generic PC BIOS emulation.
31 dpavlin 6 *
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 dpavlin 4 */
50    
51     #include <stdio.h>
52     #include <stdlib.h>
53     #include <string.h>
54 dpavlin 6 #include <time.h>
55 dpavlin 4
56 dpavlin 6 #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 dpavlin 4 #include "console.h"
73     #include "cpu_x86.h"
74 dpavlin 6 #include "devices.h"
75     #include "diskimage.h"
76 dpavlin 4 #include "machine.h"
77     #include "memory.h"
78    
79    
80     extern int quiet_mode;
81    
82 dpavlin 6 extern unsigned char font8x8[];
83 dpavlin 4
84 dpavlin 6 #define dec_to_bcd(x) ( (((x) / 10) << 4) + ((x) % 10) )
85    
86    
87 dpavlin 4 /*
88 dpavlin 6 * 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 dpavlin 4 * output_char():
127     */
128     static void output_char(struct cpu *cpu, int x, int y, int ch, int color)
129     {
130 dpavlin 6 uint64_t addr = (y * cpu->machine->md.pc.columns + x) * 2 + 0xb8000;
131 dpavlin 4 unsigned char w[2];
132 dpavlin 6 int len = 2;
133 dpavlin 4
134     w[0] = ch; w[1] = color;
135 dpavlin 6 if (color < 0)
136     len = 1;
137    
138     cpu->memory_rw(cpu, cpu->mem, addr, &w[0], len, MEM_WRITE,
139 dpavlin 4 CACHE_NONE | PHYSICAL);
140     }
141    
142    
143     /*
144 dpavlin 6 * 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 dpavlin 4 * set_cursor_pos():
160     */
161     static void set_cursor_pos(struct cpu *cpu, int x, int y)
162     {
163 dpavlin 6 int addr = y * cpu->machine->md.pc.columns + x;
164 dpavlin 4 unsigned char byte;
165 dpavlin 6 uint64_t ctrlregs = X86_IO_BASE + 0x3c0;
166 dpavlin 4
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 dpavlin 6 * 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->md.pc.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->md.pc.pic1->isr &= ~0x02;
563     }
564    
565    
566     /*
567 dpavlin 4 * pc_bios_int10():
568     *
569     * Video functions.
570     */
571     static void pc_bios_int10(struct cpu *cpu)
572     {
573 dpavlin 6 uint64_t ctrlregs = X86_IO_BASE + 0x3c0;
574     unsigned char byte;
575     unsigned char rgb[3];
576     int x,y, oldx,oldy;
577 dpavlin 4 int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
578     int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
579 dpavlin 6 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 dpavlin 4
589     switch (ah) {
590     case 0x00: /* Switch video mode. */
591 dpavlin 6 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 dpavlin 4 switch (al) {
658 dpavlin 6 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 dpavlin 4 break;
666 dpavlin 6 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 dpavlin 4 cpu->running = 0;
708     }
709     break;
710 dpavlin 6 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 dpavlin 4 default:
814     fatal("FATAL: Unimplemented PC BIOS interrupt 0x10 function"
815     " 0x%02x.\n", ah);
816     cpu->running = 0;
817     cpu->dead = 1;
818     }
819     }
820    
821    
822     /*
823     * pc_bios_int13():
824     *
825 dpavlin 6 * Disk-related functions. These usually return CF on error.
826 dpavlin 4 */
827     static void pc_bios_int13(struct cpu *cpu)
828     {
829 dpavlin 6 struct pc_bios_disk *disk;
830     int res, nread, err;
831 dpavlin 4 int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
832 dpavlin 6 int al = (cpu->cd.x86.r[X86_R_AX] >> 0) & 0xff;
833     int dh = (cpu->cd.x86.r[X86_R_DX] >> 8) & 0xff;
834     int dl = (cpu->cd.x86.r[X86_R_DX] >> 0) & 0xff;
835     int ch = (cpu->cd.x86.r[X86_R_CX] >> 8) & 0xff;
836     int cl = (cpu->cd.x86.r[X86_R_CX] >> 0) & 0xff;
837     int bx = cpu->cd.x86.r[X86_R_BX] & 0xffff;
838     uint64_t offset;
839 dpavlin 4
840     switch (ah) {
841     case 0x00: /* Reset disk, dl = drive */
842 dpavlin 6 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
843     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
844 dpavlin 4 /* Do nothing. :-) */
845     break;
846 dpavlin 6 case 0x02: /* Read sector */
847     case 0x03: /* Write sector */
848     /*
849     * Read/Write sector(s). al = nr of sectors
850     * dh = head, dl = disk id (0-based),
851     * ch = cyl, cl = 1-based starting sector nr
852     * es:bx = destination buffer; return carryflag = error
853     */
854     cpu->cd.x86.rflags |= X86_FLAGS_CF;
855     disk = get_disk(cpu->machine, cpu->cd.x86.r[X86_R_DX] & 0xff);
856     if (disk != NULL) {
857     unsigned char *buf;
858    
859     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
860     ch = ch + ((cl >> 6) << 8);
861     cl = (cl & 0x3f) - 1;
862     offset = (cl + disk->sectorspertrack * dh +
863     disk->sectorspertrack * disk->heads * ch) * 512;
864     nread = 0; err = 0;
865     debug("[ pc_bios_int13(): reading from disk 0x%x, "
866     "CHS=%i,%i,%i ]\n", dl, ch, dh, cl);
867    
868     buf = malloc(512 * al);
869    
870     if (cl+al > disk->sectorspertrack ||
871     dh >= disk->heads || ch > disk->cylinders) {
872     al = 0; err = 4; /* sector not found */
873     fatal("[ pc_bios: attempt to %s outside the d"
874     "isk? bios id=0x%02x, chs=%i,%i,%i, acces"
875     "s at %i,%i,%i ]\n", ah==2? "read" :
876     "write", dl, disk->cylinders, disk->heads,
877     disk->sectorspertrack, ch, dh, cl);
878     }
879    
880     debug("[ pc_bios_int13(): %s biosdisk 0x%02x (offset="
881     "0x%llx) mem=0x%04x:0x%04x ]\n", ah==2? "read from"
882     : "write to", dl, (long long)offset,
883     cpu->cd.x86.s[X86_S_ES], bx);
884    
885     if (ah == 3) {
886     fatal("TODO: bios disk write\n");
887     /* cpu->running = 0; */
888     /* TODO */
889     al = 0;
890     }
891     if (al > 0)
892     res = diskimage_access(cpu->machine, disk->id,
893     disk->type, 0, offset, buf, al * 512);
894     else
895     res = 0;
896     nread = al;
897     if (!res) {
898     err = 4;
899     fatal("[ pc_bios_int13(): FAILED to %s"
900     " biosdisk 0x%02x (offset=0x%llx)"
901     " ]\n", ah==2? "read from" :
902     "write to", dl, (long long)offset);
903     } else if (ah == 2) {
904     cpu->cd.x86.cursegment = X86_S_ES;
905     if (bx + 512*al > 0x10000) {
906     /* DMA overrun */
907     fatal("[ pc_bios: DMA overrun ]\n");
908     err = 9;
909     nread = al = (0x10000 - bx) / 512;
910     }
911     store_buf(cpu, bx, (char *)buf, 512 * al);
912     }
913     free(buf);
914     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
915     cpu->cd.x86.r[X86_R_AX] |= nread;
916     } else
917     err = 0x80;
918     if (err) {
919     cpu->cd.x86.rflags |= X86_FLAGS_CF;
920     cpu->cd.x86.r[X86_R_AX] |= (err << 8);
921     }
922     break;
923     case 4: /* verify disk sectors */
924     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
925     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
926     /* Do nothing. :-) */
927     break;
928     case 8: /* get drive status: TODO */
929     cpu->cd.x86.rflags |= X86_FLAGS_CF;
930     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
931     cpu->cd.x86.r[X86_R_AX] |= 0x8080;
932     disk = get_disk(cpu->machine, cpu->cd.x86.r[X86_R_DX] & 0xff);
933     if (disk != NULL) {
934     int cyl_hi, cyl_lo;
935    
936     cyl_lo = disk->cylinders & 255;
937     cyl_hi = ((disk->cylinders >> 8) & 3) << 6;
938     cyl_hi |= disk->sectorspertrack;
939    
940     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
941     cpu->cd.x86.r[X86_R_BX] &= ~0xffff;
942     if (disk->type == DISKIMAGE_FLOPPY)
943     cpu->cd.x86.r[X86_R_BX] |= 4;
944     cpu->cd.x86.r[X86_R_CX] &= ~0xffff;
945     cpu->cd.x86.r[X86_R_CX] |= (cyl_lo << 8) | cyl_hi;
946     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
947     cpu->cd.x86.r[X86_R_DX] |= 0x01 |
948     ((disk->heads - 1) << 8);
949     /* TODO: dl = nr of drives */
950     /* TODO: es:di? */
951     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
952     }
953     break;
954     case 0x15: /* Read DASD Type */
955     /* TODO: generalize */
956     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
957     cpu->cd.x86.r[X86_R_AX] |= 0x0100;
958     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
959     break;
960     case 0x41: /* Check for Extended Functions */
961     /* There is no such support. :) */
962     cpu->cd.x86.rflags |= X86_FLAGS_CF;
963     break;
964     case 0x42: /* Extended Read: */
965     /* TODO */
966     cpu->cd.x86.rflags |= X86_FLAGS_CF;
967     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
968     cpu->cd.x86.r[X86_R_AX] |= 0x0100;
969     break;
970     case 0x48: /* ? */
971     /* TODO */
972     cpu->cd.x86.rflags |= X86_FLAGS_CF;
973     break;
974     case 0x4b: /* CDROM emulation (TODO) */
975     cpu->cd.x86.rflags |= X86_FLAGS_CF;
976     break;
977     case 0xfa: /* ? */
978     cpu->cd.x86.rflags |= X86_FLAGS_CF;
979     break;
980 dpavlin 4 default:
981 dpavlin 6 fatal("FATAL: Unimplemented PC BIOS interrupt 0x13 function"
982 dpavlin 4 " 0x%02x.\n", ah);
983     cpu->running = 0;
984     cpu->dead = 1;
985     }
986     }
987    
988    
989     /*
990 dpavlin 6 * pc_bios_int14():
991     *
992     * Serial port stuff.
993     */
994     static void pc_bios_int14(struct cpu *cpu)
995     {
996     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
997    
998     switch (ah) {
999     case 0: debug("[ pc_bios_14(): TODO ]\n");
1000     break;
1001     default:
1002     fatal("FATAL: Unimplemented PC BIOS interrupt 0x14 function"
1003     " 0x%02x.\n", ah);
1004     cpu->running = 0;
1005     cpu->dead = 1;
1006     }
1007     }
1008    
1009    
1010     /*
1011     * pc_bios_int15():
1012     */
1013     static void pc_bios_int15(struct cpu *cpu)
1014     {
1015     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
1016     int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
1017     int cx = cpu->cd.x86.r[X86_R_CX] & 0xffff;
1018     int si = cpu->cd.x86.r[X86_R_SI] & 0xffff;
1019     int m;
1020     unsigned char src_entry[8];
1021     unsigned char dst_entry[8];
1022     uint32_t src_addr, dst_addr;
1023    
1024     switch (ah) {
1025     case 0x00: /* TODO? */
1026     fatal("[ PC BIOS int 0x15,0x00: TODO ]\n");
1027     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1028     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1029     cpu->cd.x86.r[X86_R_AX] |= 0x8600; /* TODO */
1030     break;
1031     case 0x06: /* TODO */
1032     fatal("[ PC BIOS int 0x15,0x06: TODO ]\n");
1033     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1034     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1035     cpu->cd.x86.r[X86_R_AX] |= 0x8600; /* TODO */
1036     break;
1037     case 0x24: /* TODO */
1038     fatal("[ PC BIOS int 0x15,0x24: TODO ]\n");
1039     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1040     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1041     cpu->cd.x86.r[X86_R_AX] |= 0x8600; /* TODO */
1042     break;
1043     case 0x41: /* TODO */
1044     fatal("[ PC BIOS int 0x15,0x41: TODO ]\n");
1045     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1046     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1047     cpu->cd.x86.r[X86_R_AX] |= 0x8600; /* TODO */
1048     break;
1049     case 0x4f: /* Keyboard Scancode Intercept (TODO) */
1050     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1051     break;
1052     case 0x53: /* TODO */
1053     fatal("[ PC BIOS int 0x15,0x53: TODO ]\n");
1054     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1055     break;
1056     case 0x86: /* Wait */
1057     /* No. :-) */
1058     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1059     break;
1060     case 0x87: /* Move to/from extended memory, via a GDT */
1061     cpu->cd.x86.cursegment = X86_S_ES;
1062     cpu->memory_rw(cpu, cpu->mem, si + 0x10, src_entry, 8,
1063     MEM_READ, CACHE_DATA);
1064     cpu->memory_rw(cpu, cpu->mem, si + 0x18, dst_entry, 8,
1065     MEM_READ, CACHE_DATA);
1066     src_addr = src_entry[2]+(src_entry[3]<<8)+(src_entry[4]<<16);
1067     dst_addr = dst_entry[2]+(dst_entry[3]<<8)+(dst_entry[4]<<16);
1068     if (src_entry[5] != 0x92 && src_entry[5] != 0x93)
1069     fatal("WARNING: int15,87: bad src access right?"
1070     " (0x%02x, should be 0x93)\n", src_entry[5]);
1071     if (dst_entry[5] != 0x92 && dst_entry[5] != 0x93)
1072     fatal("WARNING: int15,87: bad dst access right?"
1073     " (0x%02x, should be 0x93)\n", dst_entry[5]);
1074     debug("[ pc_bios: INT15: copying %i bytes from 0x%x to 0x%x"
1075     " ]\n", cx*2, src_addr, dst_addr);
1076     if (cx > 0x8000)
1077     fatal("WARNING! INT15 func 0x87 cx=0x%04x, max allowed"
1078     " is supposed to be 0x8000!\n", cx);
1079     while (cx*2 > 0) {
1080     unsigned char buf[2];
1081     cpu->memory_rw(cpu, cpu->mem, src_addr, buf, 2,
1082     MEM_READ, NO_SEGMENTATION | CACHE_DATA);
1083     cpu->memory_rw(cpu, cpu->mem, dst_addr, buf, 2,
1084     MEM_WRITE, NO_SEGMENTATION | CACHE_DATA);
1085     src_addr += 2; dst_addr += 2; cx --;
1086     }
1087     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1088     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1089     cpu->cd.x86.rflags |= X86_FLAGS_ZF;
1090     break;
1091     case 0x88: /* Extended Memory Size Determination */
1092     /* TODO: Max 16 or 64 MB? */
1093     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1094     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
1095     if (cpu->machine->physical_ram_in_mb <= 64)
1096     cpu->cd.x86.r[X86_R_AX] |= (cpu->machine->
1097     physical_ram_in_mb - 1) * 1024;
1098     else
1099     cpu->cd.x86.r[X86_R_AX] |= 63*1024;
1100     break;
1101     case 0x8A: /* Get "Big" memory size */
1102     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1103     m = (cpu->machine->physical_ram_in_mb - 1) * 1024;
1104     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
1105     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
1106     cpu->cd.x86.r[X86_R_DX] |= ((m >> 16) & 0xffff);
1107     cpu->cd.x86.r[X86_R_AX] |= (m & 0xffff);
1108     break;
1109     case 0x91: /* Interrupt Complete (bogus) */
1110     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1111     break;
1112     case 0xc0: /* System Config: (at 0xfffd:0) */
1113     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1114     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1115     cpu->cd.x86.r[X86_R_BX] &= ~0xffff;
1116     cpu->cd.x86.s[X86_S_ES] = 0xfffd;
1117     reload_segment_descriptor(cpu, X86_S_ES, 0xfffd, NULL);
1118     break;
1119     case 0xc1: /* Extended Bios Data-seg (TODO) */
1120     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1121     break;
1122     case 0xe8: /* TODO */
1123     switch (al) {
1124     case 0x01:
1125     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1126     m = cpu->machine->physical_ram_in_mb;
1127     if (m > 16)
1128     m = 16;
1129     m = (m - 1) * 1024;
1130     /* between 1MB and 16MB: (1KB blocks) */
1131     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
1132     cpu->cd.x86.r[X86_R_AX] |= (m & 0xffff);
1133     /* mem above 16MB, 64K blocks: */
1134     m = cpu->machine->physical_ram_in_mb;
1135     if (m < 16)
1136     m = 0;
1137     else
1138     m = (m-16) / 16;
1139     cpu->cd.x86.r[X86_R_BX] &= ~0xffff;
1140     cpu->cd.x86.r[X86_R_BX] |= (m & 0xffff);
1141     /* CX and DX are "configured" memory */
1142     cpu->cd.x86.r[X86_R_CX] &= ~0xffff;
1143     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
1144     cpu->cd.x86.r[X86_R_CX] |= (
1145     cpu->cd.x86.r[X86_R_AX] & 0xffff);
1146     cpu->cd.x86.r[X86_R_DX] |= (
1147     cpu->cd.x86.r[X86_R_BX] & 0xffff);
1148     break;
1149     case 0x20: /* Get memory map: TODO */
1150     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1151     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1152     cpu->cd.x86.r[X86_R_AX] |= 0x8600;
1153     break;
1154     default:fatal("[ PC BIOS int 0x15,0xe8: al=0x%02x "
1155     " TODO ]\n", al);
1156     cpu->running = 0;
1157     }
1158     break;
1159     default:
1160     fatal("FATAL: Unimplemented PC BIOS interrupt 0x15 function"
1161     " 0x%02x.\n", ah);
1162     cpu->running = 0;
1163     cpu->dead = 1;
1164     }
1165     }
1166    
1167    
1168     /*
1169     * pc_bios_int16():
1170     *
1171     * Keyboard-related functions.
1172     */
1173     static int pc_bios_int16(struct cpu *cpu, int *enable_ints_after_returnp)
1174     {
1175     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
1176     /* int al = cpu->cd.x86.r[X86_R_AX] & 0xff; */
1177     int scancode, asciicode;
1178     unsigned char tmpchar;
1179    
1180     switch (ah) {
1181     case 0x00: /* getchar */
1182     scancode = asciicode = 0;
1183     if (cpu->machine->md.pc.kbd_buf_head !=
1184     cpu->machine->md.pc.kbd_buf_tail) {
1185     asciicode = cpu->machine->md.pc.kbd_buf[
1186     cpu->machine->md.pc.kbd_buf_head];
1187     scancode = cpu->machine->md.pc.kbd_buf_scancode[
1188     cpu->machine->md.pc.kbd_buf_head];
1189     if (asciicode != 0) {
1190     cpu->cd.x86.r[X86_R_AX] =
1191     (scancode << 8) | asciicode;
1192     }
1193     cpu->machine->md.pc.kbd_buf_head ++;
1194     cpu->machine->md.pc.kbd_buf_head %=
1195     PC_BIOS_KBD_BUF_SIZE;
1196     }
1197     *enable_ints_after_returnp = 1;
1198     if (asciicode == 0)
1199     return 0;
1200     break;
1201     case 0x01: /* non-destructive "isavail" */
1202     cpu->cd.x86.rflags |= X86_FLAGS_ZF;
1203     cpu->cd.x86.r[X86_R_AX] &= ~0xffff;
1204     scancode = asciicode = 0;
1205     if (cpu->machine->md.pc.kbd_buf_head !=
1206     cpu->machine->md.pc.kbd_buf_tail) {
1207     asciicode = cpu->machine->md.pc.kbd_buf[
1208     cpu->machine->md.pc.kbd_buf_head];
1209     scancode = cpu->machine->md.pc.kbd_buf_scancode[
1210     cpu->machine->md.pc.kbd_buf_head];
1211     cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
1212     cpu->cd.x86.r[X86_R_AX] |= (scancode << 8) | asciicode;
1213     }
1214     *enable_ints_after_returnp = 1;
1215     break;
1216     case 0x02: /* read keyboard flags */
1217     /* TODO: keep this byte updated */
1218     cpu->memory_rw(cpu, cpu->mem, 0x417, &tmpchar, 1,
1219     MEM_READ, PHYSICAL);
1220     cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff)
1221     | tmpchar;
1222     break;
1223     case 0x03: /* Set Keyboard Typematic Rate: TODO */
1224     break;
1225     case 0x55: /* Microsoft stuff: Ignore :-) */
1226     break;
1227     case 0x92: /* Keyboard "Capabilities Check": TODO */
1228     break;
1229     default:
1230     fatal("FATAL: Unimplemented PC BIOS interrupt 0x16 function"
1231     " 0x%02x.\n", ah);
1232     cpu->running = 0;
1233     cpu->dead = 1;
1234     }
1235    
1236     return 1;
1237     }
1238    
1239    
1240     /*
1241     * pc_bios_int17():
1242     *
1243     * Printer port stuff.
1244     */
1245     static void pc_bios_int17(struct cpu *cpu)
1246     {
1247     int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
1248    
1249     switch (ah) {
1250     case 0x01:
1251     debug("[ PC BIOS int 0x17,0x01: TODO ]\n");
1252     cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
1253     break;
1254     default:
1255     fatal("FATAL: Unimplemented PC BIOS interrupt 0x17 function"
1256     " 0x%02x.\n", ah);
1257     cpu->running = 0;
1258     cpu->dead = 1;
1259     }
1260     }
1261    
1262    
1263     /*
1264 dpavlin 4 * pc_bios_int1a():
1265     *
1266     * Time of Day stuff.
1267     */
1268     static void pc_bios_int1a(struct cpu *cpu)
1269     {
1270 dpavlin 6 unsigned char ticks[4];
1271 dpavlin 4 int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
1272 dpavlin 6 time_t tim;
1273     struct tm *tm;
1274 dpavlin 4
1275     switch (ah) {
1276 dpavlin 6 case 0x00: /* Read tick count. */
1277     cpu->memory_rw(cpu, cpu->mem, 0x46C,
1278     ticks, sizeof(ticks), MEM_READ, CACHE_NONE | PHYSICAL);
1279     cpu->cd.x86.r[X86_R_CX] = (ticks[3] << 8) | ticks[2];
1280     cpu->cd.x86.r[X86_R_DX] = (ticks[1] << 8) | ticks[0];
1281 dpavlin 4 break;
1282 dpavlin 6 case 0x01: /* Set tick count. */
1283     ticks[0] = cpu->cd.x86.r[X86_R_DX];
1284     ticks[1] = cpu->cd.x86.r[X86_R_DX] >> 8;
1285     ticks[2] = cpu->cd.x86.r[X86_R_CX];
1286     ticks[3] = cpu->cd.x86.r[X86_R_CX] >> 8;
1287     cpu->memory_rw(cpu, cpu->mem, 0x46C,
1288     ticks, sizeof(ticks), MEM_WRITE, CACHE_NONE | PHYSICAL);
1289     break;
1290     case 0x02: /* Read real time clock time (AT,PS/2) */
1291     tim = time(NULL);
1292     tm = gmtime(&tim);
1293     cpu->cd.x86.r[X86_R_CX] &= ~0xffff;
1294     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
1295     cpu->cd.x86.r[X86_R_CX] |= (dec_to_bcd(tm->tm_hour) << 8) |
1296     dec_to_bcd(tm->tm_min);
1297     cpu->cd.x86.r[X86_R_DX] |= dec_to_bcd(tm->tm_sec) << 8;
1298     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1299     break;
1300     case 0x04: /* Read real time clock date (AT,PS/2) */
1301     tim = time(NULL);
1302     tm = gmtime(&tim);
1303     cpu->cd.x86.r[X86_R_CX] &= ~0xffff;
1304     cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
1305     cpu->cd.x86.r[X86_R_CX] |=
1306     (dec_to_bcd((tm->tm_year+1900)/100) << 8) |
1307     dec_to_bcd(tm->tm_year % 100);
1308     cpu->cd.x86.r[X86_R_DX] |= (dec_to_bcd(tm->tm_mon+1) << 8) |
1309     dec_to_bcd(tm->tm_mday);
1310     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
1311     break;
1312     case 0xb1: /* Intel PCI Bios */
1313     /* ... not installed :) */
1314     cpu->cd.x86.rflags |= X86_FLAGS_CF;
1315     break;
1316 dpavlin 4 default:
1317     fatal("FATAL: Unimplemented PC BIOS interrupt 0x1a function"
1318     " 0x%02x.\n", ah);
1319     cpu->running = 0;
1320     cpu->dead = 1;
1321     }
1322     }
1323    
1324    
1325     /*
1326 dpavlin 6 * pc_bios_int1c():
1327     *
1328     * Increase the timer-tick word at 0x40:0x6C.
1329     */
1330     static void pc_bios_int1c(struct cpu *cpu)
1331     {
1332     unsigned char ticks[4];
1333     int i;
1334    
1335     /* Increase word at 0x0040:0x006C */
1336     cpu->memory_rw(cpu, cpu->mem, 0x46C,
1337     ticks, sizeof(ticks), MEM_READ, CACHE_NONE | PHYSICAL);
1338     for (i=0; i<sizeof(ticks); i++) {
1339     ticks[i] ++;
1340     if (ticks[i] != 0)
1341     break;
1342     }
1343     cpu->memory_rw(cpu, cpu->mem, 0x46C,
1344     ticks, sizeof(ticks), MEM_WRITE, CACHE_NONE | PHYSICAL);
1345     }
1346    
1347    
1348     /*
1349     * pc_bios_smp_init():
1350     *
1351     * Initialize the "_MP_" struct in BIOS memory.
1352     *
1353     * TODO: Don't use hardcoded values like this.
1354     */
1355     void pc_bios_smp_init(struct cpu *cpu)
1356     {
1357     int i, chksum;
1358    
1359     reload_segment_descriptor(cpu, X86_S_FS, 0xf000, NULL);
1360     store_buf(cpu, 0x9000, "_MP_", 4);
1361     store_byte(cpu, 0x9004, 0x10); /* ptr to table */
1362     store_byte(cpu, 0x9005, 0x90);
1363     store_byte(cpu, 0x9006, 0x0f);
1364     store_byte(cpu, 0x9007, 0x00);
1365     store_byte(cpu, 0x9008, 0x01); /* length. should be 1 */
1366     store_byte(cpu, 0x9009, 0x04); /* version. 4 means "1.4" */
1367     /* Byte at 0x0a is checksum. TODO: make this automagic */
1368     chksum = '_' + 'M' + 'P' + '_' + 0x10 + 0x90 + 0xf + 1 + 4;
1369     store_byte(cpu, 0x900a, 0 - chksum);
1370    
1371     /* PCMP struct, at addr 0x9010. */
1372     store_buf(cpu, 0x9010, "PCMP", 4);
1373     store_16bit_word(cpu, 0x9014, 43);
1374     store_byte(cpu, 0x9016, 4); /* rev 1.4 */
1375     /* 9017 is checksum */
1376     store_buf(cpu, 0x9018, "GXemul ", 8);
1377     store_buf(cpu, 0x9020, "SMP ", 12);
1378    
1379     /* Nr of entries (one per cpu): */
1380     store_16bit_word(cpu, 0x9010 + 34, cpu->machine->ncpus);
1381    
1382     if (cpu->machine->ncpus > 16)
1383     fatal("WARNING: More than 16 CPUs?\n");
1384    
1385     for (i=0; i<cpu->machine->ncpus; i++) {
1386     int ofs = 44 + 20*i;
1387     /* 20 bytes per CPU: */
1388     store_byte(cpu, 0x9010 + ofs + 0, 0x00); /* cpu */
1389     store_byte(cpu, 0x9010 + ofs + 1, i); /* id */
1390     store_byte(cpu, 0x9010 + ofs + 3, 1 | /* enable */
1391     ((i == cpu->machine->bootstrap_cpu)? 2 : 0));
1392     }
1393     }
1394    
1395    
1396     /*
1397     * pc_bios_simple_pmode_setup():
1398     *
1399     * This function is called from emul.c before loading a 32-bit or 64-bit ELF.
1400     * Loading ELFs when the emulation is set to 16-bit real mode is not a good
1401     * thing, so this function sets up a simple GDT which maps every 0xZyyyyyyy
1402     * to 0x0yyyyyyy.
1403     *
1404     * 0xf4000 GDT:
1405     * 00 = NULL
1406     * 08 = code
1407     * 10 = data
1408     */
1409     void pc_bios_simple_pmode_setup(struct cpu *cpu)
1410     {
1411     int i, j, addr = 0, npts;
1412     uint32_t pt_base;
1413     cpu->cd.x86.cursegment = X86_S_FS;
1414     reload_segment_descriptor(cpu, X86_S_FS, 0xf100, NULL);
1415    
1416     /* 0x00 = NULL descriptor. */
1417     addr += 8;
1418    
1419     /* 0x08 = Code descriptor. */
1420     store_byte(cpu, addr + 0, 0xff);
1421     store_byte(cpu, addr + 1, 0xff);
1422     store_byte(cpu, addr + 2, 0x00);
1423     store_byte(cpu, addr + 3, 0x00);
1424     store_byte(cpu, addr + 4, 0x00);
1425     store_byte(cpu, addr + 5, 0x9f);
1426     store_byte(cpu, addr + 6, 0xcf);
1427     store_byte(cpu, addr + 7, 0x00);
1428     addr += 8;
1429    
1430     /* 0x10 = Data descriptor. */
1431     store_byte(cpu, addr + 0, 0xff);
1432     store_byte(cpu, addr + 1, 0xff);
1433     store_byte(cpu, addr + 2, 0x00);
1434     store_byte(cpu, addr + 3, 0x00);
1435     store_byte(cpu, addr + 4, 0x00);
1436     store_byte(cpu, addr + 5, 0x93);
1437     store_byte(cpu, addr + 6, 0xcf);
1438     store_byte(cpu, addr + 7, 0x00);
1439     addr += 8;
1440    
1441     cpu->cd.x86.gdtr = 0xf1000;
1442     cpu->cd.x86.gdtr_limit = 0xfff;
1443    
1444     addr = 0x1000;
1445     cpu->cd.x86.cr[3] = 0xf2000;
1446    
1447     npts = 4;
1448     pt_base = 0xf3000; /* 0xf3000, f4000, f5000, f6000 */
1449    
1450     /* Set up the page directory: */
1451     for (i=0; i<1024; i++) {
1452     uint32_t pde = pt_base + 0x03 + ((i & (npts-1)) << 12);
1453     store_32bit_word(cpu, addr + i*4, pde);
1454     }
1455     addr += 4096;
1456    
1457     /* Set up the page tables: */
1458     for (i=0; i<npts; i++) {
1459     for (j=0; j<1024; j++) {
1460     uint32_t pte = (i << 22) + (j << 12) + 0x03;
1461     store_32bit_word(cpu, addr + j*4, pte);
1462     }
1463     addr += 4096;
1464     }
1465    
1466     cpu->cd.x86.cr[0] |= X86_CR0_PE | X86_CR0_PG;
1467    
1468     /* Interrupts are dangerous when we start in pmode! */
1469     cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
1470    
1471     reload_segment_descriptor(cpu, X86_S_CS, 0x08, NULL);
1472     reload_segment_descriptor(cpu, X86_S_DS, 0x10, NULL);
1473     reload_segment_descriptor(cpu, X86_S_ES, 0x10, NULL);
1474     reload_segment_descriptor(cpu, X86_S_SS, 0x10, NULL);
1475     cpu->cd.x86.r[X86_R_SP] = 0x7000;
1476     cpu->cd.x86.cursegment = X86_S_DS;
1477     }
1478    
1479    
1480     /*
1481     * pc_bios_init():
1482     */
1483     void pc_bios_init(struct cpu *cpu)
1484     {
1485     char t[81];
1486     int x, y, nboxlines, i, any_disk = 0, disknr, tmp;
1487     int boot_id, boot_type, bios_boot_id = 0, nfloppies = 0, nhds = 0;
1488    
1489     /* Go to real mode: */
1490     cpu->cd.x86.cr[0] &= ~X86_CR0_PE;
1491    
1492     boot_id = diskimage_bootdev(cpu->machine, &boot_type);
1493    
1494     if (cpu->machine->md.pc.initialized) {
1495     fatal("ERROR: pc_bios_init(): Already initialized.\n");
1496     return;
1497     }
1498    
1499     if (cpu->machine->md.pc.pic1 == NULL) {
1500     fatal("ERROR: No interrupt controller?\n");
1501     exit(1);
1502     } else
1503     cpu->machine->md.pc.pic1->irq_base = 0x08;
1504    
1505     /* pic2 can be NULL when emulating an original XT: */
1506     if (cpu->machine->md.pc.pic2 != NULL)
1507     cpu->machine->md.pc.pic2->irq_base = 0x70;
1508    
1509     /* Disk Base Table (11 or 12 bytes?) at F000h:EFC7: */
1510     cpu->cd.x86.cursegment = X86_S_FS;
1511     reload_segment_descriptor(cpu, X86_S_FS, 0xf000, NULL);
1512     store_byte(cpu, 0xefc7 + 0, 0xcf);
1513     store_byte(cpu, 0xefc7 + 1, 0xb8);
1514     store_byte(cpu, 0xefc7 + 2, 1); /* timer ticks till shutoff */
1515     store_byte(cpu, 0xefc7 + 3, 2); /* 512 bytes per sector */
1516     store_byte(cpu, 0xefc7 + 4, 17);
1517     store_byte(cpu, 0xefc7 + 5, 0xd8);
1518     store_byte(cpu, 0xefc7 + 6, 0xff);
1519     store_byte(cpu, 0xefc7 + 7, 0);
1520     store_byte(cpu, 0xefc7 + 8, 0xf6);
1521     store_byte(cpu, 0xefc7 + 9, 1); /* head bounce delay in msec */
1522     store_byte(cpu, 0xefc7 + 10, 1);/* motor start time in 1/8 secs */
1523     store_byte(cpu, 0xefc7 + 11, 1);/* motor stop time in 1/4 secs */
1524    
1525     /* BIOS System Configuration Parameters (8 bytes) at 0xfffd:0: */
1526     reload_segment_descriptor(cpu, X86_S_FS, 0xfffd, NULL);
1527     store_byte(cpu, 0, 8); store_byte(cpu, 1, 0); /* len */
1528     store_byte(cpu, 2, 0xfc); /* model */
1529     store_byte(cpu, 3, 0); /* sub-model */
1530     store_byte(cpu, 4, 0); /* bios revision */
1531     store_byte(cpu, 5, 0x60); /* features */
1532     /* see http://members.tripod.com/~oldboard/assembly/
1533     int_15-c0.html for details */
1534    
1535     /* Some info in the last paragraph of the BIOS: */
1536     reload_segment_descriptor(cpu, X86_S_FS, 0xffff, NULL);
1537     /* TODO: current date :-) */
1538     store_byte(cpu, 0x05, '0'); store_byte(cpu, 0x06, '1');
1539     store_byte(cpu, 0x07, '/');
1540     store_byte(cpu, 0x08, '0'); store_byte(cpu, 0x09, '1');
1541     store_byte(cpu, 0x0a, '/');
1542     store_byte(cpu, 0x0b, '0'); store_byte(cpu, 0x0c, '5');
1543     store_byte(cpu, 0x0e, 0xfc);
1544    
1545     /* Copy the first 128 chars of the 8x8 VGA font into 0xf000:0xfa6e */
1546     reload_segment_descriptor(cpu, X86_S_FS, 0xf000, NULL);
1547     store_buf(cpu, 0xfa6e, (char *)font8x8, 8*128);
1548     store_buf(cpu, 0xfa6e - 1024, (char *)font8x8 + 1024, 8*128);
1549    
1550     /*
1551     * Initialize all real-mode interrupt vectors to point to somewhere
1552     * within the PC BIOS area (0xf000:0x8yy0), and place an IRET
1553     * instruction (too fool someone who really reads the BIOS memory).
1554     */
1555     for (i=0; i<256; i++) {
1556     if (i == 0x20)
1557     i = 0x70;
1558     if (i == 0x78)
1559     break;
1560     reload_segment_descriptor(cpu, X86_S_FS, 0x0000, NULL);
1561     store_16bit_word(cpu, i*4, 0x8000 + i*16);
1562     store_16bit_word(cpu, i*4 + 2, 0xf000);
1563    
1564     /* Exceptions: int 0x1e = ptr to disk table, 1f=fonthigh */
1565     if (i == 0x1e)
1566     store_16bit_word(cpu, i*4, 0xefc7);
1567     if (i == 0x1f)
1568     store_16bit_word(cpu, i*4, 0xfa6e - 1024);
1569    
1570     reload_segment_descriptor(cpu, X86_S_FS, 0xf000, NULL);
1571     store_byte(cpu, 0x8000 + i*16, 0xCF); /* IRET */
1572     }
1573    
1574     /* For SMP emulation, create an "MP" struct in BIOS memory: */
1575     if (cpu->machine->ncpus > 1)
1576     pc_bios_smp_init(cpu);
1577    
1578     /* Prepare for text mode: (0x03 = 80x25, 0x01 = 40x25) */
1579     set_video_mode(cpu, 0x03);
1580    
1581     cmos_write(cpu, 0x15, 640 & 255);
1582     cmos_write(cpu, 0x16, 640 >> 8);
1583     tmp = cpu->machine->physical_ram_in_mb / 1024;
1584     if (tmp > 63*1024)
1585     tmp = 63*1024;
1586     cmos_write(cpu, 0x17, tmp & 255);
1587     cmos_write(cpu, 0x18, tmp >> 8);
1588    
1589     /* Clear the screen first: */
1590     set_cursor_pos(cpu, 0, 0);
1591     for (y=0; y<cpu->machine->md.pc.rows; y++)
1592     for (x=0; x<cpu->machine->md.pc.columns; x++)
1593     output_char(cpu, x,y, ' ', 0x07);
1594    
1595     nboxlines = cpu->machine->md.pc.columns <= 40? 4 : 3;
1596    
1597     /* Draw a nice box at the top: */
1598     for (y=0; y<nboxlines; y++)
1599     for (x=0; x<cpu->machine->md.pc.columns; x++) {
1600     unsigned char ch = ' ';
1601     if (cpu->machine->use_x11) {
1602     if (y == 0) {
1603     ch = 196;
1604     if (x == 0)
1605     ch = 218;
1606     if (x == cpu->machine->md.pc.columns-1)
1607     ch = 191;
1608     } else if (y == nboxlines-1) {
1609     ch = 196;
1610     if (x == 0)
1611     ch = 192;
1612     if (x == cpu->machine->md.pc.columns-1)
1613     ch = 217;
1614     } else if (x == 0 || x ==
1615     cpu->machine->md.pc.columns-1)
1616     ch = 179;
1617     } else {
1618     if (y == 0 || y == nboxlines-1) {
1619     ch = '-';
1620     if (x == 0 || x ==
1621     cpu->machine->md.pc.columns-1)
1622     ch = '+';
1623     } else {
1624     if (x == 0 || x ==
1625     cpu->machine->md.pc.columns-1)
1626     ch = '|';
1627     }
1628     }
1629     output_char(cpu, x,y, ch, 0x19);
1630     }
1631    
1632     sprintf(t, "GXemul");
1633     #ifdef VERSION
1634     sprintf(t + strlen(t), " "VERSION);
1635     #endif
1636     set_cursor_pos(cpu, 2, 1);
1637     pc_bios_printstr(cpu, t, 0x1f);
1638    
1639     sprintf(t, "%i cpu%s (%s), %i MB memory",
1640     cpu->machine->ncpus, cpu->machine->ncpus > 1? "s" : "",
1641     cpu->cd.x86.model.name, cpu->machine->physical_ram_in_mb);
1642     if (cpu->machine->md.pc.columns <= 40)
1643     set_cursor_pos(cpu, 2, 2);
1644     else
1645     set_cursor_pos(cpu, 78 - strlen(t), 1);
1646     pc_bios_printstr(cpu, t, 0x17);
1647     if (cpu->machine->md.pc.columns <= 40)
1648     set_cursor_pos(cpu, 0, 5);
1649     else
1650     set_cursor_pos(cpu, 0, 4);
1651    
1652     cpu->machine->md.pc.curcolor = 0x07;
1653    
1654     /* "Detect" Floppies, IDE disks, and SCSI disks: */
1655     for (i=0; i<4; i++) {
1656     if (diskimage_exist(cpu->machine, i, DISKIMAGE_FLOPPY)) {
1657     struct pc_bios_disk *p;
1658     p = add_disk(cpu->machine, i, i, DISKIMAGE_FLOPPY);
1659     sprintf(t, "%c%c", i<2? ('A'+i):' ', i<2? ':':' ');
1660     pc_bios_printstr(cpu, t, 0xf);
1661     if (i < 2)
1662     nfloppies ++;
1663     sprintf(t, " (bios disk %02x) FLOPPY", i);
1664     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1665     sprintf(t, ", %i KB", (int)(p->size / 1024));
1666     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1667     if (cpu->machine->md.pc.columns <= 40)
1668     pc_bios_printstr(cpu, "\n ", 0x07);
1669     sprintf(t, " (CHS=%i,%i,%i)", p->cylinders, p->heads,
1670     p->sectorspertrack);
1671     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1672     if (boot_id == i && boot_type == DISKIMAGE_FLOPPY) {
1673     bios_boot_id = i;
1674     pc_bios_printstr(cpu, " [boot device]", 0xf);
1675     }
1676     pc_bios_printstr(cpu, "\n",
1677     cpu->machine->md.pc.curcolor);
1678     any_disk = 1;
1679     }
1680     }
1681     disknr = 0x80;
1682     for (i=0; i<8; i++) {
1683     if (diskimage_exist(cpu->machine, i, DISKIMAGE_IDE)) {
1684     struct pc_bios_disk *p;
1685     p = add_disk(cpu->machine, disknr, i, DISKIMAGE_IDE);
1686     sprintf(t, "%s", disknr==0x80? "C:" : " ");
1687     pc_bios_printstr(cpu, t, 0xf);
1688     nhds ++;
1689     sprintf(t, " (bios disk %02x) IDE %s, id %i",
1690     disknr, diskimage_is_a_cdrom(cpu->machine, i,
1691     DISKIMAGE_IDE)? "cdrom" : (
1692     diskimage_is_a_tape(cpu->machine, i,
1693     DISKIMAGE_IDE)? "tape" : "disk"),
1694     i);
1695     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1696     if (cpu->machine->md.pc.columns <= 40)
1697     pc_bios_printstr(cpu, "\n ", 0x07);
1698     else
1699     pc_bios_printstr(cpu, ", ",
1700     cpu->machine->md.pc.curcolor);
1701     sprintf(t, "%lli MB", (long long) (p->size >> 20));
1702     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1703     if (boot_id == i && boot_type == DISKIMAGE_IDE) {
1704     bios_boot_id = disknr;
1705     pc_bios_printstr(cpu, " [boot device]", 0xf);
1706     }
1707     pc_bios_printstr(cpu, "\n",
1708     cpu->machine->md.pc.curcolor);
1709     disknr++;
1710     any_disk = 1;
1711     }
1712     }
1713     for (i=0; i<8; i++) {
1714     if (diskimage_exist(cpu->machine, i, DISKIMAGE_SCSI)) {
1715     struct pc_bios_disk *p;
1716     p = add_disk(cpu->machine, disknr, i, DISKIMAGE_SCSI);
1717     sprintf(t, "%s", disknr==0x80? "C:" : " ");
1718     pc_bios_printstr(cpu, t, 0xf);
1719     nhds ++;
1720     sprintf(t, " (bios disk %02x) SCSI disk, id %i",
1721     disknr, i);
1722     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1723     if (cpu->machine->md.pc.columns <= 40)
1724     pc_bios_printstr(cpu, "\n ", 0x07);
1725     else
1726     pc_bios_printstr(cpu, ", ",
1727     cpu->machine->md.pc.curcolor);
1728     sprintf(t, "%lli MB", (long long) (p->size >> 20));
1729     pc_bios_printstr(cpu, t, cpu->machine->md.pc.curcolor);
1730     if (boot_id == i && boot_type == DISKIMAGE_SCSI) {
1731     bios_boot_id = disknr;
1732     pc_bios_printstr(cpu, " [boot device]", 0xf);
1733     }
1734     pc_bios_printstr(cpu, "\n",
1735     cpu->machine->md.pc.curcolor);
1736     disknr++;
1737     any_disk = 1;
1738     }
1739     }
1740    
1741     if (any_disk)
1742     pc_bios_printstr(cpu, "\n", cpu->machine->md.pc.curcolor);
1743     else
1744     pc_bios_printstr(cpu, "No disks attached!\n\n", 0x0f);
1745    
1746     /* See http://members.tripod.com/~oldboard/assembly/bios_data_area.html
1747     for more info. */
1748     if (nfloppies > 0)
1749     nfloppies --;
1750    
1751     reload_segment_descriptor(cpu, X86_S_FS, 0x0000, NULL);
1752     store_16bit_word(cpu, 0x400, 0x03F8); /* COM1 */
1753     store_16bit_word(cpu, 0x402, 0x0378); /* COM2 */
1754     store_byte(cpu, 0x410, (nfloppies << 6) | 0x0f); /* nfloppies etc */
1755     store_byte(cpu, 0x411, 2 << 1); /* nserials etc */
1756     store_16bit_word(cpu, 0x413, 640); /* KB of low RAM */
1757     store_byte(cpu, 0x449, cpu->machine->md.pc.videomode); /* video mode */
1758     store_16bit_word(cpu, 0x44a, cpu->machine->md.pc.columns);/* columns */
1759     store_16bit_word(cpu, 0x463, 0x3D4); /* CRT base port */
1760     store_byte(cpu, 0x475, nhds); /* nr of harddisks */
1761     store_byte(cpu, 0x484, cpu->machine->md.pc.rows-1);/* nr of lines-1 */
1762     store_byte(cpu, 0x485, 16); /* font height */
1763    
1764     /* Registers passed to the bootsector code: */
1765     reload_segment_descriptor(cpu, X86_S_CS, 0x0000, NULL);
1766     reload_segment_descriptor(cpu, X86_S_DS, 0x0000, NULL);
1767     reload_segment_descriptor(cpu, X86_S_ES, 0x0000, NULL);
1768     reload_segment_descriptor(cpu, X86_S_SS, 0x0000, NULL);
1769    
1770     cpu->cd.x86.r[X86_R_AX] = 0xaa55;
1771     cpu->cd.x86.r[X86_R_CX] = 0x0001;
1772     cpu->cd.x86.r[X86_R_DI] = 0xffe4;
1773     cpu->cd.x86.r[X86_R_SP] = 0xfffe;
1774     cpu->cd.x86.r[X86_R_DX] = bios_boot_id;
1775    
1776     cpu->cd.x86.rflags |= X86_FLAGS_IF;
1777     cpu->pc = 0x7c00;
1778    
1779     cpu->machine->md.pc.initialized = 1;
1780     }
1781    
1782    
1783     /*
1784 dpavlin 4 * 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 dpavlin 6 int int_nr, flags;
1790     int enable_ints_after_return = 0;
1791     unsigned char w[2];
1792 dpavlin 4
1793 dpavlin 6 if (addr == 0xffff0) {
1794     fatal("[ bios reboot ]\n");
1795     cpu->running = 0;
1796     return 0;
1797     }
1798 dpavlin 4
1799 dpavlin 6 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 dpavlin 4 switch (int_nr) {
1809 dpavlin 6 case 0x02: /* NMI? */
1810     debug("[ pc_bios: NMI? TODO ]\n");
1811 dpavlin 4 break;
1812 dpavlin 6 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 dpavlin 4 case 0x13:
1829     pc_bios_int13(cpu);
1830 dpavlin 6 enable_ints_after_return = 1;
1831 dpavlin 4 break;
1832 dpavlin 6 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 dpavlin 4 break;
1841 dpavlin 6 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 dpavlin 4 default:
1854     fatal("FATAL: Unimplemented PC BIOS interrupt 0x%02x.\n",
1855     int_nr);
1856     cpu->running = 0;
1857     cpu->dead = 1;
1858 dpavlin 6 return 0;
1859 dpavlin 4 }
1860    
1861     /*
1862     * Return from the interrupt: Pop ip (pc), cs, and flags.
1863     */
1864 dpavlin 6 cpu->cd.x86.cursegment = X86_S_SS;
1865 dpavlin 4 cpu->pc = load_16bit_word(cpu, cpu->cd.x86.r[X86_R_SP]);
1866 dpavlin 6 reload_segment_descriptor(cpu, X86_S_CS,
1867     load_16bit_word(cpu, cpu->cd.x86.r[X86_R_SP] + 2), NULL);
1868 dpavlin 4
1869 dpavlin 6 /* Actually, don't pop flags, because they contain result bits
1870     from interrupt calls. Only pop the Interrupt Flag. */
1871     flags = load_16bit_word(cpu, cpu->cd.x86.r[X86_R_SP] + 4);
1872     cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
1873     cpu->cd.x86.rflags |= (flags & X86_FLAGS_IF);
1874    
1875     if (enable_ints_after_return)
1876     cpu->cd.x86.rflags |= X86_FLAGS_IF;
1877    
1878 dpavlin 4 cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] & ~0xffff)
1879     | ((cpu->cd.x86.r[X86_R_SP] + 6) & 0xffff);
1880    
1881     return 1;
1882     }
1883    
1884 dpavlin 6
1885     #endif /* ENABLE_X86 */

  ViewVC Help
Powered by ViewVC 1.1.26