VirtualBox

Changeset 60610 in vbox for trunk/src/VBox/Devices/PC


Ignore:
Timestamp:
Apr 20, 2016 5:42:15 PM (9 years ago)
Author:
vboxsync
Message:

BIOS: Added 286 compatible INT 15h/87h implementation.

Location:
trunk/src/VBox/Devices/PC/BIOS
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/BIOS/notes.txt

    r59354 r60610  
    2222
    2323- DOS 4.01 (both IBM and Microsoft) calls INT 13h to read from disk with less
    24   than 100 bytes of stack space early in the boot sequence.
     24  than 100 bytes of stack space early in the boot sequence. This tends to be
     25  a problem especially for the SATA and SCSI code paths.
    2526
    2627- Very few guests use the 32-bit PCI BIOS interface. One is OS/2 (but falls
     
    8081  executed on 386+ processors.
    8182
     83- IBM and Microsoft OS/2 1.0 use CMOS shutdown status 9 to get back from
     84  protected mode without having called INT 15h/87h at all. That makes the
     85  status 9 handling a public interface (just like codes 5 and 0Ah) which
     86  has to be compatible with other BIOS implementations.
     87
    8288- Windows NT 3.5 and 3.51 with MPS HAL requires that INT 15h/E820h return the
    8389  I/O APIC range as reserved, or not return any ranges at all just below 4GB.
     
    8692
    8793
     94
     95 286 BIOS
     96 --------
     97
     98 For testing purposes, it's quite useful to have a BIOS that can run in a
     99classic PC/AT environment with a 286 CPU. This forces various changes, not
     100always obvious:
     101
     102 - C code can be easily compiled to produce 286-compatible object code
     103
     104 - 32-bit BIOS services such as APM or PCI BIOS are irrelevant
     105
     106 - PCI cannot be supported because it requires 32-bit port I/O
     107
     108 - AHCI cannot be supported because it requires 32-bit port I/O and PCI
     109
     110 - Switching to protected mode must be done using LMSW instead of CR0
     111
     112 - Switching back to real mode must reset the CPU (currently triple fault)
     113   and regain control by setting up the CMOS shutdown status byte
     114
     115
     116 
    88117 Notes on BIOS implementation
    89118 ----------------------------
  • trunk/src/VBox/Devices/PC/BIOS/orgs.asm

    r60579 r60610  
    141141extrn           _ahci_init:near
    142142endif
     143if VBOX_BIOS_CPU ge 80286
     144extrn           _int15_blkmove:near
     145endif
    143146
    144147
     
    16661669                BIOSORG_CHECK   0F859h  ; fixed wrt preceding code
    16671670int15_handler:
     1671
     1672if VBOX_BIOS_CPU ge 80286
     1673                cmp     ah, 87h
     1674                jne     not_blkmove
     1675               
     1676                ;; INT 15h/87h has semi-public interface because software
     1677                ;; may use CMOS shutdown status code 9 for its own purposes.
     1678                ;; The stack layout has to match.
     1679                pusha
     1680                push    es
     1681                push    ds
     1682                C_SETUP
     1683                call    _int15_blkmove
     1684                pop     ds
     1685                pop     es
     1686                popa
     1687                iret
     1688not_blkmove:
     1689
     1690endif
     1691
    16681692                pushf
    16691693                push    ds
  • trunk/src/VBox/Devices/PC/BIOS/system.c

    r59495 r60610  
    6565#pragma aux read_ss = "mov ax, ss" modify exact [ax] nomemory;
    6666
    67 void pm_stack_save(uint16_t cx, uint16_t es, uint16_t si);
     67#if VBOX_BIOS_CPU >= 80386
     68
     69/* The 386+ code uses CR0 to switch to/from protected mode.
     70 * Quite straightforward.
     71 */
     72
     73void pm_stack_save(uint16_t cx, uint16_t es, uint16_t si, uint16_t frame);
    6874#pragma aux pm_stack_save =     \
    6975    ".386"                      \
     
    7480    "mov    ds:[467h], sp"      \
    7581    "mov    ds:[469h], ss"      \
    76     parm [cx] [es] [si] modify nomemory;
     82    parm [cx] [es] [si] [ax] modify nomemory;
    7783
    7884/* Uses position independent code... because it was too hard to figure
     
    103109    modify nomemory;
    104110
    105 void pm_copy(void);
    106 #pragma aux pm_copy =               \
    107     "xor    si, si"                 \
    108     "xor    di, di"                 \
    109     "cld"                           \
    110     "rep    movsw"                  \
    111     modify nomemory;
    112 
    113111/* Restore segment limits to real mode compatible values and
    114112 * return to real mode.
     
    146144    "pop    eax"                \
    147145    "pop    ds"                 \
     146    modify nomemory;
     147
     148#elif VBOX_BIOS_CPU >= 80286
     149
     150/* The 286 code uses LMSW to switch to protected mode but it has to reset
     151 * the CPU to get back to real mode. Ugly! See return_blkmove in orgs.asm
     152 * for the other matching half.
     153 */
     154void pm_stack_save(uint16_t cx, uint16_t es, uint16_t si, uint16_t frame);
     155#pragma aux pm_stack_save =     \
     156    "xor    ax, ax"             \
     157    "mov    ds, ax"             \
     158    "mov    ds:[467h], bx"      \
     159    "mov    ds:[469h], ss"      \
     160    parm [cx] [es] [si] [bx] modify nomemory;
     161
     162/* Uses position independent code... because it was too hard to figure
     163 * out how to code the far call in inline assembler.
     164 * NB: Trashes MSW bits but the CPU will be reset anyway.
     165 */
     166void pm_enter(void);
     167#pragma aux pm_enter =              \
     168    ".286p"                         \
     169    "call   pentry"                 \
     170    "pentry:"                       \
     171    "pop    di"                     \
     172    "add    di, 18h"                \
     173    "push   20h"                    \
     174    "push   di"                     \
     175    "lgdt   fword ptr es:[si+8]"    \
     176    "lidt   fword ptr cs:pmode_IDT" \
     177    "or     al, 1"                  \
     178    "lmsw   ax"                     \
     179    "retf"                          \
     180    "pm_pm:"                        \
     181    "mov    ax, 28h"                \
     182    "mov    ss, ax"                 \
     183    "mov    ax, 10h"                \
     184    "mov    ds, ax"                 \
     185    "mov    ax, 18h"                \
     186    "mov    es, ax"                 \
     187    modify nomemory;
     188
     189/* Set up shutdown status and reset the CPU. The POST code
     190 * will regain control. Port 80h is written with status.
     191 * Code 9 is written to CMOS shutdown status byte (0Fh).
     192 * CPU is triple faulted.                                                    .
     193 */
     194void pm_exit(void);
     195#pragma aux pm_exit =               \
     196    "xor    ax, ax"                 \
     197    "out    80h, al"                \
     198    "mov    al, 0Fh"                \
     199    "out    70h, al"                \
     200    "mov    al, 09h"                \
     201    "out    71h, al"                \
     202    ".286p"                         \
     203    "lidt   fword ptr cs:pmode_IDT" \
     204    "int    3"                      \
     205    modify nomemory;
     206
     207/* Dummy. Actually done in return_blkmove. */
     208void pm_stack_restore(void);
     209#pragma aux pm_stack_restore =  \
     210    "rm_return:"                \
     211    modify nomemory;
     212
     213#endif
     214
     215void pm_copy(void);
     216#pragma aux pm_copy =               \
     217    "xor    si, si"                 \
     218    "xor    di, di"                 \
     219    "cld"                           \
     220    "rep    movsw"                  \
    148221    modify nomemory;
    149222
     
    283356void BIOSCALL int15_function(sys_regs_t r)
    284357{
    285     bx_bool     prev_a20_enable;
    286     uint16_t    base15_00;
    287     uint8_t     base23_16;
    288     uint16_t    ss;
    289358    uint16_t    bRegister;
    290359    uint8_t     irqDisable;
     
    392461        }
    393462
    394     case 0x87:
    395 #if BX_CPU < 3
    396         SET_AH(UNSUPPORTED_FUNCTION);
    397         SET_CF();
    398 #endif
    399         // +++ should probably have descriptor checks
    400         // +++ should have exception handlers
    401 
    402         // turn off interrupts
    403         int_disable();    //@todo: aren't they disabled already?
    404 
    405         prev_a20_enable = set_enable_a20(1); // enable A20 line
    406 
    407         // 128K max of transfer on 386+ ???
    408         // source == destination ???
    409 
    410         // ES:SI points to descriptor table
    411         // offset   use     initially  comments
    412         // ==============================================
    413         // 00..07   Unused  zeros      Null descriptor
    414         // 08..0f   GDT     zeros      filled in by BIOS
    415         // 10..17   source  ssssssss   source of data
    416         // 18..1f   dest    dddddddd   destination of data
    417         // 20..27   CS      zeros      filled in by BIOS
    418         // 28..2f   SS      zeros      filled in by BIOS
    419 
    420         //es:si
    421         //eeee0
    422         //0ssss
    423         //-----
    424 
    425         // check for access rights of source & dest here
    426 
    427         // Initialize GDT descriptor
    428         base15_00 = (ES << 4) + SI;
    429         base23_16 = ES >> 12;
    430         if (base15_00 < (ES<<4))
    431             base23_16++;
    432         write_word(ES, SI+0x08+0, 47);       // limit 15:00 = 6 * 8bytes/descriptor
    433         write_word(ES, SI+0x08+2, base15_00);// base 15:00
    434         write_byte(ES, SI+0x08+4, base23_16);// base 23:16
    435         write_byte(ES, SI+0x08+5, 0x93);     // access
    436         write_word(ES, SI+0x08+6, 0x0000);   // base 31:24/reserved/limit 19:16
    437 
    438         // Initialize CS descriptor
    439         write_word(ES, SI+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
    440         write_word(ES, SI+0x20+2, 0x0000);// base 15:00
    441         write_byte(ES, SI+0x20+4, 0x000f);// base 23:16
    442         write_byte(ES, SI+0x20+5, 0x9b);  // access
    443         write_word(ES, SI+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
    444 
    445         // Initialize SS descriptor
    446         ss = read_ss();
    447         base15_00 = ss << 4;
    448         base23_16 = ss >> 12;
    449         write_word(ES, SI+0x28+0, 0xffff);   // limit 15:00 = normal 64K limit
    450         write_word(ES, SI+0x28+2, base15_00);// base 15:00
    451         write_byte(ES, SI+0x28+4, base23_16);// base 23:16
    452         write_byte(ES, SI+0x28+5, 0x93);     // access
    453         write_word(ES, SI+0x28+6, 0x0000);   // base 31:24/reserved/limit 19:16
    454 
    455         pm_stack_save(CX, ES, SI);
    456         pm_enter();
    457         pm_copy();
    458         pm_exit();
    459         pm_stack_restore();
    460 
    461         set_enable_a20(prev_a20_enable);
    462 
    463         // turn interrupts back on
    464         int_enable();
    465 
    466         SET_AH(0);
    467         CLEAR_CF();
    468         break;
    469 
    470463    case 0x88:
    471464        // Get the amount of extended memory (above 1M)
     
    830823    }
    831824}
     825
     826#if VBOX_BIOS_CPU >= 80286
     827
     828#undef  FLAGS
     829#define FLAGS   r.ra.flags.u.r16.flags
     830
     831/* Function 0x87 handled separately due to specific stack layout requirements. */
     832void BIOSCALL int15_blkmove(disk_regs_t r)
     833{
     834    bx_bool     prev_a20_enable;
     835    uint16_t    base15_00;
     836    uint8_t     base23_16;
     837    uint16_t    ss;
     838
     839    // +++ should probably have descriptor checks
     840    // +++ should have exception handlers
     841
     842    // turn off interrupts
     843    int_disable();    //@todo: aren't they disabled already?
     844
     845    prev_a20_enable = set_enable_a20(1); // enable A20 line
     846
     847    // 128K max of transfer on 386+ ???
     848    // source == destination ???
     849
     850    // ES:SI points to descriptor table
     851    // offset   use     initially  comments
     852    // ==============================================
     853    // 00..07   Unused  zeros      Null descriptor
     854    // 08..0f   GDT     zeros      filled in by BIOS
     855    // 10..17   source  ssssssss   source of data
     856    // 18..1f   dest    dddddddd   destination of data
     857    // 20..27   CS      zeros      filled in by BIOS
     858    // 28..2f   SS      zeros      filled in by BIOS
     859
     860    //es:si
     861    //eeee0
     862    //0ssss
     863    //-----
     864
     865    // check for access rights of source & dest here
     866
     867    // Initialize GDT descriptor
     868    base15_00 = (ES << 4) + SI;
     869    base23_16 = ES >> 12;
     870    if (base15_00 < (ES<<4))
     871        base23_16++;
     872    write_word(ES, SI+0x08+0, 47);       // limit 15:00 = 6 * 8bytes/descriptor
     873    write_word(ES, SI+0x08+2, base15_00);// base 15:00
     874    write_byte(ES, SI+0x08+4, base23_16);// base 23:16
     875    write_byte(ES, SI+0x08+5, 0x93);     // access
     876    write_word(ES, SI+0x08+6, 0x0000);   // base 31:24/reserved/limit 19:16
     877
     878    // Initialize CS descriptor
     879    write_word(ES, SI+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
     880    write_word(ES, SI+0x20+2, 0x0000);// base 15:00
     881    write_byte(ES, SI+0x20+4, 0x000f);// base 23:16
     882    write_byte(ES, SI+0x20+5, 0x9b);  // access
     883    write_word(ES, SI+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
     884
     885    // Initialize SS descriptor
     886    ss = read_ss();
     887    base15_00 = ss << 4;
     888    base23_16 = ss >> 12;
     889    write_word(ES, SI+0x28+0, 0xffff);   // limit 15:00 = normal 64K limit
     890    write_word(ES, SI+0x28+2, base15_00);// base 15:00
     891    write_byte(ES, SI+0x28+4, base23_16);// base 23:16
     892    write_byte(ES, SI+0x28+5, 0x93);     // access
     893    write_word(ES, SI+0x28+6, 0x0000);   // base 31:24/reserved/limit 19:16
     894
     895    pm_stack_save(CX, ES, SI, (uint16_t)(void __near *)&r);
     896    pm_enter();
     897    pm_copy();
     898    pm_exit();
     899    pm_stack_restore();
     900
     901    set_enable_a20(prev_a20_enable);
     902
     903    // turn interrupts back on
     904    int_enable();
     905
     906    SET_AH(0);
     907    CLEAR_CF();
     908}
     909#endif
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette