OSDev.org https://forum.osdev.org/ |
|
UEFI loader, jump to protected mode environment? https://forum.osdev.org/viewtopic.php?f=1&t=31408 |
Page 1 of 1 |
Author: | vollkorn [ Thu Mar 09, 2017 9:04 am ] |
Post subject: | UEFI loader, jump to protected mode environment? |
Hi there, I'm currently writing an UEFI OS loader. My goal is to load a 32-bit multiboot compliant kernel. Loading the kernel to memory and relocating it to its final destination is not a big deal using UEFI boot-services. However, jumping to the kernels start address (after exiting boot services) failes on qemu (TianoCore Firmware-Image) with a "general protection fault". My entry address is "0x01302298". The code just before jumping to the start address looks like this: Code: Dump of assembler code for function call_kernel: 0x000000001ead3b31 <+0>: push %rbp 0x000000001ead3b32 <+1>: mov %rsp,%rbp 0x000000001ead3b35 <+4>: sub $0x8,%rsp 0x000000001ead3b39 <+8>: mov %rdi,-0x8(%rbp) => 0x000000001ead3b3d <+12>: mov -0x8(%rbp),%rax 0x000000001ead3b41 <+16>: jmpq *%rax with RAX=0000000001302298 The next instruction (which is expect) would be: Code: a3 bc 7b 31 01 mov %eax,0x1317bbc Instead gdb tells me, that the next instruction at this address is Quote: => 0x1302298: movabs %eax,0x8ed88c6601317bbc I've some theories (but no clue) what happens: - The firmware puts the cpu into x86_64-"long mode", this leads to miss-interpretation of the next instruction (which is a 32-bit instruction) - The last jump instruction itself is wrong: -somehow- a 32-bit jump instruction has to be used. Can someone give me a hint? Best regards |
Author: | kzinti [ Thu Mar 09, 2017 9:56 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
You firmware is running in long mode (64-bit). If you want to run a 32-bit kernel, you will have to disable it and go to 32-bit protected mode before jumping to your kernel. |
Author: | Brendan [ Thu Mar 09, 2017 9:59 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
Hi, vollkorn wrote: - The firmware puts the cpu into x86_64-"long mode", this leads to miss-interpretation of the next instruction (which is a 32-bit instruction) Yes. To fix this you have to switch to a 16-bit or 32-bit code segment (in long mode), make sure your code is in an identity mapped page (for UEFI it should be anyway), then disable long mode and paging. Note that most multiboot stuff assumes that there's usable RAM at physical address 0x00100000, and UEFI makes no guarantee about the physical address space layout (and doesn't guarantee that there's usable RAM at physical address 0x00100000, even though it's "relatively likely"). This is unsolvable; which means that there's a (relatively tiny) chance that your code can't work. Cheers, Brendan |
Author: | vollkorn [ Fri Mar 10, 2017 6:56 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
Brendan wrote: To fix this you have to switch to a 16-bit or 32-bit code segment (in long mode) Okay I did this, and it seems that qemu switches to 32-bit mode (e.g. register is now eax instead of rax). I modified an already present gdt entry by resetting the "L" bit in the "flags" part of the entry and then reloaded the %cs register with appropriate gdt index. BUT it seems to reset all other registers, including the instruction pointer. Why? Quote: store_gdt_desc(&gdt_desc);
struct gdt_t* gdt = (struct gdt_t*) gdt_desc.base; gdt[7].flags = 0x8; /* Reset 'L' bit in x86-64 descriptor */ asm volatile ("mov $0x38, %%ax\n\t" "mov %%ax, %%cs" "" : /* no output */ : /* no input */ : /* no clobber */ ); |
Author: | Octocontrabass [ Fri Mar 10, 2017 6:59 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
vollkorn wrote: Code: "mov %%ax, %%cs" That is not a valid instruction. How did you compile this without errors? |
Author: | vollkorn [ Fri Mar 10, 2017 7:37 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
I just double checked: it compiles, but qemu resets all register. Maybe a hard reset due to an illegal instruction / a bug? I'm using gcc 4.6.4 on ubuntu. How to load cs using inline assembly instead? Google does not want to give me a hint. |
Author: | Octocontrabass [ Fri Mar 10, 2017 8:15 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
There are a few ways to load CS in inline assembly, but you can't use any of them to switch from 64-bit mode to 32-bit mode in inline assembly because your compiler can't switch from 64-bit to 32-bit in the middle of a function. You can reload CS using a far return ("retf") instruction. |
Author: | vollkorn [ Fri Mar 10, 2017 10:22 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
Okay, I tried it in a different way. But this does not work either... Quote: make_lm_pm_transition:
.code64 push %rbp mov %rsp,%rbp push $0x7 lea (%rip), %rax <-- how can i know the offset to label ".inprotectedmode"? add $0x8, %rax push %rax lret .inProtectedMode: .code32 nop ... nop |
Author: | kzinti [ Fri Mar 10, 2017 10:32 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
Code: ... push $0x08 ; GDT selector push $target ; jump target retf target: ... or Code: ...
ljmpl $0x08, $target target: ... |
Author: | Octocontrabass [ Fri Mar 10, 2017 12:34 pm ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
Far jumps are not valid in 64-bit mode. Only a far return will work. |
Author: | Gigasoft [ Sat Mar 11, 2017 4:01 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
What you mean is: Code: push $0x8 lea .inProtectedMode(%rip), %rax push %rax lretq Push $.inProtectedMode might work, but only when the address is less than 0x80000000. Or, you could simply set the machine type to 0x14c (EFI_IMAGE_MACHINE_IA32) in the PE image. |
Author: | vollkorn [ Mon Mar 13, 2017 2:28 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
Gigasoft wrote: What you mean is: Code: push $0x8 lea .inProtectedMode(%rip), %rax push %rax lretq Push $.inProtectedMode might work, but only when the address is less than 0x80000000. Or, you could simply set the machine type to 0x14c (EFI_IMAGE_MACHINE_IA32) in the PE image. This did the trick for me, at least for the jumping part. But still, qemu resets all register (see below). Did I miss something? Quote: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000663
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000 EIP=0000fff1 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES =0000 00000000 0000ffff 00009300 CS =f000 ffff0000 0000ffff 00009b00 SS =0000 00000000 0000ffff 00009300 DS =0000 00000000 0000ffff 00009300 FS =0000 00000000 0000ffff 00009300 GS =0000 00000000 0000ffff 00009300 LDT=0000 00000000 0000ffff 00008200 TR =0000 00000000 0000ffff 00008b00 GDT= 00000000 0000ffff IDT= 00000000 0000ffff CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000 DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 DR6=00000000ffff0ff0 DR7=0000000000000400 EFER=0000000000000000 FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80 => 0x1ead3dcf <make_lm_pm_transition+6>: lea 0x2(%rip),%rax # 0x1ead3dd8 <make_lm_pm_transition+15> (gdb) nexti 14 push %rax 1: x/i $pc => 0x1ead3dd6 <make_lm_pm_transition+13>: push %rax (gdb) nexti 15 lret 1: x/i $pc => 0x1ead3dd7 <make_lm_pm_transition+14>: lret (gdb) nexti 0x0000000000000000 in ?? () 1: x/i $pc |
Author: | vollkorn [ Mon Mar 13, 2017 5:50 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
Haha, I'm making some progress...the trick was - like you said - use lretq instread of lret. Also: gdb must be set to a different target architecture. Otherwise instructions get misinterpreted. Gigasoft wrote: What you mean is: Code: push $0x8 lea .inProtectedMode(%rip), %rax push %rax lretq Push $.inProtectedMode might work, but only when the address is less than 0x80000000. Or, you could simply set the machine type to 0x14c (EFI_IMAGE_MACHINE_IA32) in the PE image. Thanks for your help btw |
Author: | Gigasoft [ Mon Mar 13, 2017 1:00 pm ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
Well, but what is the machine type in the PE image set to? I have no experience with UEFI, but I thought that if you set it to 0x14c rather than 0x200, it should start in 32 bit mode automatically. |
Author: | vollkorn [ Tue Mar 14, 2017 7:27 am ] |
Post subject: | Re: UEFI loader, jump to protected mode environment? |
Gigasoft wrote: Well, but what is the machine type in the PE image set to? I have no experience with UEFI, but I thought that if you set it to 0x14c rather than 0x200, it should start in 32 bit mode automatically. The machine type should be x86_64. I followed the the instructions listed here http://wiki.osdev.org/UEFI#Developing_with_GNU-EFI to setup my toolchain. How can I read the machine type from my efi application? Maybe the "jump to protected mode" thing wouldn't be necessary, if the efi-application could be 32-bit from the beginning. However, learning something new is always good |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |