flat assembler
Message board for the users of flat assembler.

Index > OS Construction > switching to PMode

Author
Thread Post new topic Reply to topic
emc



Joined: 20 Aug 2011
Posts: 90
Location: France
emc
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
Post 26 Jan 2012, 18:30
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17667
Location: In your JS exploiting you and your system
revolution
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.
Post 26 Jan 2012, 18:48
View user's profile Send private message Visit poster's website Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 619
cod3b453
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).
Post 26 Jan 2012, 20:21
View user's profile Send private message Reply with quote
emc



Joined: 20 Aug 2011
Posts: 90
Location: France
emc
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 Smile

_________________
;; emc
Post 26 Jan 2012, 20:59
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4242
Location: 2018
edfed
step 1: jump outside
step 2: loading a kernel
step 3: switching to pmode
Post 26 Jan 2012, 21:37
View user's profile Send private message Visit poster's website Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 619
cod3b453
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.
Post 26 Jan 2012, 21:47
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4242
Location: 2018
edfed
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.
Post 27 Jan 2012, 12:20
View user's profile Send private message Visit poster's website Reply with quote
emc



Joined: 20 Aug 2011
Posts: 90
Location: France
emc
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. Rolling Eyes
Post 27 Jan 2012, 16:49
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 313
Mac2004
emc: Where's your destination buffer es:bx setup?

Your are trying to load the second sector to linear address 0x7e00.
es:bx needs to be setup according to your destination.

http://en.wikipedia.org/wiki/INT_13H#INT_13h_AH.3D02h:_Read_Sectors_From_Drive

Regards
Mac2004
Post 27 Jan 2012, 19:53
View user's profile Send private message Reply with quote
emc



Joined: 20 Aug 2011
Posts: 90
Location: France
emc
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 Confused
Post 28 Jan 2012, 08:54
View user's profile Send private message Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 619
cod3b453
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).
Post 28 Jan 2012, 16:39
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
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 can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.