| Author |
| Thread |
 |
|
emc
Joined: 20 Aug 2011
Posts: 90
Location: France
|
switching to PMode
Hi,
I try to switch to protected mode, with the following code:
Code: |
|
org $0000
cld
;-------- Set up segments ---------;
start:
mov ax, $7c0
mov ds, ax
mov ax, $9000
mov es, ax
mov cx, 256
;----------- Print the welcome message -----------
mov bl, $8 ; gray color
mov si, hello
call putStr
;---------- Print the "stage1" and "stage2" ----------;
mov bl, $f ; wihte color
mov si, stg1
call putStr
mov si, stg2
call putStr
;---------- switch to PMode ---------;
toPM:
cli
lgdt [gdt_info]
mov eax, cr0
or al, 1
mov cr0, eax
jmp far $8:PMode
;------------- Global Descriptor Table (from Linux 0.01 bootldr) -------------
gdt:
dw 0,0,0,0 ; dummy
dw 0x07FF ; 8Mb - limit=2047 (2048*4096=8Mb)
dw 0x0000 ; base address=0
dw 0x9A00 ; code read/exec
dw 0x00C0 ; granularity=4096, 386
dw 0x07FF ; 8Mb - limit=2047 (2048*4096=8Mb)
dw 0x0000 ; base address=0
dw 0x9200 ; data read/write
dw 0x00C0 ; granularity=4096, 386
gdtend:
gdt_info:
dw gdtend-gdt-1
dd gdt
; ---- FUNCTIONS ---- ;
putStr:
lodsb ; al = [ds:si]
or al, al ; al == 0 ?
jz done
mov ah, $e ; print char
int $10
jmp putStr
done:
ret
;-------- DATA --------;
hello: db " - Hi! Bootloader -", 13, 10, 13, 10, 0
stg1: db "* stage 1: loading stage 2", 13, 10, 0
stg2: db "** stage 2: switching to protected mode...", 13, 10, 0
stg3: db "*** stage 3: loading the kernel", 13, 10, 0
times 510 - ($-$$) db $42
dw 0xAA55
PMode:
mov dword [0xb8000], "done" ;; print out "done" from video memory
@@: jmp @b
|
|
All that I get is a blinking screen from qemu. It outputs my "stage1" and "stage2" strings, and reboot very fastly, forever.
I think my PMode switching is bad and makes the troubles. Am I wrong ? What do you think?
Regards.
_________________ ;; emc
Last edited by emc on 29 Jan 2012, 09:17; edited 1 time in total
|
26 Jan 2012, 18:30 |
|
revolution
When all else fails, read the source
Joined: 24 Aug 2004
Posts: 10800
Location: Galactic Sector ZZ9 Plural Z Alpha
|
Your ORG is 0x0000 but your code is loaded at 0x00007C00. Either set your jump to PMode to point to 0x00007C00+PMode, or set your GDT table for a base of 0x00007C00.
Edit: Another option is to ORG at 0x7c00 and run everything from a 0x0000 base.
|
26 Jan 2012, 18:48 |
|
|
|
I'm going to guess you're booting from a hdd or floppy, where the boot sector size is 512 bytes. Your PMode code is outside this area and so needs to be loaded from the disk first (the code is not actually there at run time). Right after the PMode switch you'll want to set up ds,es,ss to be valid GDT data selectors (which looks to be 0x10).
|
26 Jan 2012, 20:21 |
|
emc
Joined: 20 Aug 2011
Posts: 90
Location: France
|
Quote: |
|
Edit: Another option is to ORG at 0x7c00 and run everything from a 0x0000 base.
|
|
Quote: |
|
Your PMode code is outside this area and so needs to be loaded from the disk first
|
|
Ok, I've added the org directive correctly and I have inserted my MPode in the first 512 bytes. It's work, now.
So I have to switch to PMode after be loaded outside of the first 512 bytes because I have to use the int $13 to load anything from the disk (and pmode don't allow BIOS int). aright?
stage 1: jump outside
stage 2: switching to pmode
stage 3: loading a kernel
Is it a good idea?
Thanks you 
_________________ ;; emc
|
26 Jan 2012, 20:59 |
|
edfed
Joined: 20 Feb 2006
Posts: 3937
Location: In an open world without walls and fences, we wouldn't need Windows and Gates
|
step 1: jump outside
step 2: loading a kernel
step 3: switching to pmode
|
26 Jan 2012, 21:37 |
|
|
|
There's a number of ways you can do this.
e.g. In my project, the HDD version has a "stub" (stage 0) boot sector that uses the BIOS to load the first stage and the CD ISO version boots directly from the first stage*; both use PIO ATA drivers to load the second stage and execute it.
The second stage, still in RMode, enables and checks A20, enumerates the BIOS memory map, enumerates and enables VESA (if available)** and switches to PMode. Again, this has a 32bit PIO ATA driver which is almost the same as the 16bit one, which it uses to scan for its file system and load the core and its drivers before switching to it.
*This difference is because I can't fit my first stage code into a 512 byte HDD sector (is it possible, I just didn't want two versions of the code) but can for the 2048 byte CD sector.
**These are all the things you might want to do in RMode that can't be done in PMode.
----
In my case "stages 2 & 3" are the same since switching to PMode is relatively basic compared to all the other initialisation. BUT there are other projects I've seen that switch immediately to PMode, load their kernels and execute it in their boot sectors.
The point here is it can vary where you choose to divide the different operations AND what you want to do. There is an issue of functionality vs size during the boot process that affects these decisions.
|
26 Jan 2012, 21:47 |
|
edfed
Joined: 20 Feb 2006
Posts: 3937
Location: In an open world without walls and fences, we wouldn't need Windows and Gates
|
what is sure is that 512 bytes is not enough to (be partition root) AND (load&launch kernel from file system) AND (switch pm). it can do only one of them at a time.
better would be to load and launch kernel from file system in a second stage, because the first one of only 512 bytes will just be the partition table.
second stage will load kernel and launch it
and then, kernel is in the mode you want, you can launch applications now!
applications can be any privilege level, it depends on the kernel to determine this iopl at loading.
etc...
hem, maybe it is possible in fact, it depends on how is made the file system.
|
27 Jan 2012, 12:20 |
|
emc
Joined: 20 Aug 2011
Posts: 90
Location: France
|
I am trying to read a 2nd sector of the floppy to get enough memory to switch to PMode as you have suggested.
Here is my code, the carry flag which denote an error is always up after trying to read a 2nd sector:
Code: |
|
;
; yet another try
;
SIZE = 1 ; number of sectors to load (512 bytes is enough)
;------------------------ STAGE 1 ------------------------;
org $7c00
mov [bootdrv], dl ; save the drive number (normally 0, floppy drive A)
mov si, str0
call putstr ; print out the welcome msg
mov si, str1
call putstr ; print out "step 1...."
xor ax, ax ; reset disk drive
int $13 ; dl is already set
mov ah, 2 ; read sectors from drive
mov al, SIZE ; how many sectors?
mov ch, 0 ; read the first track
mov cl, 2 ; read the 2nd sector
mov dh, 0 ; head 0
mov dl, [bootdrv] ; load on the current drive
int $13 ; if error occured then CF = 1
jc @f
jmp stage2
;; fail
@@:
mov si, fuck
call putstr
jmp $
;-- functions --
putstr:
lodsb ; al = [ds:si]
or al, al ; al == 0 ?
jz @f
mov ah, $e ; print char
int $10
jmp putstr
@@: ret
;-- data --
str0: db "- bootloader -", 10, 13, 0
str1: db "> step 1: jumping outside the bootsector...", 0
str2: db "> step 2", 0
done: db "done", 10, 13, 0
fuck: db 10, 13, "failed to read the sector. FUCK! :@", 0
bootdrv: db 0
times 510-($-$$) db $00
dw $aa55
;------------------------ STAGE 2 ------------------------;
stage2:
mov si, done
call putstr ; print "done"
|
|
I think there are bad parameters to the 2nd function of the int $13 which makes this failure. I tried to modify some values (track number, sector number) but the carry flag is still up indicating an error. 
|
27 Jan 2012, 16:49 |
|
emc
Joined: 20 Aug 2011
Posts: 90
Location: France
|
My destination buffer must be $7c00+512 (absolute address) and it's $07e00, so BX has to contain $7e00 and ES has to contain $000 and we have [$0000:$7e00].
Code: |
|
0000
+ 7e00 ($7e00 = $7c00+512)
---------
= 07e00
|
|
I tried that but the problem still occurs 
|
28 Jan 2012, 08:54 |
|
|
|
This is ripped out of some old code from my previous loader:
Code: |
|
use16
org 0x7C00
cli
jmp 0x0000:@f
@@:
xor ax,ax
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0x7C00
mov byte [disk.id],dl
sti
mov ax,1 ; LBA
mov bx,stage2 ; Dst
mov si,1 ; Size
call disk.read
;jc .error
jmp stage2
; in
; ax = LBA
; si = Count
; es:bx = Dst
;
; out
; CF
disk.read:
push ax dx si
.next:
or si,si
jz .done
call disk.readlba
jc .done
mov dx,es
add bx,0x0200
jnc @f
add dx,0x1000
@@:
mov es,dx
inc ax
dec si
jmp .next
.done:
pop si dx ax
ret
; in
; ax = LBA
; es:bx = Dst
; si = Count
;
; out
; CF
disk.readlba:
push ax cx dx di
mov di,0x0005
call disk.lba_chs
@@:
stc
dec di
jz .done
call disk.reset
jc .done
mov ax,0x0201
int 0x13
jc @b
.done:
pop di dx cx ax
ret
;in
;
;out
; CF
disk.reset:
push ax di
mov di,0x0005 ; Attempts
@@:
stc
dec di
jz .done
xor ah,ah
int 0x13
jc @b
.done:
pop di ax
ret
; in
; ax = LBA
;
; out
; ch = C
; cl = S
; dh = H
; dl = Drive ID
disk.lba_chs:
xor dx,dx
div word [disk.s_c]
inc dx
push dx
xor dx,dx
div word [disk.h_c]
pop cx
mov ch,al
mov dh,dl
mov dl,byte [disk.id]
ret
disk.s_c dw 18
disk.h_c dw 2
disk.id db 0
times (0x0200 - ($ - 0x7C00) - 2) db 0
dw 0xAA55
stage2:
mov ax,0x0003
int 0x10
cli
hlt
times (0x0200 - ($ and 0x01FF)) db 0
|
|
The sectors per cylinder (disk.s_c) and heads per cylinder (disk.h_c) values are set up for a floppy disk so need to be modified for a hard disk (this example will actually work for both).
|
28 Jan 2012, 16:39 |
|
|
|
Forum Rules:
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
|
|
|
|
|
Powered by phpBB © 2001-2005 phpBB Group.
|