"Fossies" - the Fresh Open Source Software Archive

Member "pcemu/bios.c" (22 Jan 2001, 32777 Bytes) of package /linux/privat/old/pcemu-1.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "bios.c" see the Fossies "Dox" file reference documentation.

    1 /****************************************************************************
    2 *                                                                           *
    3 *                            Third Year Project                             *
    4 *                                                                           *
    5 *                            An IBM PC Emulator                             *
    6 *                          For Unix and X Windows                           *
    7 *                                                                           *
    8 *                             By David Hedley                               *
    9 *                                                                           *
   10 *                                                                           *
   11 * This program is Copyrighted.  Consult the file COPYRIGHT for more details *
   12 *                                                                           *
   13 ****************************************************************************/
   14 
   15 /* This is BIOS.C It contains stuff about the ROM BIOS (at 0xf000:xxxx) */
   16 
   17 #include "global.h"
   18 
   19 #include <stdio.h>
   20 #include <fcntl.h>
   21 #include <unistd.h>
   22 #include <time.h>
   23 #include <signal.h>
   24 #include <string.h>
   25 #include <sys/stat.h>
   26 
   27 #include "cpu.h"
   28 #include "vga.h"
   29 #include "bios.h"
   30 #include "debugger.h"
   31 #include "vgahard.h"
   32 #include "hardware.h"
   33 
   34 #define BIOS
   35 
   36 #include "mfs_link.h"
   37 
   38 void (*bios_routine[256])(void);
   39 
   40 static BYTE *BIOS_base;
   41 static BYTE *data_segment;
   42 
   43 #define SYSTEMID 0xFB
   44 
   45 #define BIOSDATE "06/09/94"     /* Damned American date format :) */
   46 #define BIOSCOPYRIGHT "(c) 1994 University of Bristol"
   47 
   48 #define INT_ROUTINE_START 0x1000
   49 
   50 #define KB_1 (data_segment[0x17])
   51 #define KB_2 (data_segment[0x18])
   52 
   53 unsigned modifiers = 0;
   54 
   55 #define SHIFT_R 1
   56 #define SHIFT_L 2
   57 #define CTRL    4
   58 #define ALT     8
   59 #define SCROLL  16
   60 #define NUMLOCK 32
   61 #define CAPS    64
   62 #define INSERT  128
   63 
   64 #define CTRL_L  1
   65 #define ALT_L   2
   66 #define SYSREQ  4
   67 #define HOLD    8
   68 
   69 #define CTRL_R  4
   70 #define ALT_R   8
   71 
   72 #define update_flag(flag, key, state) \
   73        if (state) flag &= ~(key); else flag |= key;
   74 
   75 void open_drive(DiskTab [], int);
   76 
   77 int numhdisks = 0;
   78 int numfdisks = 2;
   79 
   80 DiskTab fdisk[MAXFDISKS] = {
   81     {"/dev/fd0", 18, 80, 2, 1, 0},
   82     {"/dev/fd1", 18, 80, 2, 1, 0}
   83 };
   84 
   85 DiskTab hdisk[MAXHDISKS] = {
   86     {"/dev/zero", 0, 0, 0, 0, 0},
   87     {"/dev/zero", 0, 0, 0, 0, 0}
   88 };
   89 
   90 int bootdisk = 0x0;
   91 static unsigned pos = INT_ROUTINE_START;
   92 
   93 #define diskerror data_segment[0x41]
   94 
   95 #define GetCurKeyBufStart()     GetMemW(data_segment, 0x1a)
   96 #define GetCurKeyBufEnd()       GetMemW(data_segment, 0x1c)
   97 #define GetKeyBufStart()        GetMemW(data_segment, 0x80)
   98 #define GetKeyBufEnd()          GetMemW(data_segment, 0x82)
   99 
  100 #define SetCurKeyBufStart(addr) PutMemW(data_segment, 0x1a, addr)
  101 #define SetCurKeyBufEnd(addr)   PutMemW(data_segment, 0x1c, addr)
  102 #define SetKeyBufStart(addr)    PutMemW(data_segment, 0x80, addr)
  103 #define SetKeyBufEnd(addr)      PutMemW(data_segment, 0x82, addr)
  104 
  105 static unsigned num = 0;
  106 
  107 struct vm86_struct vm86s;
  108 char tmpdir[] = "/tmp";
  109 
  110 #include "keytabs.h"
  111 
  112 
  113 void loc(void)
  114 {
  115     unsigned count = 200;
  116     unsigned sp, seg, off;
  117 
  118     for (sp = ChangeE(wregs[SP]); count > 0 ; sp+=2, count--)
  119     {
  120         seg = GetMemW(c_stack, (WORD)(sp+2));
  121         off = (WORD)(GetMemW(c_stack, sp) - 2);
  122         if (memory[(seg << 4) + off] == 0xcd)
  123             break;
  124     }
  125     if (count == 0)
  126         printf("Sorry - no information as to the location of the problem\n");
  127     else
  128         printf("Routine called from cs:ip = %04X:%04X\n", seg, off);
  129 }
  130 
  131 
  132 static void put_ticks(UINT32 ticks)
  133 {
  134     PutMemB(data_segment, 0x6c, (BYTE)ticks);
  135     ticks >>= 8;
  136     PutMemB(data_segment, 0x6d, (BYTE)ticks);
  137     ticks >>= 8;
  138     PutMemB(data_segment, 0x6e, (BYTE)ticks);
  139     ticks >>= 8;
  140     PutMemB(data_segment, 0x6f, (BYTE)ticks);
  141 }
  142 
  143 
  144 void set_int(unsigned intno, BYTE *before, unsigned bcount,
  145              void (*routine)(void), BYTE *after, unsigned acount)
  146 {
  147     PutMemW(memory,intno*4,pos);
  148     PutMemW(memory,intno*4+2,0xf000);
  149 
  150     if (before && bcount > 0)
  151     {
  152         memcpy(&BIOS_base[pos], before, bcount);
  153         pos += bcount;
  154     }
  155     
  156     if (routine)
  157     {
  158         bios_routine[intno] = routine;
  159         BIOS_base[pos++] = 0xf1; /* bios .... */
  160         BIOS_base[pos++] = 0xf1;
  161         BIOS_base[pos++] = intno;
  162         BIOS_base[pos++] = 0;
  163         BIOS_base[pos++] = 0;
  164         BIOS_base[pos++] = 0;
  165     }
  166 
  167     if (after && acount > 0)
  168     {
  169         memcpy(&BIOS_base[pos], after, acount);
  170         pos += acount;
  171     }
  172 }
  173 
  174 
  175 void set_vector(unsigned intno, unsigned seg, unsigned off)
  176 {
  177     PutMemW(memory,4*intno,off);
  178     PutMemW(memory,4*intno+2,seg);
  179 }
  180 
  181 
  182 static void int_serial(void)
  183 {
  184     D(printf("In serial. Function = 0x%02X\n", *bregs[AH]););
  185 
  186     CalcAll();
  187     switch(*bregs[AH])
  188     {
  189     default:
  190         *bregs[AH] = 0x80;
  191         D(printf("unsupported function\n"););
  192         break;
  193     }
  194 }
  195 
  196 
  197 static void int_printer(void)
  198 {
  199     D(printf("In printer. Function = 0x%02X\n", *bregs[AH]););
  200 
  201     CalcAll();
  202     switch(*bregs[AH])
  203     {
  204     default:
  205         *bregs[AH] = 1;
  206         D(printf("unsupported function\n"););
  207         break;
  208     }
  209 }
  210 
  211 
  212 int code_to_num(unsigned code)
  213 {
  214     unsigned ascii = scan_unshifted[code];
  215 
  216     if (ascii >= '0' && ascii <= '9')
  217         return ascii-'0';
  218 
  219     return -1;
  220 }
  221 
  222 
  223 void raw_to_BIOS(unsigned code, unsigned e0, unsigned *ascii, unsigned *scan)
  224 {
  225     BYTE *tab;
  226     int tmp;
  227 
  228     if (KB_1 & ALT)
  229     {
  230         *ascii = (code == 0x39) ? 0x20 : 0;
  231 
  232         if (!e0 && (tmp = code_to_num(code)) >= 0)
  233         {
  234             num = num*10 + tmp;
  235             *scan = 0;
  236             return;
  237         }
  238 
  239         if (code == 0x1c && e0)
  240             *scan = 0xa6;
  241         else
  242             *scan  = scan_alt[code];
  243         return;
  244     }
  245 
  246     if (KB_1 & CTRL)
  247     {
  248         if (code == 0x39)
  249         {
  250             *ascii = 0x20;
  251             *scan = code;
  252         }
  253         else if (code >= 0x36 && code <= 0x58)
  254         {
  255             *ascii = 0;
  256             *scan = scan_ctrl_high[code - 0x36];
  257         }
  258         else if (code == 0x03)
  259         {
  260             *ascii = 0;
  261             *scan = code;
  262         }
  263         else
  264         {
  265             *ascii = scan_ctrl[code];
  266             if (e0 && code == 0x1c)
  267                 *scan = 0xe0;
  268             else
  269                 *scan = *ascii ? code : 0;
  270         }
  271 
  272         return;
  273     }
  274 
  275     tab = scan_unshifted;
  276 
  277     if (KB_1 & (SHIFT_L | SHIFT_R))
  278     {
  279         if (code >= 0x3b && code <= 0x44)
  280         {
  281             *ascii = 0;
  282             *scan = code+25;
  283             return;
  284         }
  285         if (code == 0x57 || code == 0x58)
  286         {
  287             *ascii = 0;
  288             *scan = code+0x30;
  289             return;
  290         }
  291         tab = scan_shift;
  292     }
  293 
  294     if (e0 && code == 0x36)
  295         *ascii = '/';
  296     else if (e0 && code == 0x1c)
  297     {
  298         *ascii = 0x0d;
  299         *scan = 0xe0;
  300         return;
  301     }
  302     else if (e0 || (code >= 0x47 && code <= 0x53 && !(KB_1 & NUMLOCK)))
  303         *ascii = 0;
  304     else
  305     {
  306         *ascii = tab[code];
  307         if ((KB_1 & CAPS) && *ascii >= 'a' && *ascii <= 'z')
  308             *ascii &= 0xdf;
  309     }
  310     
  311     if (code == 0x57 || code == 0x58)
  312         *scan = code+0x2e;
  313     else
  314         *scan = code;
  315 }
  316 
  317 
  318 static void put_key_in_buffer(unsigned ascii, unsigned scan)
  319 {
  320     unsigned cstart, cend, bufstart, bufend, tmp;
  321     
  322     if (KB_2 & HOLD)
  323     {
  324         KB_2 &= ~HOLD;
  325         return;
  326     }
  327     
  328     cstart = GetCurKeyBufStart();
  329     cend = GetCurKeyBufEnd();
  330     bufstart = GetKeyBufStart();
  331     bufend = GetKeyBufEnd();
  332     
  333     tmp = cend;
  334     cend += 2;
  335     
  336     if (cend >= bufend)
  337         cend = bufstart;
  338     
  339     if (cend == cstart)
  340     {
  341         fprintf(stderr,"\a");
  342                     fflush(stderr);
  343     }
  344     else
  345     {
  346         D(printf("Writing ascii %02X scan %02X\n",ascii,scan););
  347         PutMemB(data_segment, tmp, ascii);
  348         PutMemB(data_segment, tmp+1, scan);
  349         SetCurKeyBufEnd(cend);
  350     }
  351 }
  352  
  353    
  354 void int9(void)
  355 {
  356     unsigned code, state, ascii, scan;
  357     static unsigned e0_code = FALSE;
  358 
  359     CalcAll();
  360 
  361     code = *bregs[AL];
  362 
  363     *bregs[AH] = 0;
  364 
  365     D(printf("Read: %02X\n", code););
  366     state = code & 0x80;
  367     
  368     if ((code & 0xe0) == 0xe0)
  369     {
  370         e0_code = TRUE;
  371         return;
  372     
  373     }
  374     code &= 0x7f;
  375 
  376     switch (code)
  377     {
  378     case 0x2a:
  379         update_flag(KB_1, SHIFT_L, state);
  380         break;
  381     case 0x3a:
  382         if (!state)
  383             KB_1 ^= CAPS;
  384         break;
  385     case 0x1d:
  386         if (e0_code)
  387         {
  388             update_flag(modifiers, CTRL_R, state);
  389         }
  390         else
  391         {
  392             update_flag(KB_2, CTRL_L, state);
  393             update_flag(modifiers, CTRL_L, state);
  394         }
  395         update_flag(KB_1, CTRL, !(modifiers & (CTRL_R | CTRL_L)));
  396         break;
  397     case 0x38:
  398         if (e0_code)
  399         {
  400             update_flag(modifiers, ALT_R, state);
  401         }
  402         else
  403         {
  404             update_flag(KB_2, ALT_L, state);
  405             update_flag(modifiers, ALT_L, state);
  406         }
  407         update_flag(KB_1, ALT, !(modifiers & (ALT_R | ALT_L)));
  408         if (state)
  409         {
  410             num &= 0xff;
  411             if (num)
  412                 put_key_in_buffer(num, 0);
  413         }
  414         else
  415             num = 0;
  416         break;
  417     case 0x36:
  418         if (!e0_code)
  419         {
  420             update_flag(KB_1, SHIFT_R, state);
  421             break;
  422         }
  423 
  424         /* else fall through.. */
  425     default:
  426         if (code == 0x52)
  427         {
  428             update_flag(KB_2, INSERT, state);
  429             if (state)
  430                 KB_1 &= ~INSERT;
  431         }
  432 
  433         if (!state)
  434         {
  435             if (code == 0x46 && (KB_1 & CTRL))
  436             {
  437                 unsigned cstart;
  438 
  439                 D(printf("Control-Break!\n"););
  440                 *bregs[AH] = 2;
  441                 PutMemB(data_segment, 0x71, 1);
  442                 cstart = GetCurKeyBufStart();   /* Clear keyboard buffer */
  443                 SetCurKeyBufEnd(cstart);
  444                 break;
  445             }
  446 
  447             if (code == 0x45 && (KB_1 & CTRL))
  448             {
  449                 if (!(KB_2 & HOLD))
  450                 {
  451                     D(printf("Pause!\n"););
  452                     *bregs[AH] = 1;
  453                     KB_2 |= HOLD;
  454                 }
  455                 break;
  456             }
  457 
  458             if (code == 0x53 && (KB_1 & CTRL) && (KB_1 & ALT))
  459             {
  460                 D(printf("Got exit request!\n"););
  461                 exit_emu();
  462                 /* Not reached */
  463             }
  464 
  465             raw_to_BIOS(code, e0_code, &ascii, &scan);
  466 
  467             D(printf("%02X/%02X\n", ascii, scan););
  468             if (ascii != 0 || scan != 0)
  469             {
  470                 if (!(KB_1 & ALT) && ascii == 0 && e0_code)
  471                     ascii = 0xe0;
  472 
  473                 put_key_in_buffer(ascii, scan);
  474             }
  475         }
  476         break;
  477     }
  478     e0_code = FALSE;
  479     D(printf("Exiting key interrupt\n"););
  480 }
  481 
  482 
  483 static void int_keyboard(void)
  484 {
  485     unsigned cstart, cend, bufstart, bufend;
  486     unsigned func = *bregs[AH];
  487     unsigned tmp;
  488 
  489     CalcAll();
  490     switch(func)
  491     {
  492     case 0x00:  /* Get non-extended key */
  493     case 0x10:  /* Get extended key */
  494         cstart = GetCurKeyBufStart();
  495         cend = GetCurKeyBufEnd();
  496         
  497         if (cstart != cend)
  498         {
  499             bufstart = GetKeyBufStart();
  500             bufend = GetKeyBufEnd();
  501             
  502             *bregs[AL] = GetMemB(data_segment, cstart);
  503             *bregs[AH] = GetMemB(data_segment, cstart+1);
  504             
  505             if (func == 0x00) {
  506                 if (*bregs[AH] == 0xe0) {
  507                     *bregs[AH] = 0x1c;
  508         }
  509                 else {
  510                     if (*bregs[AL] == 0xe0) {
  511                         *bregs[AL] = 0x00;
  512             }
  513         }
  514         }
  515 
  516             cstart += 2;
  517             
  518             if (cstart >= bufend)
  519                 cstart = bufstart;
  520             
  521             SetCurKeyBufStart(cstart);
  522             
  523             D(printf("Cleared key %02X\n", *bregs[AL]););
  524 
  525             *bregs[CL] = 1;
  526             break;
  527         }
  528         else
  529             *bregs[CL] = 0;
  530         break;
  531     case 0x01:  /* Get non-extended status */
  532     case 0x11:  /* Get extended status */
  533         cstart = GetCurKeyBufStart();
  534         cend = GetCurKeyBufEnd();
  535 
  536         if (cstart == cend)
  537             ZF = 1;
  538         else
  539         {
  540             *bregs[AL] = GetMemB(data_segment, cstart);
  541             *bregs[AH] = GetMemB(data_segment, cstart+1);
  542             
  543             if (func == 0x01) {
  544                 if (*bregs[AH] == 0xe0) {
  545                     *bregs[AH] = 0x1c;
  546         }
  547                 else {
  548                     if (*bregs[AL] == 0xe0) {
  549                         *bregs[AL] = 0x00;
  550             }
  551         }
  552         }
  553             
  554             ZF = 0;
  555             D(printf("Returning key %02X from INT 16 1/11\n", *bregs[AL]););
  556         }
  557 
  558         break;
  559     case 0x02:  /* Get keyboard flags */
  560         *bregs[AL] = KB_1;
  561         break;
  562     case 0x03:  /* Set repeat rate */
  563     case 0x04:  /* Set key click */
  564         break;
  565     case 0x05:  /* Push scan code */
  566         cstart = GetCurKeyBufStart();
  567         cend = GetCurKeyBufEnd();
  568         bufstart = GetKeyBufStart();
  569         bufend = GetKeyBufEnd();
  570         
  571         tmp = cend;
  572         cend += 2;
  573         
  574         if (cend >= bufend)
  575             cend = bufstart;
  576         
  577         if (cend == cstart)
  578         {
  579             CF = 1;
  580             *bregs[AL] = 1;
  581         }
  582         else
  583         {
  584             PutMemB(data_segment, tmp, *bregs[CL]);
  585             PutMemB(data_segment, tmp+1, *bregs[CH]);
  586             SetCurKeyBufEnd(cend);
  587             CF = 0;
  588             *bregs[AL] = 0;
  589         }
  590         break;
  591     case 0x12:  /* Get enhanced keyboard flags */
  592         *bregs[AL] = KB_1;
  593         *bregs[AH] = (!(!(modifiers & CTRL_L)) +
  594                       (!(!(modifiers & ALT_L)) << 1) +
  595                       (!(!(modifiers & CTRL_R)) << 2 ) +
  596                       (!(!(modifiers & ALT_R)) << 3) +
  597                       (!(!(KB_2 & SCROLL)) << 4) +
  598                       (!(!(KB_2 & NUMLOCK)) << 5) +
  599                       (!(!(KB_2 & CAPS)) << 6) +
  600                       (!(!(KB_2 & SYSREQ)) << 7));
  601         break;
  602     default:
  603         D(printf("Warning: unimplemented INT 16 function %02X\n",func););
  604         CF = 1;
  605         break;
  606     }
  607 }
  608 
  609 
  610 static void int_extended(void)
  611 {
  612     D(printf("In INT 0x15. Function = 0x%02X\n", *bregs[AH]););
  613 
  614     CalcAll();
  615     CF = 1;
  616     switch(*bregs[AH])
  617     {
  618     case 0x4f:
  619         break;
  620     case 0x85:
  621         CF = 0;
  622         break;
  623     case 0x10:
  624     case 0x41:
  625     case 0x64:
  626     case 0xc0:
  627     case 0xc1:
  628     case 0x84:
  629     case 0x87:
  630     case 0x88:
  631     case 0x89:
  632     case 0xd8:
  633         *bregs[AH] = 0x80;
  634         break;
  635     case 0x90:
  636     case 0x91:
  637         *bregs[AH] = 0;
  638         CF = 0;
  639         break;
  640     case 0xc2:
  641         *bregs[AH] = 1;
  642         break;
  643     default:
  644         printf("unimplement INT 15h function %02X\n",*bregs[AH]);
  645 #ifdef DEBUG
  646         loc();
  647         exit_emu();
  648 #else
  649         *bregs[AH] = 0x80;
  650 #endif
  651         break;
  652     }
  653 }
  654 
  655 
  656 static void int_basic(void)
  657 {
  658     CalcAll();
  659     D(printf("In BASIC\n"););
  660 }
  661 
  662 
  663 static void int_reboot(void)
  664 {
  665     CalcAll();
  666     D(printf("In reboot\n"););
  667     exit_emu();
  668 }
  669 
  670 
  671 static void int_equipment(void)
  672 {
  673     CalcAll();
  674     D(printf("In equipment\n"););
  675     *bregs[AL] = data_segment[0x10];
  676     *bregs[AH] = data_segment[0x11];
  677 }
  678 
  679 
  680 static void int_memory(void)
  681 {
  682     CalcAll();
  683     D(printf("In memory\n"););
  684     *bregs[AL] = data_segment[0x13];
  685     *bregs[AH] = data_segment[0x14];
  686 }
  687 
  688 
  689 static UINT32 get_ticks_since_midnight(void)
  690 {
  691     time_t curtime;
  692     struct tm *local;
  693     unsigned seconds;
  694 
  695     curtime = time(NULL);
  696     local = localtime(&curtime);
  697 
  698     seconds = (local->tm_hour * 3600) + (local->tm_min * 60) + local->tm_sec;
  699     return (TICKSPERSEC*seconds);
  700 }
  701 
  702 
  703 static void int_time(void)
  704 {
  705     time_t curtime;
  706     struct tm *local;
  707 
  708     D(printf("In time. Function = 0x%02X\n", *bregs[AH]););
  709 
  710     CalcAll();
  711     switch(*bregs[AH])
  712     {
  713     case 0:     /* Get ticks */
  714         put_ticks(get_ticks_since_midnight());
  715 
  716         *bregs[DL] = GetMemB(data_segment, 0x6c);
  717         *bregs[DH] = GetMemB(data_segment, 0x6d);
  718         *bregs[CL] = GetMemB(data_segment, 0x6e);
  719         *bregs[CH] = GetMemB(data_segment, 0x6f);
  720         *bregs[AL] = GetMemB(data_segment, 0x70);
  721 
  722         CF = 0;
  723 
  724 /*        D(printf("Returning %02X%02X%02X%02X\n", *bregs[CL], *bregs[CH],
  725                  *bregs[DH], *bregs[DL]);); */
  726         break;
  727     case 1:     /* Set ticks */
  728 
  729         PutMemB(data_segment, 0x6c, *bregs[DL]);
  730         PutMemB(data_segment, 0x6d, *bregs[DH]);
  731         PutMemB(data_segment, 0x6e, *bregs[CL]);
  732         PutMemB(data_segment, 0x6f, *bregs[CH]);
  733         break;
  734     case 2:     /* Get time */
  735         curtime = time(NULL);
  736         local = localtime(&curtime);
  737         
  738         *bregs[CH] = (local->tm_hour % 10) | ((local->tm_hour / 10) << 4);
  739         *bregs[CL] = (local->tm_min % 10) | ((local->tm_min / 10) << 4);
  740         *bregs[DH] = (local->tm_sec % 10) | ((local->tm_sec / 10) << 4);
  741         *bregs[DL] = local->tm_isdst > 0;
  742         CF = 0;
  743 
  744         put_ticks(get_ticks_since_midnight());
  745     case 3:     /* Set time */
  746         break;
  747     case 4:     /* Get date */
  748     {
  749         unsigned century, year, month;
  750 
  751         curtime = time(NULL);
  752         local = localtime(&curtime);
  753 
  754         century = 19 + (local->tm_year / 100);
  755         year = local->tm_year % 100;
  756         month = local->tm_mon+1;
  757         *bregs[CH] = (century % 10) | (century/10 << 4);
  758         *bregs[CL] = (year % 10) | (year/10 << 4);
  759         *bregs[DH] = (month % 10) | (month/10 << 4);
  760         *bregs[DL] = (local->tm_mday % 10) | (local->tm_mday/10 << 4);
  761         CF = 0;
  762     }
  763         break;
  764     case 0x5:
  765     case 0x6:
  766     case 0x7:
  767     case 0x08:
  768     case 0x09:
  769     case 0x0a:
  770     case 0x0b:
  771     case 0x35:  /* ??? Called by word perfect ??? */
  772     case 0x36:  /* ditto */
  773         CF = 1;
  774         break;
  775     default:
  776         printf("unimplemented INT 1Ah function %02X\n", *bregs[AH]);
  777 #ifdef DEBUG
  778         loc();
  779         exit_emu();
  780 #endif
  781         break;
  782     }
  783 }
  784 
  785 
  786 static DiskTab *get_disk_tab(int num)
  787 {
  788     if (num < numfdisks)
  789         return &fdisk[num];
  790     
  791     num -= 0x80;
  792     if ((num < numhdisks) && (num >= 0))
  793         return &hdisk[num];
  794     
  795     return NULL;
  796 }
  797 
  798 
  799 static int disk_seek(DiskTab *disk, int cylinder, int head, int sector)
  800 {
  801     unsigned pos;
  802 
  803     if (head > disk->heads || cylinder > disk->cylinders ||
  804         sector > disk->sectors)
  805     {
  806         CF = 1;
  807         *bregs[AH] = diskerror = 0x4;  /* Sector not found */
  808         return -1;
  809     }
  810     pos = ((cylinder*disk->heads + head)*disk->sectors + sector) << 9;
  811     if (pos != lseek(disk->fd, pos, 0))
  812     {
  813         CF = 1;
  814         *bregs[AH] = diskerror = 0x4;  /* Sector not found */
  815         return -1;
  816     }
  817     return 0;
  818 }
  819 
  820 
  821 static void int_disk(void)
  822 {
  823     int head, sector, cylinder, res, num;
  824     BYTE *buffer;
  825     DiskTab *disk;
  826 
  827     res = 0;
  828 
  829     CalcAll();
  830 
  831     switch(*bregs[AH])
  832     {
  833     case 0:
  834         D(printf("Initialise disk 0x%02X\n",*bregs[DL]););
  835         CF = 0;
  836         break;
  837     case 1:  /* Get last error */
  838         D(printf("Get last disk error\n"););
  839         *bregs[AH] = 0;
  840         *bregs[AL] = diskerror;
  841         break;
  842     case 2:  /* Read sector */
  843         disk = get_disk_tab(*bregs[DL]);
  844         if (!disk)
  845         {
  846             CF = 1;
  847             *bregs[AH] = diskerror = 0xaa;  /* Drive not ready... */
  848             break;
  849         }
  850         head = *bregs[DH];
  851         cylinder = *bregs[CH] + ((*bregs[CL] & 0xc0) << 2);
  852         sector = (*bregs[CL] & 0x3f) -1;
  853         buffer = &c_es[ChangeE(wregs[BX])];
  854         D(printf("DISK 0x%02X (%s) read [h%d,s%d,t%d](%d)->%04X:%04X\n",
  855                  *bregs[DL], disk->name, head, sector, cylinder, *bregs[AL],
  856                  sregs[ES], ChangeE(wregs[BX])););
  857         if (disk_seek(disk, cylinder, head, sector))
  858             break;
  859 
  860         num = *bregs[AL] << 9;
  861         res = read(disk->fd, buffer, num);
  862         if (res & 0x1ff)
  863         {
  864             CF = 1;
  865             *bregs[AH] = diskerror = 0x2;  /* Sector corrupt */
  866             break;
  867         }
  868         *bregs[AH] = diskerror = 0;
  869         *bregs[AL] = res >> 9;
  870         CF = 0;
  871         break;
  872     case 3:  /* Write sector */
  873         disk = get_disk_tab(*bregs[DL]);
  874         if (!disk)
  875         {
  876             CF = 1;
  877             *bregs[AH] = diskerror = 0xaa;  /* Drive not ready... */
  878             break;
  879         }
  880         head = *bregs[DH];
  881         cylinder = *bregs[CH] + ((*bregs[CL] & 0xc0) << 8);
  882         sector = (*bregs[CL] & 0x3f) -1;
  883         buffer = &c_es[ChangeE(wregs[BX])];
  884         D(printf("DISK 0x%02X (%s) read [h%d,s%d,t%d](%d)->%04X:%04X\n",
  885                  *bregs[DL], disk->name, head, sector, cylinder, *bregs[AL],
  886                  sregs[ES], ChangeE(wregs[BX])););
  887         if (disk_seek(disk, cylinder, head, sector))
  888             break;
  889 
  890         num = *bregs[AL] << 9;
  891         res = write(disk->fd, buffer, num);
  892         if (res & 0x1ff)
  893         {
  894             CF = 1;
  895             *bregs[AH] = diskerror = 0x2;  /* Sector corrupt */
  896             break;
  897         }
  898         *bregs[AH] = diskerror = 0;
  899         *bregs[AL] = res >> 9;
  900         CF = 0;
  901         break;
  902     case 4: /* Test disk */
  903         D(printf("Testing disk 0x%02X\n",*bregs[DL]););
  904         disk = get_disk_tab(*bregs[DL]);
  905         if (!disk)
  906         {
  907             CF = 1;
  908             *bregs[AH] = diskerror = 0xaa;  /* Drive not ready... */
  909             break;
  910         }
  911         head = *bregs[DH];
  912         cylinder = *bregs[CH] + ((*bregs[CL] & 0xc0) << 8);
  913         sector = (*bregs[CL] & 0x3f) -1;
  914         buffer = &c_es[ChangeE(wregs[BX])];
  915         if (disk_seek(disk, cylinder, head, sector))
  916             break;
  917 
  918         *bregs[AH] = diskerror = 0;
  919         *bregs[AL] = res >> 9;
  920         CF = 0;
  921         break;
  922     case 5: /* Format disc track */
  923     case 6: /* Format and set bad sector flags */
  924     case 7: /* Format drive starting from given track */
  925         CF = 0;
  926         break;
  927     case 8: /* Get disk params */
  928         D(printf("Get disk params 0x%02X\n",*bregs[DL]););
  929         disk = get_disk_tab(*bregs[DL]);
  930         if (disk)
  931         {
  932             if (*bregs[DL] < 0x80)
  933                 switch(disk->sectors)
  934                 {
  935                 case 9:
  936                     *bregs[BL] = (disk->cylinders == 80) ? 3 : 1;
  937                     break;
  938                 case 15:
  939                     *bregs[BL] = 2;
  940                     break;
  941                 case 18:
  942                     *bregs[BL] = 4;
  943                     break;
  944                 }
  945             else
  946                 *bregs[BL] = 0; /* Is this right? */
  947 
  948             *bregs[CH] = (disk->cylinders - 1) & 0xff;
  949             *bregs[CL] = (disk->sectors - 1) | (((disk->cylinders - 1)
  950                                                  & 0x300) >> 2);
  951             *bregs[DH] = disk->heads - 1;
  952             *bregs[DL] = (*bregs[DL] < 0x80) ? numfdisks : numhdisks;
  953             *bregs[AL] = 0;
  954             CF = 0;
  955         }
  956         else
  957         {
  958             CF = 1;
  959             *bregs[AH] = diskerror = 0x1;
  960             wregs[DX] = 0;
  961             wregs[CX] = 0;
  962         }
  963         break;
  964     case 0x15:  /* Get disk type */
  965         D(printf("Get disk type 0x%02X\n",*bregs[DL]););
  966         disk = get_disk_tab(*bregs[DL]);
  967         if (disk)
  968         {
  969             CF = 0;
  970             if (*bregs[DL] >= 0x80)
  971             {
  972                 num = disk->cylinders * disk->sectors * disk->heads;
  973                 *bregs[DL] = num & 0xff;
  974                 *bregs[DH] = (num & 0xff00) >> 8;
  975                 *bregs[CL] = (num & 0xff0000) >> 16;
  976                 *bregs[CH] = (num & 0xff000000) >> 24;
  977                 *bregs[AH] = 3;
  978             }
  979             else
  980                 *bregs[AH] = 1;
  981         }
  982         else
  983         {
  984             CF = 1;
  985             *bregs[AH] = 0;
  986         }
  987         break;
  988     default:
  989         printf("Unimplemented INT 13h function %02X\n",*bregs[AH]);
  990 #ifdef DEBUG
  991         loc();
  992         exit_emu();
  993 #endif
  994         break;
  995         }
  996 
  997     D(if (CF) printf("Operation failed\n"););
  998 }
  999 
 1000 #if !defined(DISABLE_MFS)
 1001 static int call_mfs(int (*routine)(void))
 1002 {
 1003     int ret;
 1004 
 1005     vm86s.regs.eax = ChangeE(wregs[AX]);
 1006     vm86s.regs.ebx = ChangeE(wregs[BX]);
 1007     vm86s.regs.ecx = ChangeE(wregs[CX]);
 1008     vm86s.regs.edx = ChangeE(wregs[DX]);
 1009     vm86s.regs.esi = ChangeE(wregs[SI]);
 1010     vm86s.regs.edi = ChangeE(wregs[DI]);
 1011     vm86s.regs.ebp = ChangeE(wregs[BP]);
 1012     vm86s.regs.esp = ChangeE(wregs[SP]);
 1013     vm86s.regs.cs  = sregs[CS];
 1014     vm86s.regs.ds  = sregs[DS];
 1015     vm86s.regs.es  = sregs[ES];
 1016     vm86s.regs.ss  = sregs[SS];
 1017     vm86s.regs.eip = ip;
 1018     vm86s.regs.eflags = CompressFlags();
 1019 
 1020 #if 0
 1021 printf("--------------------\n");
 1022 print_regs();
 1023 printf("eflags = %X\n", vm86s.regs.eflags);
 1024 printf("\n");
 1025 fflush(stdout);
 1026 #endif
 1027     
 1028     ret = routine();
 1029 
 1030 
 1031     wregs[AX] = ChangeE(vm86s.regs.eax);
 1032     wregs[BX] = ChangeE(vm86s.regs.ebx);
 1033     wregs[CX] = ChangeE(vm86s.regs.ecx);
 1034     wregs[DX] = ChangeE(vm86s.regs.edx);
 1035     wregs[SI] = ChangeE(vm86s.regs.esi);
 1036     wregs[DI] = ChangeE(vm86s.regs.edi);
 1037     wregs[BP] = ChangeE(vm86s.regs.ebp);
 1038     wregs[SP] = ChangeE(vm86s.regs.esp);
 1039     
 1040     sregs[CS] = (WORD)vm86s.regs.cs;
 1041     c_cs = SegToMemPtr(CS);
 1042     sregs[DS] = (WORD)vm86s.regs.ds;
 1043     c_ds = SegToMemPtr(DS);
 1044     sregs[SS] = (WORD)vm86s.regs.ss;
 1045     c_stack = c_ss = SegToMemPtr(SS);
 1046     sregs[ES] = (WORD)vm86s.regs.es;
 1047     c_es = SegToMemPtr(ES);
 1048 
 1049     ip = (WORD)vm86s.regs.eip;
 1050     ExpandFlags(vm86s.regs.eflags);
 1051 
 1052 #if 0
 1053 print_regs();
 1054 printf("eflags = %X\n", vm86s.regs.eflags);
 1055 fflush(stdout);
 1056 #endif
 1057 
 1058     return ret;
 1059 }
 1060 #endif
 1061 
 1062 static void int_doshelper(void)
 1063 {
 1064     CalcAll();
 1065     printf("doshelper AX=%X BX=%x\n", ChangeE(wregs[AX]), ChangeE(wregs[BX]));fflush(stdout);
 1066     fflush(stdout);
 1067     switch(*bregs[AL])
 1068     {
 1069     case 0x00: /* Check for Linux DOSEMU. We pretend to be V1.0 */
 1070         wregs[AX] = ChangeE(0xAA55);
 1071         wregs[BX] = ChangeE(0x0100);
 1072         break;
 1073 #if !defined(DISABLE_MFS)
 1074     case 0x20: /* MFS entry */
 1075         call_mfs(mfs_intentry);
 1076         break;
 1077 #endif
 1078     default:
 1079         CF = 1;
 1080     }
 1081 }
 1082 
 1083 
 1084 static void int_2f(void)
 1085 {
 1086 #if !defined(DISABLE_MFS)
 1087     unsigned tmp,tmp2;
 1088 
 1089     D(printf("In INT 0xe8 AH = 0x%02X  AL = 0x%02X\n",*bregs[AH],*bregs[AL]););
 1090 
 1091     CalcAll();
 1092     switch(*bregs[AH])
 1093     {
 1094     case 0x11:
 1095         tmp = ChangeE(wregs[SP]);
 1096         tmp2 = tmp + 6;
 1097         wregs[SP] = ChangeE(tmp2);
 1098         ZF = call_mfs(mfs_redirector) ? 0 : 1;
 1099         wregs[SP] = ChangeE(tmp);
 1100         break;
 1101     default:
 1102         break;
 1103     }
 1104 #endif
 1105 }
 1106 
 1107 
 1108 static void setup(void)
 1109 {
 1110     static BYTE int8code[] =
 1111     {
 1112         30,80,82,184,64,0,142,216,161,108,0,139,22,110,0,5,
 1113         1,0,131,210,0,131,250,24,114,14,61,176,0,114,9,49,
 1114         192,49,210,198,6,112,0,1,163,108,0,137,22,110,0,176,
 1115         32,230,32,251,205,28,90,88,31,207
 1116     };
 1117     static BYTE afterint[] = { 0xfb, 0xca, 0x02, 0x00 };
 1118     static BYTE before_int16[] = { 0x51, 0xb9, 0x01, 0x00, 0xfb };
 1119     static BYTE after_int16[] = { 0xe3, 0xf8, 0x59, 0xca, 0x02, 0x00 };
 1120     static BYTE int9bcode[] =
 1121     {
 1122         30,80,180,79,228,96,205,21,114,7,176,32,230,32,251,235,57
 1123     };
 1124     static BYTE int9acode[] =
 1125     {
 1126         176,32,230,32,251,8,228,116,42,254,204,117,14,184,64,0,142,
 1127         216,246,6,24,0,8,117,249,235,24,254,204,117,4,205,27,235,16,
 1128         254,204,117,4,205,5,235,8,254,204,117,4,180,133,205,21,88,31,207
 1129     };
 1130     static BYTE inte7code[] =
 1131     {
 1132         0x06,0x57,0x50,0xb8,0x0c,0x12,0xcd,0x2f,0x58,0x5f,0x07,0xcf
 1133     };
 1134 
 1135     unsigned equip = 0;
 1136     int i;
 1137 
 1138     memory[0xf0000+0xfffe] = SYSTEMID;
 1139 
 1140     EMS_Setup();
 1141     
 1142     if (numfdisks > 0)
 1143         equip |= (1 | ((numfdisks-1) << 6));
 1144     equip |= mono ? 0x30 : 0x20;
 1145 
 1146 
 1147     SetCurKeyBufStart(0x001e);
 1148     SetCurKeyBufEnd(0x001e);
 1149     SetKeyBufStart(0x001e);
 1150     SetKeyBufEnd(0x003e);
 1151 
 1152     PutMemW(data_segment, 0x10, equip);
 1153     PutMemW(data_segment, 0x13, 640);
 1154     PutMemB(data_segment, 0x3e, 0xff);
 1155     PutMemB(data_segment, 0x3f, 0);
 1156     PutMemB(data_segment, 0x40, 0);
 1157     PutMemB(data_segment, 0x41, 0);
 1158     PutMemW(data_segment, 0x72, 0x1234);
 1159     PutMemW(data_segment, 0x75, numhdisks);
 1160     PutMemW(data_segment, 0x96, 16);            /* 101/102 keyboard */
 1161     PutMemB(data_segment, 0x17, NUMLOCK);
 1162 
 1163     PutMemB(BIOS_base, 0x00, 0xcf);  /* IRET */
 1164 
 1165     PutMemB(BIOS_base, 0xfff0, 0xcd);  /* INT 19 */
 1166     PutMemB(BIOS_base, 0xfff1, 0x19);
 1167     PutMemB(BIOS_base, 0xfff2, 0xeb);  /* jmp $-2 */
 1168     PutMemB(BIOS_base, 0xfff3, 0xfe);
 1169 
 1170     for (i = 0; i < 256; i++)           /* Reset all int vectors */
 1171     {
 1172         if (i >= 0x60 && i <= 0x6f)
 1173             continue;
 1174         else
 1175         {
 1176             PutMemW(memory, i*4, 0);
 1177             PutMemW(memory, i*4+2, 0xf000);
 1178         }
 1179     }
 1180 
 1181 #define INSTALL_INT(intno, before, handler, after) \
 1182     set_int(intno, before, before?(sizeof before):0, handler, after, \
 1183         after?(sizeof after):0)
 1184 
 1185     /*         Int_no Code_before       Handler         Code_after */
 1186     
 1187     INSTALL_INT(0x08, int8code,     NULL,       NULL);
 1188     INSTALL_INT(0x09, int9bcode,    int9,       int9acode);
 1189     INSTALL_INT(0x11, NULL,     int_equipment,  afterint);
 1190     INSTALL_INT(0x12, NULL,     int_memory, afterint);
 1191     INSTALL_INT(0x13, NULL,     int_disk,   afterint);
 1192     INSTALL_INT(0x14, NULL,     int_serial, afterint);
 1193     INSTALL_INT(0x15, NULL,     int_extended,   afterint);
 1194     INSTALL_INT(0x16, before_int16, int_keyboard,   after_int16);
 1195     INSTALL_INT(0x17, NULL,     int_printer,    afterint);
 1196     INSTALL_INT(0x18, NULL,     int_basic,  afterint);
 1197     INSTALL_INT(0x19, NULL,     int_reboot, afterint);
 1198     INSTALL_INT(0x1a, NULL,     int_time,   afterint);
 1199     
 1200     INSTALL_INT(0x4b, NULL,     int_ems,    afterint);
 1201 
 1202     INSTALL_INT(0xe6, NULL,     int_doshelper,  afterint);
 1203     INSTALL_INT(0xe7, inte7code,    NULL,       NULL);
 1204     INSTALL_INT(0xe8, NULL,     int_2f,     afterint);
 1205    
 1206 #undef INSTALL_INT
 1207 
 1208     put_ticks(get_ticks_since_midnight());
 1209 
 1210     memcpy(BIOS_base+0xfff5,BIOSDATE,sizeof BIOSDATE);
 1211     memcpy(BIOS_base+0xe000,BIOSCOPYRIGHT, sizeof BIOSCOPYRIGHT);
 1212 }
 1213 
 1214 
 1215 void init_bios(void)
 1216 {
 1217     int i;
 1218 #ifdef BOOT
 1219     DiskTab *boot;
 1220 #endif
 1221 
 1222     if (numhdisks)
 1223         for (i = 0; i < numhdisks; i++)
 1224             open_drive(hdisk, i);
 1225 
 1226     for (i = 0; i < numfdisks; i++)
 1227         open_drive(fdisk, i);
 1228 
 1229     BIOS_base = &memory[0xf0000];
 1230     data_segment = &memory[0x400];
 1231 
 1232     setup();
 1233 
 1234 #ifdef BOOT
 1235     boot = get_disk_tab(bootdisk);
 1236 
 1237     if (boot == NULL || read(boot->fd, &memory[0x7c00], 512) != 512)
 1238     {
 1239         fprintf(stderr, "Cannot boot from %s :",boot->name);
 1240         if (boot)
 1241             perror(NULL);
 1242         exit(1);
 1243     }
 1244     
 1245     sregs[CS] = sregs[ES] = sregs[DS] = sregs[SS] = 0;
 1246     *bregs[DL] = bootdisk;
 1247     ip = 0x7c00;
 1248     IF = 1;
 1249 #endif
 1250 
 1251 #ifdef DEBUGGER
 1252     signal(SIGINT, (void *)debug_breakin);
 1253 #else
 1254     signal(SIGINT, (void *)exit_emu);
 1255 #endif
 1256     signal(SIGTERM, (void *)exit_emu);
 1257 
 1258 }
 1259 
 1260 void open_drive(DiskTab disktab[], int drive)
 1261 {
 1262     disktab[drive].mounted = 1;
 1263     if ((disktab[drive].fd = open(disktab[drive].name, O_RDWR)) < 0)
 1264     {
 1265     if ((disktab[drive].fd = open(disktab[drive].name, O_RDONLY)) < 0)
 1266     {
 1267         printf("Unable to open %s at all\n", disktab[drive].name);
 1268         disktab[drive].mounted = 0;
 1269         disktab[drive].fd = open("/dev/zero", O_RDWR);
 1270     }
 1271     }
 1272 }
 1273 
 1274 char *set_drive(DiskTab disktab[], int drive, char *device, int sectors, int cylinders, int heads)
 1275 {
 1276     if ((disktab[drive].name = strdup(device)) == NULL)
 1277     {
 1278         fprintf(stderr, "Insufficient available memory\n");
 1279         exit(1);
 1280     }
 1281     disktab[drive].sectors = sectors;
 1282     disktab[drive].cylinders = cylinders;
 1283     disktab[drive].heads = heads;
 1284     
 1285     return NULL;
 1286 }
 1287 
 1288 char *set_floppy_drive(int drive, char *device, int sectors, int cylinders, int heads)
 1289 {
 1290     char s[8];
 1291     char *status;
 1292     
 1293     status = set_drive(fdisk, drive, device, sectors, cylinders, heads);
 1294     if (status)
 1295         return(status);
 1296     strncpy(s, fdisk[drive].name, 5);
 1297     s[5] = '\0';
 1298     if (strcmp(s, "/dev/")==0)
 1299         fdisk[drive].removable = 1;
 1300     else
 1301         fdisk[drive].removable = 0;
 1302         
 1303     return NULL;
 1304 }
 1305 
 1306 char *set_hard_drive(int drive, char *device, int sectors, int cylinders, int heads)
 1307 {
 1308     char *status;
 1309     
 1310     status = set_drive(hdisk, drive, device, sectors, cylinders, heads);
 1311     if (status)
 1312         return(status);
 1313     hdisk[drive].removable = 0;
 1314     
 1315     return NULL;
 1316 }
 1317 
 1318 char *set_num_fdrives(int num)
 1319 {
 1320     if ((num<0) || (num>2))
 1321         return "Can't have this many floppy drives";
 1322     numfdisks = num;
 1323     return NULL;
 1324 }
 1325 
 1326 char *set_num_hdrives(int num)
 1327 {
 1328     if ((num<0) || (num>2))
 1329         return "Can't have this many hard drives";
 1330     numhdisks = num;
 1331     return NULL;
 1332 }
 1333 
 1334 void bios_off(void)
 1335 {
 1336     int i;
 1337     
 1338     for (i = 0; i < numfdisks; i++)
 1339         close(fdisk[i].fd);
 1340 
 1341     if (numhdisks)
 1342         for (i =0; i < numhdisks; i++)
 1343             close(hdisk[i].fd);
 1344 }
 1345