Page 1 of 2

Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 8:09 am
by mrjbom
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?

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 8:21 am
by PeterX
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

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 8:46 am
by iansjack
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

Posted: Sun Jul 05, 2020 9:58 am
by mrjbom
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’.
Now, in my "loader" code, before passing control to kmain(), I configure my own GDT this way:

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
In C code I declared gdt address:

Code: Select all

extern char gdt_desc[];
Is that right?
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

Posted: Sun Jul 05, 2020 10:19 am
by PeterX
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.

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 10:26 am
by mrjbom
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..
What kind of variable should I use to control the GDT?

Address of the "gdt:" tag ?

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 10:28 am
by PeterX
mrjbom wrote:
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..
What kind of variable should I use to control the GDT?

Address of the "gdt:" tag ?
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?

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 10:54 am
by mrjbom
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?
The article that talks about the transition to ring 3 talks about the need to create two new entries in GDT.
mrjbom wrote:this article says that I should create 2 new entries in GDT and configure them to ring 3
I don't know exactly how to create entries in GDT because I don't know where to find the pointer...

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;
I want to try this:

Will this work as I need it? If I can create a new entry in the GDT?

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 10:57 am
by PeterX
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:
EDIT: OK, maybe it's better to use LDT? Just a suggestion.

I fear I am wrong here regarding GDT only setting up once.

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 11:14 am
by nexos
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

Posted: Sun Jul 05, 2020 11:18 am
by mrjbom
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.
I'm trying to configure GDT in C.
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

Posted: Sun Jul 05, 2020 11:22 am
by PeterX
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.

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 11:24 am
by mrjbom
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:
Do you suggest using regular gdt for core tasks, and gdt_ring3 for userspace tasks?
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?
PeterX wrote:EDIT: OK, maybe it's better to use LDT? Just a suggestion.
In this case, can I use gdt for core tasks and ldt for userspace tasks?

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 11:27 am
by mrjbom
PeterX wrote: I thought (and I maybe wrong) that you setup the GDT only once and that is easier in Asm than in C.
I install GDT once only in asm code.
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.
How do I find this pointer? Is it "gdt:" (asm code) or something else?

Re: Accessing GDT when using GRUB

Posted: Sun Jul 05, 2020 11:32 am
by PeterX
mrjbom wrote:
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.
How do I find this pointer? Is it "gdt:" (asm code) or something else?
Yes, type something like:

Code: Select all

global gdt
gdt: