Load kernel before or after I enable the Protect Mode?

All off topic discussions go here. Everything from the funny thing your cat did to your favorite tv shows. Non-programming computer questions are ok too.
Post Reply
User avatar
smwikipedia
Member
Member
Posts: 49
Joined: Tue Apr 20, 2010 1:11 am

Load kernel before or after I enable the Protect Mode?

Post by smwikipedia »

I am writing a loader for my little test OS. My booting sequence is as below:

Bootsector -> Loader -> Kernel...

Bootsector: Only load the loader.
Loader: (a) Load the kernal from a floppy in real mode
(b) Switch to protect mode

Kernel: to-be-continued...


I am wondering:

In what order should I arrange the 2 parts of the Loader's job?

Currently, the loader loads the kernel into memory with the help of real mode BIOS interrupt routine. But real mode limits the size of memory I can use. Though the kernel for now is small enough to fit in, what if it grow quite big in the future?

So I am considering doing step (b) first. But thus I won't be able to use the BIOS interrupt routine, then I have to implement my own floppy driver.

How does Linux handle this problem?

Could someone give me some suggestion to solve this problem elegantly?
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Load kernel before or after I enable the Protect Mode?

Post by gerryg400 »

You could use big real (unreal) mode

http://en.wikipedia.org/wiki/Unreal_mode

- gerryg400
If a trainstation is where trains stop, what is a workstation ?
User avatar
smwikipedia
Member
Member
Posts: 49
Joined: Tue Apr 20, 2010 1:11 am

Re: Load kernel before or after I enable the Protect Mode?

Post by smwikipedia »

Thanks gerryg400. How about turning on protect mode first?
earlz
Member
Member
Posts: 1546
Joined: Thu Jul 07, 2005 11:00 pm
Contact:

Re: Load kernel before or after I enable the Protect Mode?

Post by earlz »

smwikipedia wrote:Thanks gerryg400. How about turning on protect mode first?
This would make things much more complicated because you would not have access to the BIOS. Yes, I know that say floppy disk access is "Easy" but the BIOS makes it so you can boot off of anything the BIOS considers bootable(and can be read with int13h) including CD, harddrive, and flash drive.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Load kernel before or after I enable the Protect Mode?

Post by gerryg400 »

It's been a long time since I did this. From memory you...

1. enable a20
2. create segment descriptors with a 4G limit
3. switch to protected mode
4. load DS and ES
5. switch back to real mode.

You can now copy data up above the 1MB barrier and at the same time bios interrupts will still work

6. set esi and edi to contain src and dest addresses
7. db 66h
db 67h
movsb

- gerryg400
If a trainstation is where trains stop, what is a workstation ?
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Load kernel before or after I enable the Protect Mode?

Post by gerryg400 »

earlz,

In fact big real mode is 16bit so the BIOS is accessible

- gerryg400
If a trainstation is where trains stop, what is a workstation ?
StephanvanSchaik
Member
Member
Posts: 127
Joined: Sat Sep 29, 2007 5:43 pm
Location: Amsterdam, The Netherlands

Re: Load kernel before or after I enable the Protect Mode?

Post by StephanvanSchaik »

smwikipedia wrote:Currently, the loader loads the kernel into memory with the help of real mode BIOS interrupt routine. But real mode limits the size of memory I can use. Though the kernel for now is small enough to fit in, what if it grow quite big in the future?
You generally have two options that are easy. The first option is to, as mentioned before, get into unreal mode, voodoo mode, flat mode, whatever, in which case your data segments will be 32-bit and thus be able to access 4GB, whilst your code segment remains 16-bit, in which case you can simply use the BIOS. The other option is to load a block in real mode, switch to protected mode, move the block and switch back to real mode to load the next block. Doing it purely in protected mode or even long mode is possible, but you'll have to write a x86-16 emulator for the BIOS or use VM86, which is absent in long mode. Another option is not to use the BIOS, but your own drivers to access the drive, this, however, is an advanced method which you will not be able to support everywhere from the start, besides you'll still need the BIOS to load your drivers. So at the end it's probably the best to go with unreal mode, voodoo mode, flat mode, or whatever.
smwikipedia wrote:How does Linux handle this problem?
Linux doesn't really deal with it since Linux is usually loaded by GRUB Legacy or GRUB 2, which aren't part of Linux actually. You could always look at their old boot loader, LILO, though.
gerryg400 wrote:It's been a long time since I did this. From memory you...

1. enable a20
2. create segment descriptors with a 4G limit
3. switch to protected mode
4. load DS and ES
5. switch back to real mode.

You can now copy data up above the 1MB barrier and at the same time bios interrupts will still work

6. set esi and edi to contain src and dest addresses
7. db 66h
db 67h
movsb

- gerryg400

Code: Select all

; enable the A20 here.
; ...
    push ds
    push es
    push fs
    push gs
    lgdt [GDT32.Pointer]
    mov eax, cr0
    or eax, 00000000000000000000000000000001b
    mov cr0, eax
    mov ax, GDT32.Data
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, cr0
    and eax, 11111111111111111111111111111110b
    mov cr0, eax
    pop gs
    pop fs
    pop es
    pop ds
    sti
; ...
GDT32:
    .Null:                              equ $ - GDT32
                                        dq 0
    .Code:                              equ $ - GDT32
                                        dw 0xFFFF
                                        dw 0
                                        db 0
                                        db 10011010b
                                        db 11001111b
                                        db 0
    .Data:                              equ $ - GDT32
                                        dw 0xFFFF
                                        dw 0
                                        db 0
                                        db 10010010b
                                        db 11001111b
                                        db 0
    .Pointer:                           dw $ - GDT32 - 1
                                        dd GDT32
To copy data you use something like:

Code: Select all

    mov esi, 0x00001000
    mov edi, 0x00100000
    mov ecx, 1024
    a32 rep movsd

Regards,
Stephan J.R. van Schaik.
Post Reply