Hi,
This code uses a trick to change the segment limit for DS to 4 GB (instead of 64 KB), so that DS can be used to access anything in the physical address space below 4 GB.
The general steps are:
- * Load a GDT for protected mode
* Enable protected mode
* Set DS to a selector with a 4 GB limit
* Disable protected mode (leaving DS with a 4 GB limit)
* Restore the "visible part" of DS and its base address to real mode values
Specifically, "mov bx, 0x08" loads a reference to the selector with a 4 GB limit into BX (i.e. the first GDT entry) and the next "mov ds, bx" puts this selector into DS.
To understand this you need to know that for each segment register there's a visible part (the value you'd get in AX if you did "mov ax,SegReg") and some hidden parts. The hidden parts include the base address and the segment limit.
In real mode, "mov SegReg, Reg16" (e.g. "mov ds, bx") will change the visible part and the hidden base address, but will leave the hidden limit part untouched. In protected mode all of these parts are set. That's what makes it work - use protected mode to set all parts, then use real mode to restore everything except the limit.
After running this code, you'd be able to do things like:
Code: Select all
mov bx,0
mov ds,bx ;Make sure base address of DS = 0
mov eax,[dword 0x12345678] ;Get the dword from the middle of no-where
mov [dword 0x000B8000],eax ;Put it into video memory
Or perhaps even better:
Code: Select all
mov edi,2*1024*1024 ;edi = 32 bit address to copy OS
mov bp,sectorsNeeded ;bp = number of sectors to copy
.nextSector:
call loadNextSector ;Load a sector into the buffer below 1 MB
mov cx, 512 / 4 ;cx = number of dwords per sector
mov esi,temporaryBuffer ;esi = 32 bit address of buffer below 1 MB
.nextDword:
a32 lodsd ;eax = next dword in sector
mov [edi],eax ;Copy it to where it needs to go
add edi,4 ;edi = 32 bit address for next dword
loop .nextDword ;Do all dwords in this sector
sub bp,1 ;Decrease number of sectors left to load
jne .nextSector ;Keep doing sectors if there's some left
Unfortunately DS may not be the best segment to use for this because of the way "rep movsd" works with segment override prefixes. Using ES instead would allow you to do:
Code: Select all
mov edi,2*1024*1024 ;edi = 32 bit address to copy OS
mov bp,sectorsNeeded ;bp = number of sectors to copy
.nextSector:
call loadNextSector ;Load a sector into the buffer below 1 MB
mov ecx, 512 / 4 ;ecx = number of dwords per sector
mov esi,temporaryBuffer ;esi = 32 bit address of buffer below 1 MB
a32 es rep movsd ;Copy the sector to where it needs to go
sub bp,1 ;Decrease number of sectors left to load
jne .nextSector ;Keep doing sectors if there's some left
[EDIT: Minor change - I forgot that the address size prefix makes "rep movsd" use ECX rather than CX]
But this depends on what else you're using the segment register for...
Cheers,
Brendan