More details on the A20 problem with the DeskPro 386 ROM
This commit is contained in:
parent
1508cd1bf3
commit
10202ccef5
7 changed files with 1340 additions and 1228 deletions
|
|
@ -1,6 +1,6 @@
|
|||
Compaq DeskPro 386
|
||||
---
|
||||
I finally dumped the [Compaq DeskPro 386-16 ROMs](/devices/pc/bios/compaq/deskpro386/) from the motherboard I bought
|
||||
I finally dumped the [Compaq DeskPro 386/16 ROMs](/devices/pc/bios/compaq/deskpro386/) from the motherboard I bought
|
||||
on ebay last year, so I'm ready to begin adding 80386 support to PCjs.
|
||||
|
||||
I'd also like to locate a copy of the "Compaq DeskPro 386 Technical Reference Guide, Volumes 1 and 2". It's not hard
|
||||
|
|
|
|||
105
blog/2015/04/16/README.md
Normal file
105
blog/2015/04/16/README.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
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.
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
;;
|
||||
;; Relocate the ROM and initialize conventional RAM
|
||||
;;
|
||||
call xc825 ; 0000BCAF E8730B
|
||||
|
||||
;;
|
||||
;; This 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.
|
||||
|
||||
;;
|
||||
;; 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.
|
||||
|
||||
Here's the problem: the code at F000:F480 almost immediately attempts to enter protected-mode, which
|
||||
fails because A20 is disabled.
|
||||
|
||||
;;
|
||||
;; When we arrive here, the A20 line has been disabled, so in theory, the GDT is
|
||||
;; accessible only at the "low" ROM address (%0F0730), not the "high" address (%FF0730).
|
||||
;; And even if we DID access it from the "low" address, it contains base addresses (eg,
|
||||
;; for selector 0x28) located at %FFxxxx, so we're still screwed if A20 is disabled.
|
||||
;;
|
||||
;; TODO: Determine how this code worked in "real life"
|
||||
;;
|
||||
;; FYI, it seems this code doesn't do anything if bits 6 and 7 of the RAM Settings
|
||||
;; register are set to anything other than 0x40 (ie, it returns to real-mode almost
|
||||
;; immediately after entering protected-mode).
|
||||
;;
|
||||
lgdt [cs:0x077e] ; 0000F498 load [gdtr_hi] into GDTR
|
||||
mov eax,cr0 ; 0000F49E 0F2000
|
||||
or ax,0x1 ; 0000F4A1 0D0100
|
||||
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 code at F000: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:
|
||||
|
||||
test word [cs:si],0x0f00 ; 0000F48A 2EF704000F
|
||||
jz xf494 ; 0000F48F 7403
|
||||
|
||||
But the high byte of the word at [cs:si] (part of Compaq's Built-In Memory table) is initialized
|
||||
earlier with a value from AL that was first masked with 0xF0:
|
||||
|
||||
;;
|
||||
;; Isolate the base memory settings in bits 5-4 (00=640Kb, 10=512Kb, 11=256Kb)
|
||||
;;
|
||||
and al,0xf0 ; 000085D7 24F0 '$.'
|
||||
|
||||
;;
|
||||
;; Update [bim_table_offset]+1 (eg, %FF7FB7) with base memory settings
|
||||
;;
|
||||
mov [es:di+0x1],al ; 000085D9 26884501 '&.E.'
|
||||
|
||||
and I'm not aware of any intervening code that could have altered that byte, so it's not clear how the
|
||||
high byte of the word at [cs:si] would ever contain any set bits that coincide with 0x0F.
|
||||
|
||||
I've worked around this problem for now by changing how PCjs manages the A20 line. All A20 changes
|
||||
now go through the CPU component, instead of directly to the Bus component, giving the CPU first crack
|
||||
at any changes to A20. If the CPU is in real-mode, it simply passes the A20 request on to the Bus.
|
||||
However, if the CPU is in protected-mode, it maintains the requested "logical" A20 state, but ensures
|
||||
that the "physical" state of A20 is always enabled. In short, it is no longer possible for the CPU
|
||||
to be in protected-mode AND for the A20 line to be disabled; when one is enabled, the other is enabled
|
||||
as well.
|
||||
|
||||
That's obviously NOT how the actual hardware works, but it does have the advantage of avoiding strange
|
||||
bugs involving the A20 line in protected-mode -- including this "bug" in the Compaq DeskPro 386 ROM BIOS.
|
||||
|
||||
Here's my Compaq DeskPro 386/16 PCjs test configuration. Set a breakpoint at F000:F498 ("bp f000:f498")
|
||||
in the Debugger panel and see what *you* think. Use the "rp" command to see all registers, including
|
||||
the current base and limit values loaded into the selectors.
|
||||
|
||||
[Embedded DeskPro 386](/devices/pc/machine/compaq/deskpro386/ega/2048kb/machine.xml "PCjs:deskpro386-ega-2048k::uncompiled:debugger")
|
||||
|
||||
*[@jeffpar](http://twitter.com/jeffpar)*
|
||||
*April 16, 2015*
|
||||
Loading…
Reference in a new issue