Load kernel at 2 mb mark

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
jason7007

Load kernel at 2 mb mark

Post by jason7007 »

Hello,

I planning to load my kernel at 2 mb mark, can I use the int 13h extension to do this after I setup the unreal mode and activate the A20 line? I am booting from hard disk.


Thank you very much in advance.
Jason
Cjmovie

Re:Load kernel at 2 mb mark

Post by Cjmovie »

You can use it, but BIOS can only read stuff into the lower 1mb section of memory. You must have BIOS read it to somewhere it will like (Such as 0x7E00:0x0000, right after the bootloader) and then copy it to where you want it. Then call BIOS again, move it to the next spot, etc. etc.

My bootloader does this, if you'd like to look you can see it at my CVS (fake) area: http://demi.cjmovie.net/Source/Bootloader/Stage2.asm

And, yes, it is a big source file, but I think I've commented it at least fairly well...Every line has a comment, and not just those crappy '...' or 'etc' lines!
You'd be interested in the 'read sector' function.
jason7007

Re:Load kernel at 2 mb mark

Post by jason7007 »

THANKS A LOT cjmovie!!
Cjmovie

Re:Load kernel at 2 mb mark

Post by Cjmovie »

Haha, your welcome. Anytime :)
jason7007

Re:Load kernel at 2 mb mark

Post by jason7007 »

Hi Cjmovie,

Here is a part of your code that I need clarification.

Code: Select all

 cli                          ;Disable interrupts
 push ds                   ;Save Real-Mode DS
 
 lgdt [GdtUnreal]         ;Load Unreal-Mode GDT
 
 mov eax, cr0             ;Get CR0 register
 or al, 1                     ;Set P-Mode bit
 mov cr0, eax             ;Put it back (in PMODE now!)
 
 mov bx, 0x08    ?????         ;Put in bx to put in ds....
 mov ds, bx               ;Data segment now 32-bit!
 
 and al, 0xFE             ;Set CR0 for real mode again...
 mov cr0, eax             ;Now put it back, we are in real mode now
 
 pop ds                   ;Restore real-mode DS
 sti         
In the above code which I put question mark , what is 0x08, why you put that to ds, then at the end you pop ds, you overwrite it?

Thanks,
Jason
<pype> use [ code ] ... [ /code ] tags to avoid code being translated in smileys</pype>
Cjmovie

Re:Load kernel at 2 mb mark

Post by Cjmovie »

Quite simply:

I put 0x08 in bx then into ds. 0x08 is the segment selector for my unreal mode GDT. In my unreal mode GDT, 0x08 corresponds to the only entry, a 4GB limit 32-bit segment for data. Putting it in DS makes further accesses to memory be 32-bit, as apposed to the 16-bit segment it used to have in it.

As for popping DS back....I'm not really sure. The best guess I have is that the segments you loaded while in protected mode overwrite those the CPU used in real mode, then when you POP it it takes the DS that it used to have, except that now it's been overwritten with the 32-bit segment. I'm no expert.

In fact, that part of code is almost an exact copy of how I learned it.
http://www.osdev.org/osfaq2/index.php/BabyStep7

Also, Let me look, I beleive I myself in fact posted about this a while back.....
http://www.mega-tokyo.com/forum/index.p ... 6#msg71806
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Load kernel at 2 mb mark

Post by Brendan »

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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Cjmovie

Re:Load kernel at 2 mb mark

Post by Cjmovie »

Ha, thanks for clearing up the limit part Brendan...I had already known anything else, I was just iffy on it, so again, thanks their also.

jason7007, I beleive brendan has explained it better than me, don't you think so? :P
jason7007

Re:Load kernel at 2 mb mark

Post by jason7007 »

Hi

5 star for Brendan
1 star for Cjmovie

thank you to both of you
jason7007

Re:Load kernel at 2 mb mark

Post by jason7007 »

Hi,

Sorry,
This part of your code is causing my computer to reset or boot.

I just put something like this after your code.

mov si, msg_BootSuccess
call PrintMessage
call wait_key

I don't see any message, cause it is booting the computer.

Thanks
Jason
Cjmovie

Re:Load kernel at 2 mb mark

Post by Cjmovie »

After who's code?
Post Reply