Switch to PMode not working

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
chris

Switch to PMode not working

Post by chris »

When I try this on my test computer it just hangs. I'm in the process of getting Bochs running so I can get some debug info.

Code: Select all

ORG 00000h
BITS 16
        
main:   
        mov     ax, 07C00h
        mov     ds, ax
        mov     ax, 08000h
        mov     ss, ax
        mov     ax, 09000h
        mov     sp, ax
        
        ; Enable the A20 line.
        call    .enable_a20
        ; Reprogram the PIC.
        ; call  .reprogPIC
        
        ; Re-enable the keyboard (if it's off)
        mov     al, 0AEh
        mov     dx, 064h
        out     dx, al
        
        cli

        lgdt    [gdt_main]
        lidt    [idt_main]
        
        mov     eax, 000000011h
        mov     cr0, eax

        jmp     dword 008h:main32
        
; Candy's A20 Code:
        
.a20_tries db 00FFh
        
.empty_8042:
       push    cx
        mov     cx, 65535

.empty_8042_loop:
        dec     cx
        jz      .empty_8042_end_loop

        mov     dx, 064h
        in      al, dx
        test    al, 01h
        jz      .no_output

        mov     dx, 064h
        in      al, dx
        jmp     .empty_8042_loop

.no_output:
        test    al, 02h
        jnz     .empty_8042_loop

.empty_8042_end_loop:
        pop     cx
        ret

.enable_a20:

.a20_none:
        call    .a20_test
        jnz     .a20_done

.a20_bios:
        mov     ax, 02401h
        pushf
        int     015h
        popf
        call    .a20_test
        jnz     .a20_done

.a20_kbc:
 call    .empty_8042

        call    .a20_test
        jnz     .a20_done

        mov     al, 0D1h
        mov     dx, 064h
        out     dx, al

        call    .empty_8042

        mov     al, 0DFh
        mov     dx, 060h
        out     dx, al

        call    .empty_8042

        mov     dx, 092h
        in      al, dx
        or      al, 02h
        and     al, 0FEh
        out     dx, al

.a20_wait:
        xor     cx, cx

.a20_wait_loop:
        call    .a20_test
        jnz     .a20_done
        loop    .a20_wait_loop

        mov     bx, .a20_tries
        dec     byte [bx]
        jnz     .enable_a20
        mov     si, .a20_not_working
        ; call  print_message_16

.crash:
        hlt
        jmp     .crash

.crash:
        hlt
        jmp     .crash

.a20_done:
        ret

.a20_not_working db "Unable to enable A20 gate, booting failed."

.a20_test:
        push    cx
        push    ax
        xor     cx, cx
        mov     fs, cx
        dec     cx
        mov     gs, cx
        mov     cx, 020h
        mov     ax, [fs:600h]
        push ax

.a20_test_wait:
        inc     ax
        mov     [fs:600h], ax
        wbinvd
        cmp     ax, [gs:610h]
        je      .a20_test_wait

        pop     ax
        mov     [fs:600h], ax
        pop     ax
        pop     cx
        ret

loc     dw      0

gdt
        ; Null descriptor.
        dw 00000h

        ; Here we cheat a bit, using a portion of our null descriptor as the GDT
        ; data loaded into GDTR, saving some bytes.
gdt_main
        dw 007FFh
        dw 01800h

        ; CPL0 code segment.
        dw 0FFFFh
        dw 00000h
        dw 09A00h
        dw 000CFh

        ; CPL0 data/stack segment.
        dw 0FFFFh
        dw 00000h
        dw 09200h
        dw 000CFh

        ; Alignement
        dw 00000h

idt_main
        dw 007FFh
        dw 01000h

BITS 32

main32:
        ; Reload segment registers with our CPL0 data/stack segment.
        mov     ax, 010h
        mov     ds, ax
        mov     es, ax
        mov     fs, ax
        mov     gs, ax
        mov     ss, ax

        mov     eax, 0B8000h
        mov     [eax], byte 'X'
        mov     [eax + 1], byte 007h

        jmp $

  times 512 - ($ - $$) - 2 db 0

        dw 0AA55h

aladdin

Re:Switch to PMode not working

Post by aladdin »

Try this
mov eax,cr0
or ax,1
mov cr0,eax ; set PMode to 1

jmp next
next :
; Reload segment registers with our CPL0 data/stack segment.
mov ax, 010h
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

mov esp, 0x9F000 ;you forgot this line

jmp dword addresse_of_your kernel
instead of this

mov eax, 000000011h
mov cr0, eax

jmp dword 008h:main32

hope this will help u
DennisCGc

Re:Switch to PMode not working

Post by DennisCGc »

Hi,

Code: Select all

        mov    eax, 000000011h
Is it a typo ? AFAIK it should b instead of h...
chris

Re:Switch to PMode not working

Post by chris »

I tried what aladdin said, but had no luck. This is what Bochs is saying:
00004279641i[CPU0 ] -----------------------------------
00004279641i[CPU0 ] selector->index*8 + 7 = 15
00004279641i[CPU0 ] gdtr.limit = 0
00004279641i[CPU0 ] fetch_raw_descriptor: GDT: index > limit
00004279641i[CPU0 ] | EAX=00000011 EBX=00000000 ECX=000b0001 EDX=00000064
00004279641i[CPU0 ] | ESP=00009000 EBP=00000000 ESI=00000000 EDI=0000ffe4
00004279641i[CPU0 ] | IOPL=0 NV UP DI PL NZ NA PO NC
00004279641i[CPU0 ] | SEG selector base limit G D
00004279641i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00004279641i[CPU0 ] | DS:7c00( 0000| 0| 0) 0007c000 0000ffff 0 0
00004279641i[CPU0 ] | ES:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00004279641i[CPU0 ] | FS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00004279641i[CPU0 ] | GS:ffff( 0000| 0| 0) 000ffff0 0000ffff 0 0
00004279641i[CPU0 ] | SS:8000( 0000| 0| 0) 00080000 0000ffff 0 0
00004279641i[CPU0 ] | CS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00004279641i[CPU0 ] | EIP=00007c34 (00007c2c)
00004279641i[CPU0 ] | CR0=0x00000011 CR1=0x00000000 CR2=0x00000000
00004279641i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00004279641i[CPU0 ] -----------------------------------
00004279641e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetti
ng
chris

Re:Switch to PMode not working

Post by chris »

I fixed my GDT pointer (should be "dd 01800h" and not dw ..") and now Bochs outputs:

Code: Select all

00004279641i[CPU0 ] -----------------------------------
00004279641i[CPU0 ] selector->index*8 + 7 = 15
00004279641i[CPU0 ] gdtr.limit = 0
00004279641i[CPU0 ] fetch_raw_descriptor: GDT: index > limit
00004279641i[CPU0 ] | EAX=00000011  EBX=00000000  ECX=000f0001  EDX=00000064
00004279641i[CPU0 ] | ESP=00009000  EBP=00000000  ESI=00000000  EDI=0000ffe4
00004279641i[CPU0 ] | IOPL=0 NV UP DI PL NZ NA PO NC
00004279641i[CPU0 ] | SEG selector     base    limit G D
00004279641i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00004279641i[CPU0 ] |  DS:7c00( 0000| 0|  0) 0007c000 0000ffff 0 0
00004279641i[CPU0 ] |  ES:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00004279641i[CPU0 ] |  FS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00004279641i[CPU0 ] |  GS:ffff( 0000| 0|  0) 000ffff0 0000ffff 0 0
00004279641i[CPU0 ] |  SS:8000( 0000| 0|  0) 00080000 0000ffff 0 0
00004279641i[CPU0 ] |  CS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00004279641i[CPU0 ] | EIP=00007c34 (00007c2c)
00004279641i[CPU0 ] | CR0=0x00000011 CR1=0x00000000 CR2=0x00000000
00004279641i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00004279641i[CPU0 ] >> 66
00004279641i[CPU0 ] >> ea
00004279641i[CPU0 ] >> 0e
00004279641i[CPU0 ] >> 01
00004279641i[CPU0 ] >> 00
00004279641i[CPU0 ] >> 00
00004279641i[CPU0 ] >> 08
00004279641i[CPU0 ] >> 00
00004279641i[CPU0 ] >> : opsize jmp 0008:0000010e
00004279641i[CPU0 ] -----------------------------------
00004279641e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting

Dreamsmith

Re:Switch to PMode not working

Post by Dreamsmith »

Code: Select all

        lgdt    [gdt_main]
...
gdt_main
        dw 007FFh
        dw 01800h

        ; CPL0 code segment.
        dw 0FFFFh
So, your GDT is at address 0xFFFF1800? If not, then this code is in error. Your LIDT code looks fishy too.

Perhaps you meant "dd" instead of "dw"?
chris

Re:Switch to PMode not working

Post by chris »

I fixed the IDT problem earlier, I should have mentioned that. I also had forgotten to write the code to move my GDT to 0x1800. Here is the new code, but it still hangs.
chris

Re:Switch to PMode not working

Post by chris »

Code: Select all

ORG 00000h
BITS 16

main:
        mov     ax, 07C00h
        mov     ds, ax
        mov     ax, 08000h
        mov     ss, ax
        mov     ax, 09000h
        mov     sp, ax

        ; Enable the A20 line.
        call    .enable_a20
        ; Reprogram the PIC.
        ; call  .reprogPIC

        ; Re-enable the keyboard (if it's off)
        mov     al, 0AEh
        mov     dx, 064h
        out     dx, al

        cli

        ; Prevent undefined stuff.
        mov     di, 01000h
        mov     cx, 0400h
        xor     eax, eax
        cld
        rep     stosd

        ; Move the GDT to 0x1800 linear.
        mov     si, gdt
        mov     di, 01800h
        mov     ecx, 010h
        rep     movsd

        lgdt    [gdt_main]
        lidt    [idt_main]

        mov     eax, 000000011h
        mov     cr0, eax

        jmp     dword 008h:main32

 ... A20 Stuff

gdt                                             
        ; Null descriptor.                        
        dw 00000h
                                                        
        ; Here we cheat a bit, using a portion of our null descriptor as the GDT
        ; data loaded into GDTR, saving some bytes.
gdt_main                                                        
        dw 007FFh                                                 
        dd 01800h

      ; CPL0 code segment.                                                            
        dw 0FFFFh
        dw 00000h                                                                               
        dw 09A00h
        dw 000CFh

        ; CPL0 data/stack segment.
        dw 0FFFFh 
        dw 00000h 
        dw 09200h
        dw 000CFh
        
        ; Alignement  
        dw 00000h
        
idt_main
        dw 007FFh
        dd 01000h 
        
BITS 32 
        
main32: 
        ; Reload segment registers with our CPL0 data/stack segment.
        mov     ax, 010h
        mov     ds, ax
        mov     es, ax
        mov     fs, ax                    
        mov     gs, ax
        mov     ss, ax
                                                
        mov     esp, 0A0000h                      

        mov     eax, 0B8000h                    
        mov     [eax], byte 'X'                   
        mov     [eax + 1], byte 007h
                                                        
        jmp $
        
        times 512 - ($ - $$) - 2 db 0                           
        
        dw 0AA55h
Boch's Output:

Code: Select all

00004280688i[CPU0 ] -----------------------------------
00004280688i[CPU0 ] selector->index*8 + 7 = 15
00004280688i[CPU0 ] gdtr.limit = 0
00004280688i[CPU0 ] fetch_raw_descriptor: GDT: index > limit
00004280688i[CPU0 ] | EAX=00000011  EBX=00000000  ECX=00000000  EDX=00000064
00004280688i[CPU0 ] | ESP=00009000  EBP=00000000  ESI=0000014a  EDI=00001840
00004280688i[CPU0 ] | IOPL=0 NV UP DI PL ZR NA PE NC
00004280688i[CPU0 ] | SEG selector     base    limit G D
00004280688i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00004280688i[CPU0 ] |  DS:7c00( 0000| 0|  0) 0007c000 0000ffff 0 0
00004280688i[CPU0 ] |  ES:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00004280688i[CPU0 ] |  FS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00004280688i[CPU0 ] |  GS:ffff( 0000| 0|  0) 000ffff0 0000ffff 0 0
00004280688i[CPU0 ] |  SS:8000( 0000| 0|  0) 00080000 0000ffff 0 0
00004280688i[CPU0 ] |  CS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00004280688i[CPU0 ] | EIP=00007c50 (00007c48)
00004280688i[CPU0 ] | CR0=0x00000011 CR1=0x00000000 CR2=0x00000000
00004280688i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00004280688i[CPU0 ] >> 66
00004280688i[CPU0 ] >> ea
00004280688i[CPU0 ] >> 2a
00004280688i[CPU0 ] >> 01
00004280688i[CPU0 ] >> 00
00004280688i[CPU0 ] >> 00
00004280688i[CPU0 ] >> 08
00004280688i[CPU0 ] >> 00
00004280688i[CPU0 ] >> : opsize jmp 0008:0000012a
00004280688i[CPU0 ] -----------------------------------
00004280688e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetti
ng
Something must still be wrong with my GDT...
Curufir

Re:Switch to PMode not working

Post by Curufir »

Code: Select all

        mov    ax, 07C00h
        mov    ds, ax

....

        ; Move the GDT to 0x1800 linear.
        mov    si, gdt
        mov    di, 01800h
        mov    ecx, 010h
        rep    movsd
You never bother to set DS to 0, so you've just copied your GDT into a segment starting at 0x7c00. A segment which is wrong for a bootloader anyhow, since it should be 0x7c0 if your ORG is 0. Either way this means you load GDTR with garbage, and then try to use that bad GDTR to load garbage as a selector. At this point Bochs runs home to mommy crying.

In other words.
Old man: This is a warning...not to disturb the Ark of the Covenant.
Jones: What about the height of the staff? Did Belloq get it off of here?
Old man: Yes, it is here...This means six kadams high - 'about seventy-two inches'. Wait! And take back one kadam to honor the Hebrew God whose Ark this is.
Jones: You said their headpiece only had markings on one side. Are you absolutely sure? Belloq's staff is too long.
Sallah and Jones: They're digging in the wrong place! (laughing)
chris

Re:Switch to PMode not working

Post by chris »

I fixed the 0x7C0 thing, and switched my GDT relocation code to:

Code: Select all

; Move the GDT to 0x1800 linear.
        mov     si, gdt
        mov     ax, 0
        mov     es, ax
        mov     di, 01800h
        mov     ecx, 010h
        rep     movsd
the NASM docs say movsd will move [DS:SI] to [ES:DI]

What is still wrong?

All I see in bochsout.txt is

Code: Select all

00004280691e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetti
ng
Curufir

Re:Switch to PMode not working

Post by Curufir »

Code: Select all

        mov    eax, 000000011h
        mov    cr0, eax
This is not good, not good at all. The idea is to turn on the PE bit, not destroy all the others (That includes screwing with the MP bit until you need to).

Try this instead:

Code: Select all

mov eax, cr0
or eax, 1
mov cr0, eax
chris

Re:Switch to PMode not working

Post by chris »

I'm still getting the same error.

How can I use the Bochs debugger to find where it's happening?
Curufir

Re:Switch to PMode not working

Post by Curufir »

Code: Select all

 jmp    dword 008h:main32
This will be jumping to the wrong place.

main32 is a label representing the offset from the start of the text section (Because you're using ORG 0), but that text section has been loaded into the segment starting at 0x7c00. Since when you do the absolute jump the place you want branch to is offset from 0 in memory you need to add 0x7c00 to main32 to reach the right place.

Bochs debugging is just a question of setting some breakpoints and stepping through. The manual makes plenty of sense.
chris

Re:Switch to PMode not working

Post by chris »

That was it! It works now. Thanks Curufir and everyone else that posted.

Now it's onto filesystem interpretation :).
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Switch to PMode not working

Post by Brendan »

Hi,
Curufir wrote: This is not good, not good at all. The idea is to turn on the PE bit, not destroy all the others (That includes screwing with the MP bit until you need to).

Try this instead:

Code: Select all

mov eax, cr0
or eax, 1
mov cr0, eax
Messing up the other flags isn't such a bad idea - or at least clearing the cache disable flags and task switched flag (some BIOSs leave the caches disabled, and some versions of windows leaves the TS flag set).

As long as the CPU does have an FPU, then
"mov cr0, 000000011h" isn't a bad idea. If it's possible that there is no FPU then I'd use something like:

Code: Select all

        mov    eax, cr0
        and     eax,0x00000010
        or       eax,0x00000001
        mov    cr0, eax

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.
Post Reply