Accessing GDT when using GRUB
Accessing GDT when using GRUB
Hi.
I am trying to create a user space(I will only use ring 0 and 3), this article says that I should create 2 new entries in GDT and configure them to ring 3.
But I didn't create GDT. I have an IDT with working interrupts and exceptions. As far as I understand, GRUB created GDT instead of me.
How can I manage the GDT that GRUB made? Or do I need to create my own?
I am trying to create a user space(I will only use ring 0 and 3), this article says that I should create 2 new entries in GDT and configure them to ring 3.
But I didn't create GDT. I have an IDT with working interrupts and exceptions. As far as I understand, GRUB created GDT instead of me.
How can I manage the GDT that GRUB made? Or do I need to create my own?
Re: Accessing GDT when using GRUB
I assume we are talking about 32bit mode.
The Grub GDT is not meant to be used as the normal kernel GDT. So you have to setup two or three ring 0 segments (code, data, stack). And similar with ring 3.
This is a good time to thoroughly design the memory layout and the GDT.
Greetings
Peter
The Grub GDT is not meant to be used as the normal kernel GDT. So you have to setup two or three ring 0 segments (code, data, stack). And similar with ring 3.
This is a good time to thoroughly design the memory layout and the GDT.
Greetings
Peter
Re: Accessing GDT when using GRUB
The OP might want to re-read the multiboot specification.
the OS image must not load any segment registers (even just reloading the same values!) until it sets up its own ‘GDT’.
Re: Accessing GDT when using GRUB
Now, in my "loader" code, before passing control to kmain(), I configure my own GDT this way:iansjack wrote:The OP might want to re-read the multiboot specification.the OS image must not load any segment registers (even just reloading the same values!) until it sets up its own ‘GDT’.
Code: Select all
global gdt_desc
start:
cli
mov esp, stack_top
push ebx
push eax
jmp load_gdt
;global descriptor table
gdt:
gdt_null:
dq 0
gdt_code:
dw 0FFFFh
dw 0
db 0
db 10011010b
db 11001111b
db 0
gdt_data:
dw 0FFFFh
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end:
gdt_desc:
dw gdt_end - gdt - 1
dd gdt
load_gdt:
lgdt [gdt_desc] ;load GDT
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.setcs
.setcs:
call kmain
.hltloop:
hlt
jmp .hltloop
Code: Select all
extern char gdt_desc[];
How do I create a new structure for GDT? I can use it to manage GDT, right?
Can I now use the gdt_desc variable to manage gdt?
Re: Accessing GDT when using GRUB
No, you normally don't use the GDT-"descriptor" as you name it. It is used only to tell the CPU where the GDT is.
You use it as you do, by setting CS, DS etc. to 0x08 (CS by a far JMP) and 0x10 (DS etc. and SS). But you need to set ESP (32bit stack pointer), too. But you are doing it right so far.
EDIT: Just add two more entries in the GDT for ring 3.
You use it as you do, by setting CS, DS etc. to 0x08 (CS by a far JMP) and 0x10 (DS etc. and SS). But you need to set ESP (32bit stack pointer), too. But you are doing it right so far.
EDIT: Just add two more entries in the GDT for ring 3.
Last edited by PeterX on Sun Jul 05, 2020 10:26 am, edited 1 time in total.
Re: Accessing GDT when using GRUB
What kind of variable should I use to control the GDT?PeterX wrote:No, you normally don't use the GDT-"descriptor" as you name it. It is used only to tell the CPU where the GDT is..
Address of the "gdt:" tag ?
Re: Accessing GDT when using GRUB
I am not aware of any use case, where you would want to access the GDT later on from C. But maybe I over-simplify things here?mrjbom wrote:What kind of variable should I use to control the GDT?PeterX wrote:No, you normally don't use the GDT-"descriptor" as you name it. It is used only to tell the CPU where the GDT is..
Address of the "gdt:" tag ?
Re: Accessing GDT when using GRUB
The article that talks about the transition to ring 3 talks about the need to create two new entries in GDT.PeterX wrote:I am not aware of any use case, where you would want to access the GDT later on from C. But maybe I over-simplify things here?
I don't know exactly how to create entries in GDT because I don't know where to find the pointer...mrjbom wrote:this article says that I should create 2 new entries in GDT and configure them to ring 3
Code: Select all
//gdt data from bootloader.asm
extern char gdt[];
struct gdt_ptr_struct
{
unsigned short limit;
unsigned int base;
};
struct gdt_ptr_struct* GDT = (struct gdt_ptr_struct*)gdt;
Will this work as I need it? If I can create a new entry in the GDT?
Re: Accessing GDT when using GRUB
Like this:
EDIT: OK, maybe it's better to use LDT? Just a suggestion.
I fear I am wrong here regarding GDT only setting up once.
Code: Select all
;global descriptor table
gdt:
gdt_null:
dq 0
gdt_code:
dw 0FFFFh
dw 0
db 0
db 10011010b
db 11001111b
db 0
gdt_data:
dw 0FFFFh
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_ring3_code:
dw ...
...
gdt_ring3_data:
dw ...
...
gdt_end:
I fear I am wrong here regarding GDT only setting up once.
Re: Accessing GDT when using GRUB
You should set up the GDT in C. It will make life easier. Make it the first thing you setup. The LDT has to do with process memory management and could not replace the GDT.
Re: Accessing GDT when using GRUB
I'm trying to configure GDT in C.nexos wrote:You should set up the GDT in C. It will make life easier. Make it the first thing you setup. The LDT has to do with process memory management and could not replace the GDT.
That is, I load GDT in bootloader.asm and then I want to be able to manage GDT from C code.
Here I have a pointer to GDT(I hope this is it), can I create new entries there? Or did I make a mistake somewhere?
Code: Select all
//gdt data from bootloader.asm
extern char gdt[];
struct gdt_ptr_struct
{
unsigned short limit;
unsigned int base;
};
struct gdt_ptr_struct* GDT = (struct gdt_ptr_struct*)gdt;
Re: Accessing GDT when using GRUB
My GDT knowledge comes from enabling pmode in a bootloader. So I am not aware of all aspects of pmode kernels. Sorry if I gace wrong advice.
I thought (and I maybe wrong) that you setup the GDT only once and that is easier in Asm than in C.
If you really need to access GDT in C, don't you the struct you mentioed, but use an ordinary pointer to the beginning of the GDT.
Greetings
Peter.
I thought (and I maybe wrong) that you setup the GDT only once and that is easier in Asm than in C.
If you really need to access GDT in C, don't you the struct you mentioed, but use an ordinary pointer to the beginning of the GDT.
Greetings
Peter.
Re: Accessing GDT when using GRUB
Do you suggest using regular gdt for core tasks, and gdt_ring3 for userspace tasks?PeterX wrote:Like this:
Code: Select all
;global descriptor table gdt: gdt_null: dq 0 gdt_code: dw 0FFFFh dw 0 db 0 db 10011010b db 11001111b db 0 gdt_data: dw 0FFFFh dw 0 db 0 db 10010010b db 11001111b db 0 gdt_ring3_code: dw ... ... gdt_ring3_data: dw ... ... gdt_end:
I would be able to load gdt_ring3 while switching to a userspace task, and load gdt for the kernel when switching back to the core.
Is this a viable approach?
In this case, can I use gdt for core tasks and ldt for userspace tasks?PeterX wrote:EDIT: OK, maybe it's better to use LDT? Just a suggestion.
Re: Accessing GDT when using GRUB
I install GDT once only in asm code.PeterX wrote: I thought (and I maybe wrong) that you setup the GDT only once and that is easier in Asm than in C.
How do I find this pointer? Is it "gdt:" (asm code) or something else?PeterX wrote: If you really need to access GDT in C, don't you the struct you mentioed, but use an ordinary pointer to the beginning of the GDT.
Re: Accessing GDT when using GRUB
Yes, type something like:mrjbom wrote:How do I find this pointer? Is it "gdt:" (asm code) or something else?PeterX wrote: If you really need to access GDT in C, don't you the struct you mentioed, but use an ordinary pointer to the beginning of the GDT.
Code: Select all
global gdt
gdt: