Changeset 60610 in vbox for trunk/src/VBox/Devices/PC
- Timestamp:
- Apr 20, 2016 5:42:15 PM (9 years ago)
- Location:
- trunk/src/VBox/Devices/PC/BIOS
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/BIOS/notes.txt
r59354 r60610 22 22 23 23 - 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. 25 26 26 27 - Very few guests use the 32-bit PCI BIOS interface. One is OS/2 (but falls … … 80 81 executed on 386+ processors. 81 82 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 82 88 - Windows NT 3.5 and 3.51 with MPS HAL requires that INT 15h/E820h return the 83 89 I/O APIC range as reserved, or not return any ranges at all just below 4GB. … … 86 92 87 93 94 95 286 BIOS 96 -------- 97 98 For testing purposes, it's quite useful to have a BIOS that can run in a 99 classic PC/AT environment with a 286 CPU. This forces various changes, not 100 always 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 88 117 Notes on BIOS implementation 89 118 ---------------------------- -
trunk/src/VBox/Devices/PC/BIOS/orgs.asm
r60579 r60610 141 141 extrn _ahci_init:near 142 142 endif 143 if VBOX_BIOS_CPU ge 80286 144 extrn _int15_blkmove:near 145 endif 143 146 144 147 … … 1666 1669 BIOSORG_CHECK 0F859h ; fixed wrt preceding code 1667 1670 int15_handler: 1671 1672 if 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 1688 not_blkmove: 1689 1690 endif 1691 1668 1692 pushf 1669 1693 push ds -
trunk/src/VBox/Devices/PC/BIOS/system.c
r59495 r60610 65 65 #pragma aux read_ss = "mov ax, ss" modify exact [ax] nomemory; 66 66 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 73 void pm_stack_save(uint16_t cx, uint16_t es, uint16_t si, uint16_t frame); 68 74 #pragma aux pm_stack_save = \ 69 75 ".386" \ … … 74 80 "mov ds:[467h], sp" \ 75 81 "mov ds:[469h], ss" \ 76 parm [cx] [es] [si] modify nomemory;82 parm [cx] [es] [si] [ax] modify nomemory; 77 83 78 84 /* Uses position independent code... because it was too hard to figure … … 103 109 modify nomemory; 104 110 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 113 111 /* Restore segment limits to real mode compatible values and 114 112 * return to real mode. … … 146 144 "pop eax" \ 147 145 "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 */ 154 void 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 */ 166 void 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 */ 194 void 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. */ 208 void pm_stack_restore(void); 209 #pragma aux pm_stack_restore = \ 210 "rm_return:" \ 211 modify nomemory; 212 213 #endif 214 215 void pm_copy(void); 216 #pragma aux pm_copy = \ 217 "xor si, si" \ 218 "xor di, di" \ 219 "cld" \ 220 "rep movsw" \ 148 221 modify nomemory; 149 222 … … 283 356 void BIOSCALL int15_function(sys_regs_t r) 284 357 { 285 bx_bool prev_a20_enable;286 uint16_t base15_00;287 uint8_t base23_16;288 uint16_t ss;289 358 uint16_t bRegister; 290 359 uint8_t irqDisable; … … 392 461 } 393 462 394 case 0x87:395 #if BX_CPU < 3396 SET_AH(UNSUPPORTED_FUNCTION);397 SET_CF();398 #endif399 // +++ should probably have descriptor checks400 // +++ should have exception handlers401 402 // turn off interrupts403 int_disable(); //@todo: aren't they disabled already?404 405 prev_a20_enable = set_enable_a20(1); // enable A20 line406 407 // 128K max of transfer on 386+ ???408 // source == destination ???409 410 // ES:SI points to descriptor table411 // offset use initially comments412 // ==============================================413 // 00..07 Unused zeros Null descriptor414 // 08..0f GDT zeros filled in by BIOS415 // 10..17 source ssssssss source of data416 // 18..1f dest dddddddd destination of data417 // 20..27 CS zeros filled in by BIOS418 // 28..2f SS zeros filled in by BIOS419 420 //es:si421 //eeee0422 //0ssss423 //-----424 425 // check for access rights of source & dest here426 427 // Initialize GDT descriptor428 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/descriptor433 write_word(ES, SI+0x08+2, base15_00);// base 15:00434 write_byte(ES, SI+0x08+4, base23_16);// base 23:16435 write_byte(ES, SI+0x08+5, 0x93); // access436 write_word(ES, SI+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16437 438 // Initialize CS descriptor439 write_word(ES, SI+0x20+0, 0xffff);// limit 15:00 = normal 64K limit440 write_word(ES, SI+0x20+2, 0x0000);// base 15:00441 write_byte(ES, SI+0x20+4, 0x000f);// base 23:16442 write_byte(ES, SI+0x20+5, 0x9b); // access443 write_word(ES, SI+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16444 445 // Initialize SS descriptor446 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 limit450 write_word(ES, SI+0x28+2, base15_00);// base 15:00451 write_byte(ES, SI+0x28+4, base23_16);// base 23:16452 write_byte(ES, SI+0x28+5, 0x93); // access453 write_word(ES, SI+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16454 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 on464 int_enable();465 466 SET_AH(0);467 CLEAR_CF();468 break;469 470 463 case 0x88: 471 464 // Get the amount of extended memory (above 1M) … … 830 823 } 831 824 } 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. */ 832 void 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.