Jumping to GRUB module adress causes rpl !=CPL in bochs
Jumping to GRUB module adress causes rpl !=CPL in bochs
Jumping to module adress in multiboot header in GRUB causes load_seg_reg(SS): rpl != CPL. I don`t have userspace now and of course it is kernel space. Paging is disabled, if I enable it I have page fault. Obviously, rpl != CPL and not jumping to garbage exception means I reach that code. But why doesn`t it work? Module is compiled using nasm -fbin and just sets eax to 0xDEADBEEF. I believe that gdt and idt are doing fine to since everything else is working.
source: https://github.com/nergzd723/ethanium
source: https://github.com/nergzd723/ethanium
-
- Member
- Posts: 5578
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
Does it do anything else? The CPU isn't going to stop when it reaches the end of the file unless you tell it to.nergzd723 wrote:Module is compiled using nasm -fbin and just sets eax to 0xDEADBEEF.
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
Yes, jmp $ intended to stop the cpu. It seems like it`s something wrong with segments but I am sure that my GDT is okay
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
Hi,
Cheers,
bzt
From the Multiboot specification:nergzd723 wrote:Yes, jmp $ intended to stop the cpu. It seems like it`s something wrong with segments but I am sure that my GDT is okay
I think you should set up GDT here and the segment registers before you make a call to kmain (even if that's just a temporary hardcoded GDT and not the final one). Thay way you'll have a known-to-be-good segment registers, regardless what the loader passed to you. According to the spec, Multiboot does not guarantee anything about privileges (for instance that RPL and CPL will match), it only guarantees base of 0 and limit of 0xFFFFFFFF, but that's all. As a matter of fact, the Multiboot spec states: "The exact values are all undefined".the OS image must not load any segment registers (even just reloading the same values!) until it sets up its own ‘GDT’.
Cheers,
bzt
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
I believe your multiboot boot module should be an elf object file rather than a raw binary.
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
After taking a quick look, this doesn't seem right: https://github.com/nergzd723/ethanium/b ... ty.asm#L20
osdev project, goal is to run wasm as userspace: https://github.com/kwast-os/kwast
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
Your jmp_tomod function references GDT descriptors four and five, but you only have three in the GDT.
Carpe diem!
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
Thank you all for replies!
Then, I tried initializing GDT and IDT and set up syscall handler and nothing more, then jumping to app. I got error:
Does it mean that kernel runs at cpl2? It should be zero. Qemu just throw GPF.
And if I don`t have user code and user data segs, I get loading null selector error. I have no idea why is it wrong.
If I do that, the multiboot info would be wrong somewhy, magic is bad.I think you should set up GDT here and the segment registers before you make a call to kmain (even if that's just a temporary hardcoded GDT and not the final one).
Then, I tried initializing GDT and IDT and set up syscall handler and nothing more, then jumping to app. I got error:
Code: Select all
check_cs: confronting code seg descriptor dpl > cpl, dpl=3, cpl=2
And if I don`t have user code and user data segs, I get loading null selector error. I have no idea why is it wrong.
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
Hi,
Calling a function uses SS register, don't do that until you're sure you have a valid one. For example:(note: this is just a simple example I wrote from memory, could be typos in it. You also need to tailor it to your needs. Some assembler needs "$8" etc. To set up CS as well, you'll need a far call to 16:kmain.)
Cheers,
bzt
Don't do anything complex that changes registers. Just a single "lgdt" instruction with a static GDT. Then you can use segments in your jmp_tomod.nergzd723 wrote:Thank you all for replies!If I do that, the multiboot info would be wrong somewhy, magic is bad.I think you should set up GDT here and the segment registers before you make a call to kmain (even if that's just a temporary hardcoded GDT and not the final one).
Calling a function uses SS register, don't do that until you're sure you have a valid one. For example:
Code: Select all
; hardcoded temporary GDT until we set it up properly
align 16
GDT_table: dd 0, 0 ;null descriptor
dd 0000FFFFh,008F9200h ;32 bit prot mode flat ds
dd 0000FFFFh,00CF9A00h ;32 bit prot mode ring0 cs
GDT_value: dw GDT_value-GDT_table
dd GDT_table
start:
cld ; Clear the direction flag for string operations
mov esp, eax ; save eax in esp register which we will set anyway
lgdt [GDT_value] ; set up segment registers
mov ax, 8
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, esp ; restore eax with magic
mov esp, kernel_stack_top ; Set up the stack
; ...
Don't complicate your life, it's enough if you set up IDT later. Just focus on GDT.nergzd723 wrote:Then, I tried initializing GDT and IDT and set up syscall handler and nothing more
Cheers,
bzt
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
Thank you, bzt! I`ve done something like that:
Now I have triple fault, but I am sure that it even doesn`t reach kmain because COM1 is not initialized. QEMU says that I am trying to execute code outside of the RAM or the ROM. Ooops, forgot about ESP, where EAX is stored: it is 2BADB006, and eax originaly was 2BADB002.
Code: Select all
start:
cld ; Clear the direction flag for string operations
call gdt_setup
mov esp, kernel_stack_top ; Set up the stack
push eax; ; Push multiboot header
push ebx; ; Push multiboot magic
extern kmain
call kmain ; Jump to kmain (never to return)
cli ; We should not return here, but if we do:
hlt
jmp $ ; clear all interrupts and halt
gdt_setup:
mov esp, eax ; save eax
lgdt[GDT_V] ; set up hardcoded GDT
mov ax, 8
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, esp ; restore it
jmp 0x10:.fl
.fl:
ret
align 16
GDT_T:
dd 0, 0 ;null descriptor
dd 0000FFFFh, 008F9200h
dd 0000FFFFh, 00CF9A00h
GDT_V:
dw GDT_V-GDT_T
dd GDT_T
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
No wonder. I told you not to use "call". Inline the whole gdt_setup thing! Calling a function requires accessing SS as well as ESP, neither is at a known state, you should not rely on them. Also you're saving EAX in ESP inside the function body, so you lost the return address for sure.nergzd723 wrote:Now I have triple fault
Inlining that function will remove the stack dependency and with that it will solve your issue.
Code: Select all
start:
cld ; Clear the direction flag for string operations
mov esp, eax ; save eax
lgdt[GDT_V] ; set up hardcoded GDT
mov ax, 8
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, esp ; restore it
mov esp, kernel_stack_top ; Set up the stack
push eax; ; Push multiboot header
push ebx; ; Push multiboot magic
call 0x10:kmain ; Far call to kmain (never to return) sets up CS as well
Code: Select all
push eax; ; Push multiboot header
push ebx; ; Push multiboot magic
push .retaddr
jmp 0x10:kmain
.retaddr:
Cheers,
bzt
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
Oops, forgot to say that I actually tried inlining that, but it just loops.
According to bochs:
Why does it just loop that? call -469 returns execution to beginning of it. But now we are running in 0010: selector according to bochs.
According to bochs:
Code: Select all
push ebp
mov ebp, esp
sub esp, 0x0000004
mov eax, dword ptr ss:[ebp+8]
mov word ptr ss:[ebp-20], ax
mov eax, dword ptr ss:[ebp-20]
mov edx, eax
in al, dx
mov byte ptr ss:[ebp-1], al
mov al, byte ptr ss:[ebp-1]
leave
ret
add esp, 0x00000004
movzx eax, al
and eax, 0x00000020
leave
ret
test eax, eax
jz .-9 (0x00100540)
call .-42 (0x0010051b)
push ebp
mov ebp, esp
push 0x000003fd
call .-469(0x00100353)
-
- Member
- Posts: 797
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
Can you update your git repo with the exact version of your code that is giving you troubles. The version you have in Git has missing build directory, usr.o seems to be in the wrong place and can't be found and even when linked there are a bunch of undefined references. I'd like to build your project and take a look.
Some of what bzt has told you is inaccurate about what you can do without loading your own GDT. He seems to be under the mistaken impression that you can't put things on the stack without setting your own SS (it is correct you do need to set ESP).
Although the GDTR may be invalid per the Multiboot spec you are able to use CS, DS, ES, SS, FS, and GS for all types of memory accesses as long as you don't attempt to reload any of those segment registers. You can't assume the selectors in those segment registers are a particular value (that is true). You are able to continue using the Multiboot segment registers because the CPU uses the value in the hidden descriptor cache which is only changed when a segment is reloaded with new values. If the CPU is using an invalid GDTR and you do load a value into a segment register the processor will likely fault.
Without your own GDT you can't reliably do FAR calls; FAR jmp; FAR Returns; POP to segment registers; IRET; or any mov instruction that updates a segment register etc. A side effect is without your own GDT you can't reliably do interrupts which would severely limit your OS.
Some of what bzt has told you is inaccurate about what you can do without loading your own GDT. He seems to be under the mistaken impression that you can't put things on the stack without setting your own SS (it is correct you do need to set ESP).
Although the GDTR may be invalid per the Multiboot spec you are able to use CS, DS, ES, SS, FS, and GS for all types of memory accesses as long as you don't attempt to reload any of those segment registers. You can't assume the selectors in those segment registers are a particular value (that is true). You are able to continue using the Multiboot segment registers because the CPU uses the value in the hidden descriptor cache which is only changed when a segment is reloaded with new values. If the CPU is using an invalid GDTR and you do load a value into a segment register the processor will likely fault.
Without your own GDT you can't reliably do FAR calls; FAR jmp; FAR Returns; POP to segment registers; IRET; or any mov instruction that updates a segment register etc. A side effect is without your own GDT you can't reliably do interrupts which would severely limit your OS.
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
The build directory is empty, just create it. Also to build it you'll need my toolchain in home directory.missing build directory
https://github.com/nergzd723/i686-elf
You'll also need nasm. Have fixed usr.o location. And then it should build well. Bochsrc.txt in git repo isn't valid, but it just loads os.iso as cdrom.
But actually, at the time I am calling module I have a GDT. It loads gdt table and returns with new segment descriptor 0x10. Maybe GRUB puts the module where the GDT thinks data segment is located. So i need to move it to code segment? Thank you all for help!
-
- Member
- Posts: 797
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: Jumping to GRUB module adress causes rpl !=CPL in bochs
The sequence of code that is looping repeatedly is the while statement here:nergzd723 wrote:Oops, forgot to say that I actually tried inlining that, but it just loops.
According to bochs:Why does it just loop that? call -469 returns execution to beginning of it. But now we are running in 0010: selector according to bochs.Code: Select all
push ebp mov ebp, esp sub esp, 0x0000004 mov eax, dword ptr ss:[ebp+8] mov word ptr ss:[ebp-20], ax mov eax, dword ptr ss:[ebp-20] mov edx, eax in al, dx mov byte ptr ss:[ebp-1], al mov al, byte ptr ss:[ebp-1] leave ret add esp, 0x00000004 movzx eax, al and eax, 0x00000020 leave ret test eax, eax jz .-9 (0x00100540) call .-42 (0x0010051b) push ebp mov ebp, esp push 0x000003fd call .-469(0x00100353)
Code: Select all
void put_serial(char a) {
while (is_transmit_empty() == 0); // Stall while transit is filled
outb(COM1_BASE,a);
}