diff --git a/blog/2015/04/16/README.md b/blog/2015/04/16/README.md index 681374343..65788e6a0 100644 --- a/blog/2015/04/16/README.md +++ b/blog/2015/04/16/README.md @@ -2,43 +2,95 @@ Compaq DeskPro 386 Update --- PCjs can now boot the [Compaq DeskPro 386/16 ROM BIOS](/devices/pc/bios/compaq/deskpro386/). -There's still a problem with the hard disk controller, which I haven't looked into yet, but -it can be bypassed. Booting from a floppy works. +There's still a problem with the hard disk controller, which I haven't looked into yet, +but booting from a floppy works. While working through issues with this ROM BIOS, I created some lightly-annotated [source code](/devices/pc/bios/compaq/deskpro386/1988-01-28.nasm) that can be re-assembled -with [NASM](http://www.nasm.us/). The process of creating the initial source code is +with [NASM](http://www.nasm.us/). The initial process of creating the source code is explained [here](/devices/pc/bios/compaq/deskpro386/#producing-rom-source-code). -During the debugging process, I also came across a real head-scratcher. Take a look at this code -at F000:BCAF: +At the top of the source code, I explain a few important details about ROM addresses that +are worth recapping here: + +> This 32Kb ROM image is ORG'ed at 0x8000, because most of its code is designed to run +at real-mode addresses F000:8000 through F000:FFFF. + +> And even though the 80386 resets with CS:IP set to F000:FFF0, the physical base address +of CS is set to %FFFF0000, which means the ROM must also be mapped at physical addresses +%FFFF8000 through %FFFFFFFF. + +> Additionally, DeskPro 386 systems mirror this 32Kb ROM at real-mode address F000:0000 +through F000:7FFF. Once again, that region is mirrored at physical addresses %FFFF0000 +through %FFFF7FFFF. + +> In other words, both 32Kb halves of the last 64Kb of both the first and last megabyte +of the 80386's 32Gb address space are physically mapped to this ROM image. + +> Finally, the DeskPro 386 has a "RAM Relocation" feature that allows 128Kb of RAM at +%00FE0000 through %00FFFFFF to be mapped to %000E0000 through %000FFFFF, effectively +replacing the ROM in the first megabyte with write-protected RAM; the top 64Kb of that +RAM must first be initialized with the 64Kb at %000F0000 prior to remapping. It's also +possible to copy external ROMs from %000C0000 through %000EFFFF into the bottom 64Kb of +that RAM, but this is only done for ROMs known to contain relocatable code (eg, a Compaq +Enhanced Video Graphics card). + +> Every DeskPro 386 system must have a MINIMUM of 1Mb of RAM, of which either 256Kb, +512Kb, or 640Kb can be physically mapped as conventional memory (at the bottom of the +first megabyte), with the remainder (either 768Kb, 512Kb, or 384Kb) physically mapped +to the top of the 16th megabyte (ending at address %00FFFFFF), the last 128Kb of which +is used by the "RAM Relocation" feature. The remaining memory immediately below that +128Kb (ie, below %00FE0000) can only be accessed by special system software, such as CEMM. + +> Compaq refers to that remaining memory as "Compaq Built-in Memory". + +So there you have it. Once the ROM has relocated itself to RAM at the top of the 16th +megabyte, there are no less than THREE physical address ranges where ROM code and data +structures can be accessed: + + 1. %000F0000 through %000FFFFF (aka real-mode adresses F000:0000 through F000:FFFF) + 2. %00FF0000 through %00FFFFFF (the relocated copy) + 3. %FFFF0000 through %FFFFFFFF (the physical alias of %000F0000 through %000FFFFF) + +As you would expect, most of the ROM's code and data references are to first megabyte, +since most of the code is designed to run in real-mode. But there are portions that +run in protected-mode, and those portions are much less consistent about which address +range to use -- no doubt, in part, because it makes no difference. The ROM does +not run with paging enabled, so any physical address is as easy to access as any other. + +Unless, of course, the A20 line is disabled. In that case, only the first range is +accessible; the other two are not. + +And unfortunately, I've come across a code path in the ROM that attempts to switch to +protected-mode while the A20 line is still disabled, with the GDTR pointing to memory +that requires A20. The result is an immediate crash. Here's the code: ;; - ;; Relocate the ROM and initialize conventional RAM + ;; Switch to protected-mode, relocate the ROM, switch back to real-mode, disable + ;; the A20 line, and then initialize all conventional RAM. ;; call xc825 ; 0000BCAF E8730B ;; - ;; This function loads the GDTR with [00FF0730,0047], but since the previous call + ;; The next function loads the GDTR with [00FF0730,0047], but since the previous call ;; disabled the A20 line, the first selector load crashes, because physical address ;; %FF0730 requires A20. ;; call xf480 ; 0000BCB2 E8CB37 -The first call (to F000:C825) is to a long, fairly linear function that includes a call to F000:A478, -a small function whose sole purpose is to issue an 8042 Keyboard Controller command that disables the A20 -line. +The code at C825 is a long, fairly linear function that includes a call to A478, a small +function whose sole purpose is to issue an 8042 Keyboard Controller command that disables +the A20 line. ;; ;; Disable A20 ;; call xa478 ; 0000C8B4 E8C1DB -After disabling A20, the function at F000:C825 then performs a series of `rep stosd` to zero all -conventional (below 1Mb) RAM, and then it returns to the code at F000:BCB2, which in turn calls F000:F480. +After disabling A20, the code at C825 then performs a series of `rep stosd` to zero all +conventional (below 1Mb) RAM, and then it returns to BCB2, which in turn calls F480. -Here's the problem: the code at F000:F480 almost immediately attempts to enter protected-mode, which -fails because A20 is disabled. +The code at F480 almost immediately attempts to enter protected-mode: ;; ;; When we arrive here, the A20 line has been disabled, so in theory, the GDT is @@ -58,10 +110,10 @@ fails because A20 is disabled. mov cr0,eax ; 0000F4A4 0F2200 jmp 0x28:xf4ac ; 0000F4A7 EAACF42800 -I don't see how the above code can work. The JMP instruction will invariably fault, because the -GDTR is pointing to memory that cannot be accessed when A20 is disabled. +The JMP instruction will invariably fault, because the GDT is located in memory that cannot be +accessed when A20 is disabled. -The code at F000:F498 is not called from any other place. It can only be reached by running the +The code at F498 is not called from any other place. It can only be reached by running the preceding code which, among other things, disables A20. And there's only one branch between that code and the code that enters protected-mode that could possibly make any difference: diff --git a/devices/pc/bios/compaq/deskpro386/1988-01-28.nasm b/devices/pc/bios/compaq/deskpro386/1988-01-28.nasm index f54db2e7b..5d0b36cd7 100644 --- a/devices/pc/bios/compaq/deskpro386/1988-01-28.nasm +++ b/devices/pc/bios/compaq/deskpro386/1988-01-28.nasm @@ -9,29 +9,34 @@ ; ; Overview ; -------- -; This 32Kb ROM image is ORG'ed at 0x8000, because it needs to run at real-mode -; addresses F000:8000 through F000:FFFF, as well as protected-mode physical addresses -; %FFFF8000 through %FFFFFFFF. Additionally, DeskPro 386 systems mirror this 32Kb ROM -; at real-mode addresses F000:0000 through F000:7FFF, as well as protected-mode physical -; addresses %FFFF0000 through %FFFF7FFF. +; This 32Kb ROM image is ORG'ed at 0x8000, because most of its code is designed to run +; at real-mode addresses F000:8000 through F000:FFFF. ; -; In other words, both 32Kb halves of the top 64Kb of both the first megabyte and the -; 16th megabyte are physically mapped to this ROM image. +; And even though the 80386 resets with CS:IP set to F000:FFF0, the physical base address +; of CS is set to %FFFF0000, which means the ROM must also be mapped at physical addresses +; %FFFF8000 through %FFFFFFFF. +; +; Additionally, DeskPro 386 systems mirror this 32Kb ROM at real-mode address F000:0000 +; through F000:7FFF. And that region is similarly mirrored at physical addresses %FFFF0000 +; through %FFFF7FFFF. +; +; In other words, both 32Kb halves of the last 64Kb of both the first and last megabyte +; of the 80386's 32Gb address space are physically mapped to this ROM image. ; ; Finally, the DeskPro 386 has a "RAM Relocation" feature that allows 128Kb of RAM at -; %FE0000 through %FFFFFF to be mapped to %0E0000 through %0FFFFF, effectively replacing -; the ROM in the first megabyte with write-protected RAM; the top 64Kb of that RAM must -; first be initialized with the 64Kb at %0F0000 prior to remapping. It's also possible -; to copy external ROMs from %0C0000 through %0EFFFF into the bottom 64Kb of that RAM, -; but this is only done for ROMs known to contain relocatable code (eg, a Compaq Enhanced -; Video Graphics card). +; %00FE0000 through %00FFFFFF to be mapped to %000E0000 through %000FFFFF, effectively +; replacing the ROM in the first megabyte with write-protected RAM; the top 64Kb of that +; RAM must first be initialized with the 64Kb at %000F0000 prior to remapping. It's also +; possible to copy external ROMs from %000C0000 through %000EFFFF into the bottom 64Kb of +; that RAM, but this is only done for ROMs known to contain relocatable code (eg, a Compaq +; Enhanced Video Graphics card). ; ; Every DeskPro 386 system must have a MINIMUM of 1Mb of RAM, of which either 256Kb, ; 512Kb, or 640Kb can be physically mapped as conventional memory (at the bottom of the ; first megabyte), with the remainder (either 768Kb, 512Kb, or 384Kb) physically mapped -; to the top of the 16th megabyte (ending at address %FFFFFF), the last 128Kb of which +; to the top of the 16th megabyte (ending at address %00FFFFFF), the last 128Kb of which ; is used by the "RAM Relocation" feature. The remaining memory immediately below that -; 128Kb (ie, below %FE0000) can only be accessed by special system software, such as CEMM. +; 128Kb (ie, below %00FE0000) can only be accessed by special system software, such as CEMM. ; ; Compaq refers to that remaining memory as "Compaq Built-in Memory". ; @@ -6626,12 +6631,13 @@ xbc71: call xa3e0 ; 0000BC71 E86CE7 '.l.' call xd6dd ; 0000BCAC E82E1A '...' ;; - ;; Relocate the ROM and initialize conventional RAM + ;; Switch to protected-mode, relocate the ROM, switch back to real-mode, disable + ;; the A20 line, and then initialize all conventional RAM. ;; call xc825 ; 0000BCAF E8730B ;; - ;; This function loads the GDTR with [00FF0730,0047], but since the previous call + ;; The next function loads the GDTR with [00FF0730,0047], but since the previous call ;; disabled the A20 line, the first selector load crashes, because physical address ;; %FF0730 requires A20. ;;