[SOLVED] Can't jump to 0xC0000000 with paging enabled

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
User avatar
tokusan
Member
Member
Posts: 29
Joined: Mon Feb 24, 2020 10:18 pm
Location: Japan

[SOLVED] Can't jump to 0xC0000000 with paging enabled

Post by tokusan »

Hello.

I'm trying to implement paging on my OS. I prepared a page directory, and page table for kernel. Page directory starts from 0x00100000 and page table for kernel starts from 0x00101000.
After enabling paging, I tried JMP 0xC0000000, but kernel codes weren't executed. Without -no-shutdown and -no-reboot options, QEMU reboots infinitely.

Code: Select all

    DIR                  EQU 0x00100000
    MOV                 EAX, DIR
    MOV                 CR3, EAX

    MOV                 EAX, CR0
    OR                  EAX, 0x80000000
    MOV                 CR0, EAX

    MOV              ESP,0xC0080FFF
    MOV              EBP,ESP
    JMP              0xC0000000
Header code:https://gist.github.com/cb41cfce58bbcf7 ... e395b3c286
paging.asm: https://gist.github.com/720ff535ee9cad7 ... 9e36ede536
vbe.asm: https://gist.github.com/0e8d23d03ad9b97 ... d779778c0f
(I don't think vbe.asm is related to this problem.)

QEMU execution:

Code: Select all

qemu-system-i386 -drive file=build/ramen_os.img,format=raw,if=floppy -monitor stdio -no-shutdown -no-reboot
QEMU debugging console output:
(qemu) info status
VM status: paused (shutdown)
(qemu) info registers
EAX=80000011 EBX=0000418b ECX=00000000 EDX=00100000
ESI=0008c400 EDI=00102400 EBP=c0080fff ESP=c0080ff7
EIP=000068da EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 00000000 00000000 00000000
CS =0000 00000000 0000ffff 00009b00 DPL=0 CS16 [-RA]
SS =0008 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0008 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0008 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0008 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 0000c3e0 00000017
IDT= 00000000 000003ff
CR0=80000011 CR2=00000000 CR3=00100000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
(qemu) info mem
0000000000000000-0000000000100000 0000000000100000 -r-
00000000c0000000-00000000c0081000 0000000000081000 -r-
(qemu) xp /4w 0x00100000 + 0x300 * 4
0000000000100c00: 0x00101021 0x00000000 0x00000000 0x0000000
(qemu) xp /4w 0x00101000
0000000000101000: 0x00501001 0x00502001 0x00503001 0x00504001
(qemu) xp /4w 0x00501000
0000000000501000: 0x0000feeb 0x00000000 0x00000000 0x00000000
(qemu) info mem
0000000000000000-0000000000100000 0000000000100000 -r-
00000000c0000000-00000000c0081000 0000000000081000 -r-
(qemu) info tlb
0000000000000000: 0000000000000000 ---DA----
0000000000001000: 0000000000001000 ---------
0000000000002000: 0000000000002000 ----A----
0000000000003000: 0000000000003000 ---------
0000000000004000: 0000000000004000 ----A----
0000000000005000: 0000000000005000 ---DA----
0000000000006000: 0000000000006000 ----A----
0000000000007000: 0000000000007000 ---------
0000000000008000: 0000000000008000 ---------
0000000000009000: 0000000000009000 ---------
000000000000a000: 000000000000a000 ---------
000000000000b000: 000000000000b000 ---------
000000000000c000: 000000000000c000 ---DA----
000000000000d000: 000000000000d000 ---------
...
00000000000fe000: 00000000000fe000 ---------
00000000000ff000: 00000000000ff000 ---------
00000000c0000000: 0000000000501000 ---------
00000000c0001000: 0000000000502000 ---------
...
00000000c007f000: 0000000000580000 ---------
00000000c0080000: 0000000000582000 ---DA----
Kernel code (This code isn't the actual kernel code, but for testing paging) :

Code: Select all

    EXTERN os_main

os_main:
    HLT
    JMP os_main
Linker script:

Code: Select all

OUTPUT_FORMAT(binary);
OUTPUT_ARCH(i386);

ENTRY(os_main)

SECTIONS
{
    .text 0xC0000000 : { *(.text*) }

    .data : {
        *(.data)
        *(.rodata*)
        *(.bss)
    }

    /DISCARD/ : { *(.eh_frame) }
}
From the output of QEMU debugging console, it's obvious the page directory entry of kernel is accessed. However, Access bit of page table entry of kernel is 0, which means the page table entry isn't accessed.
Last edited by tokusan on Thu Feb 27, 2020 6:37 pm, edited 1 time in total.
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Can't jump to 0xC0000000 with paging enabled

Post by bzt »

Hi,

Try with bochs, in the debugger prompt type

Code: Select all

bochs:x> page 0xC000000
This will tell you exactly what's wrong with your paging tables. Qemu doesn't have such a sophisticated feature, "info tbl" is nowhere near.

Cheer,
bzt
Octocontrabass
Member
Member
Posts: 5578
Joined: Mon Mar 25, 2013 7:01 pm

Re: Can't jump to 0xC0000000 with paging enabled

Post by Octocontrabass »

tokusan wrote:

Code: Select all

qemu-system-i386 -drive file=build/ramen_os.img,format=raw,if=floppy -monitor stdio -no-shutdown -no-reboot
Add "-d int" to see which exceptions are causing the triple fault.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can't jump to 0xC0000000 with paging enabled

Post by iansjack »

Your CS value is zero, which is not valid.

You don't say what bootloader your are using, but after entering Protected Mode you need to do a far jump to set CS.
User avatar
tokusan
Member
Member
Posts: 29
Joined: Mon Feb 24, 2020 10:18 pm
Location: Japan

Re: Can't jump to 0xC0000000 with paging enabled

Post by tokusan »

Thanks for replying
Try with bochs, in the debugger prompt type
I haven't used bochs so I'm trying it. I'll post the output of page 0xC0000000 later.
Add "-d int" to see which exceptions are causing the triple fault.
log:https://gist.github.com/f244d878e393e5e ... d5d757f7e2
Your CS value is zero, which is not valid.
Isn't CS value 0000 00000000 0000ffff 00009b00? Then what's the CS value?
You don't say what bootloader your are using
I don't use any bootloaders like GRUB. My OS is supposed to be installed on floppy. (I know it's too old way, but I do what my book says.)
IPL:https://gist.github.com/251878e5b52ce6f ... e81018a5b6
but after entering Protected Mode you need to do a far jump to set CS.
Isn't this code valid?

Code: Select all

    LGDT     [GDTR0]
    MOV      EAX,CR0
    AND      EAX,0x7fffffff              
    OR       EAX,0x00000001             
    MOV      CR0,EAX
    JMP      pipelineflush
pipelineflush:
EDIT:

Code: Select all

<bochs:2> page 0xC0000000
 PDE: 0x0000000000101021    ps         A pcd pwt S R P
 PTE: 0x0000000000501001       g pat d a pcd pwt S R P
linear page 0x00000000c0000000 maps to physical page 0x000000501000
bochs log:https://gist.github.com/40dc8223d7c63b4 ... 314e944f1f
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can't jump to 0xC0000000 with paging enabled

Post by iansjack »

In Protected Mode, the values in the segment registers (as far as the programmer is concerned) are offsets into a descriptor table. These indexes are typically small numbers, such as 0x01, 0x02, etc. The register actually consists of the index plus 3 bits (the lowest 3) specifying the privilege level and the table referred to. This means that the index is multiplied by 8 and then the additional bits are ORed with this value. So the lowest possible value in the register is 0x08 - as I said before, index 0, which corresponds to the first slot in the table, is not allowed. Currently your CS register is 0, which is invalid and will cause a GP exception. To load a value into the CS register you must do a far jump - something of the form "jmp 0x08:0x1234" (although there are other ways of loading CS, this is the way it is typically done just after entering Protected Mode).

Rather than blindly following some book or tutorial I would highly recommend that you read the Intel Programmer's Manuals and try to understand what the instructions that you use are doing. For a beginner, it is much easier to follow the Bare Bones tutorials on this site and use GRUB as your bootloader. This takes care of setting up a basic Protected Mode system.
Octocontrabass
Member
Member
Posts: 5578
Joined: Mon Mar 25, 2013 7:01 pm

Re: Can't jump to 0xC0000000 with paging enabled

Post by Octocontrabass »

Code: Select all

check_exception old: 0xffffffff new 0x6
     0: v=06 e=0000 i=0 cpl=0 IP=0000:000068da pc=000068da SP=0008:c0080ff7 env->regs[R_EAX]=80000011
The CPU tried to execute an invalid instruction at address 0x68da. Since you haven't set up exception handlers yet, this caused a triple fault.

I don't know what's supposed to be at that address. If the CPU shouldn't be executing code at that address, you'll need to step through the code with a debugger to see how it gets there.
iansjack wrote:Your CS value is zero, which is not valid.
The descriptor cache is valid, so it will continue to work as long as you don't try to load 0 into CS while in protected mode. It does look like the code is intended to use a far jump instead of a near jump though.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can't jump to 0xC0000000 with paging enabled

Post by iansjack »

From the Intel manual, describing entry to Protected Mode:
3. Execute a MOV CR0 instruction that sets the PE flag (and optionally the PG flag) in control register CR0.

4. Immediately following the MOV CR0 instruction, execute a far JMP or far CALL instruction. (This operation is typically a far jump or call to the next instruction in the instruction stream.)
...
Random failures can occur if other instructions exist between steps 3 and 4 above.
Without a far jump how would the descriptor cache have been initialized with valid data in the first place?
Octocontrabass
Member
Member
Posts: 5578
Joined: Mon Mar 25, 2013 7:01 pm

Re: Can't jump to 0xC0000000 with paging enabled

Post by Octocontrabass »

The CPU is always using the descriptor cache, even in real mode. It has to be valid for the CPU to reach that point to begin with. It's the same as how unreal mode works, just in the other direction.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can't jump to 0xC0000000 with paging enabled

Post by iansjack »

I think I'll continue to rely on the information published by Intel.
Random failures can occur if other instructions exist between steps 3 and 4 above.
User avatar
tokusan
Member
Member
Posts: 29
Joined: Mon Feb 24, 2020 10:18 pm
Location: Japan

Re: Can't jump to 0xC0000000 with paging enabled

Post by tokusan »

Finally I got it. As @iansjack said, my OS had to do far jump.

Code: Select all

    LGDT     [GDTR0]
    MOV      EAX,CR0
    AND      EAX,0x7fffffff
    OR       EAX,0x00000001
    MOV      CR0,EAX
    JMP      DWORD 08h:pipelineflush
    [bits 32]
pipelineflush:
    ; ...
GDT0:
    TIMES    8 DB 0 
    DW       0xffff,0x0000,0x9a00,0x00cf 
    DW       0xffff,0x0000,0x9200,0x00cf 

    DW       0
GDTR0:
    DW       8*3-1
    DD       GDT0
When it used segmentation, it didn't far jump to data segment immediately after MOV CR0. Dozens of line were inserted between MOV CR0 and JMP 2*8:offset. So I misunderstood that it was unnecessary for my OS to do far jump.
Thanks for your support and sorry for not reading posts and my codes carefully.
Post Reply