[Solved]Can't update CS after load gdt

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
OhShift
Posts: 7
Joined: Wed Aug 20, 2014 6:35 am

[Solved]Can't update CS after load gdt

Post by OhShift »

Hello guys, I am trying to change gdt from old one which provided by uefi to my own gdt.
After load my gdt, I need to update register cs, but when I put code segment in it, the CPU reset!
I feel confused, hope someone can take me out of this reset loop. :(

Here is my code:

Code: Select all

[bits 64] ;uefi should bring us to long mode
entry:
   cli ;disable interrupt
    lgdt [GDT_R] ;load gdt
    mov rsp, STACK_BOTTOM
    mov rax, 8
    push rax ;push code seg
    push new ;push where we want to go
    retf ;far return
    new:
    mov ax, 16 ;update data seg
    mov es, ax
    mov ss, ax
    mov ds, ax
    mov fs, ax
    mov gs, ax
    call main ;call c code
    jmp HALT
And here is the GDT:

Code: Select all

GDT_R:
	dw (GDT_END - GDT)
	dq GDT
	
GDT:
NULL:
	dw 0x0
	dw 0x0
	db 0x0
	db 0x0
	db 0x0
	db 0x0
CODE:
	dw 0xffff
	dw 0x0
	db 0x0
	db 0x9a
	db 0xaf
	db 0x0
DATA:
	dw 0xffff
	dw 0x0
	db 0x0
	db 0x92
	db 0xcf
	db 0x0
GDT_END:
==== 4-9-2016 ====
I fix it with:

Code: Select all

    cli ;disable interrupt

	lgdt [GDT_R]

	mov eax, 0x10
	push rax
	mov rax, STACK_BOTTOM
	push rax
	push 0x202
	mov eax, 0x8
	push rax
	mov rax, InNewGDT
	push rax
	iretq
InNewGDT:
	mov ax, 0x10
	mov es, ax
	mov ss, ax
	mov ds, ax
	mov fs, ax
	mov gs, ax

	lea rax, [rel main]
	call rax
    jmp HALT

GDT_R:
	dw GDT_END - GDT - 1
	dq GDT
GDT:
NULL: equ $ - GDT
	dq 0x0
CODE: equ $ - GDT
	dw 0xffff
	dw 0x0
	db 0x0
	db 0x9a
	db 0xaf
	db 0x0
DATA: equ $ - GDT
	dw 0xffff
	dw 0x0
	db 0x0
	db 0x92
	db 0xcf
	db 0x0
GDT_END:
retf cant work well, so instead i use iretq and everything works well!

sorry for my poor English.
Last edited by OhShift on Sat Sep 03, 2016 9:19 pm, edited 1 time in total.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Can't update CS after load gdt

Post by Octacone »

OhShift wrote:

Code: Select all

[bits 64] ;uefi should bring us to long mode
That is not how long mode works. You cannot enter long mode by doing "BITS 64", you need to set it up.
Take a look at: http://wiki.osdev.org/Setting_Up_Long_Mode You need to set up your GDT for 64 Bit arch.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: Can't update CS after load gdt

Post by SpyderTL »

[bits 64] only tells the compiler that it should generate 64-bit long mode byte codes. It doesn't tell the CPU (or UEFI) that it should be in long mode.

When UEFI calls your code, you are probably going to be in 32-bit protected mode. So you should use [Bits 32] until you switch to 64-bit mode yourself.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: Can't update CS after load gdt

Post by Octocontrabass »

Are you trying to do this before exiting boot services?

Does the PE header correctly identify your binary as 64-bit? UEFI will load 64-bit binaries in long mode, no matter what the previous posts say. :wink:

Does the assembler you're using assemble "push new" as "push qword new" and not "push dword new"?

Have you tried debugging your code using QEMU? (Bochs doesn't seem to have any UEFI firmware available.)
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can't update CS after load gdt

Post by iansjack »

Octocontrabass wrote:UEFI will load 64-bit binaries in long mode, no matter what the previous posts say. :wink:
That may be so, but the new GDT has to have 64-bit descriptors, unlike those that the OP is trying to use.
OhShift
Posts: 7
Joined: Wed Aug 20, 2014 6:35 am

Re: Can't update CS after load gdt

Post by OhShift »

octacone wrote:
OhShift wrote:

Code: Select all

[bits 64] ;uefi should bring us to long mode
That is not how long mode works. You cannot enter long mode by doing "BITS 64", you need to set it up.
Take a look at: http://wiki.osdev.org/Setting_Up_Long_Mode You need to set up your GDT for 64 Bit arch.
I compiled a 64bit efi file and when the uefi bios support 64bit mode, my bootloader works!
But when i boot it in 32bit bios, it give me error message. So I think i probably is in Long Mode.

btw, thanks for the comment :D
OhShift
Posts: 7
Joined: Wed Aug 20, 2014 6:35 am

Re: Can't update CS after load gdt

Post by OhShift »

Octocontrabass wrote:Are you trying to do this before exiting boot services?
No, i don't. In fact,

Code: Select all

entry
is called by my bootloader, and it is after ExitBootService() and SetVirtualAddress().
Octocontrabass wrote:Does the PE header correctly identify your binary as 64-bit? UEFI will load 64-bit binaries in long mode, no matter what the previous posts say. :wink:
I think so.. My compiler option is set to X64. It should give me an X64 output.
Octocontrabass wrote:Does the assembler you're using assemble "push new" as "push qword new" and not "push dword new"?
But address in Long Mode are 64bit right? I disassembled the binary file, and its show "push qword new".
Octocontrabass wrote:Have you tried debugging your code using QEMU? (Bochs doesn't seem to have any UEFI firmware available.)
Yes, I have been tried. and here is the debug log:

Code: Select all

Triple fault
CPU Reset (CPU 0)
RAX=00000000bff20e18 RBX=00000000bff21f18 RCX=0000000000000000 RDX=00000000bff21f88
RSI=00000000be780698 RDI=00000000bff21f70 RBP=00000000bff94b20 RSP=00000000bff94ab8
R8 =00000000bff94a4c R9 =00000000bff18518 R10=00000000bed02ec8 R11=0000000000000040
R12=0000000000000000 R13=0000000000100000 R14=0000000000090002 R15=0000000000000000
RIP=0000000000100010 RFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0008 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0028 0000000000000000 ffffffff 00af9b00 DPL=0 CS64 [-RA]
SS =0008 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0008 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0008 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0008 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT=     0000000000100034 00000018
IDT=     00000000bfc07018 00000fff
CR0=80000033 CR2=0000000000000000 CR3=00000000bff33000 CR4=00000668
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000017 CCD=0000000000000000 CCO=SUBQ    
EFER=0000000000000500
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
XMM08=00000000000000000000000000000000 XMM09=00000000000000000000000000000000
XMM10=00000000000000000000000000000000 XMM11=00000000000000000000000000000000
XMM12=00000000000000000000000000000000 XMM13=00000000000000000000000000000000
XMM14=00000000000000000000000000000000 XMM15=00000000000000000000000000000000
Thanks for the comment :D
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can't update CS after load gdt

Post by iansjack »

How much RAM are you allocating to the QEMU virtual machine?
OhShift
Posts: 7
Joined: Wed Aug 20, 2014 6:35 am

Re: Can't update CS after load gdt

Post by OhShift »

iansjack wrote:How much RAM are you allocating to the QEMU virtual machine?
4GB
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Can't update CS after load gdt

Post by Brendan »

Hi,
OhShift wrote:

Code: Select all

    push rax ;push code seg
    push new ;push where we want to go
    retf ;far return
For UEFI, the executable is position independent (could be loaded at any virtual address). For this reason it's impossible for "push new" to work properly because it's impossible for the assembler or linker to guess the address it might be loaded; and you'd have to do something like (e.g. NASM syntax) "lea rax,[rel new]" (to get an RIP relative address into RAX) and "push rax".


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.
OhShift
Posts: 7
Joined: Wed Aug 20, 2014 6:35 am

Re: Can't update CS after load gdt

Post by OhShift »

Brendan wrote:Hi,
OhShift wrote:

Code: Select all

    push rax ;push code seg
    push new ;push where we want to go
    retf ;far return
For UEFI, the executable is position independent (could be loaded at any virtual address). For this reason it's impossible for "push new" to work properly because it's impossible for the assembler or linker to guess the address it might be loaded; and you'd have to do something like (e.g. NASM syntax) "lea rax,[rel new]" (to get an RIP relative address into RAX) and "push rax".


Cheers,

Brendan
Thanks for the comment! After i change "push new" to "lea rax, [rel new]" and "push rax", i still got a Triple fault when execute "retf". what should i do?
Should i reset uefi paging before reset GDT?
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Can't update CS after load gdt

Post by Brendan »

Hi,
OhShift wrote:
Brendan wrote:
OhShift wrote:

Code: Select all

    push rax ;push code seg
    push new ;push where we want to go
    retf ;far return
For UEFI, the executable is position independent (could be loaded at any virtual address). For this reason it's impossible for "push new" to work properly because it's impossible for the assembler or linker to guess the address it might be loaded; and you'd have to do something like (e.g. NASM syntax) "lea rax,[rel new]" (to get an RIP relative address into RAX) and "push rax".
Thanks for the comment! After i change "push new" to "lea rax, [rel new]" and "push rax", i still got a Triple fault when execute "retf". what should i do?
Should i reset uefi paging before reset GDT?
I'd assume you have the same problem everywhere else too.

For example; for the first 6 instructions of the code you posted:
  • your "lgdt [GDT_R]" loads the GDTR from an address that's impossible to know at compile time
  • the GDTR pointer itself (at "GDT_R:") contains an "address of GDT" that's impossible to know at compile time
  • you load RSP with an address that's impossible to know at compile time
  • then you do the "push new" (already mentioned)
It's essentially the same problem repeated 4 times in 6 instructions.


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.
OhShift
Posts: 7
Joined: Wed Aug 20, 2014 6:35 am

Re: Can't update CS after load gdt

Post by OhShift »

Brendan wrote:Hi,
I'd assume you have the same problem everywhere else too.

For example; for the first 6 instructions of the code you posted:
  • your "lgdt [GDT_R]" loads the GDTR from an address that's impossible to know at compile time
  • the GDTR pointer itself (at "GDT_R:") contains an "address of GDT" that's impossible to know at compile time
  • you load RSP with an address that's impossible to know at compile time
  • then you do the "push new" (already mentioned)
It's essentially the same problem repeated 4 times in 6 instructions.


Cheers,

Brendan
How can i calculate the address of GDT in GDT_R?
Post Reply