GRUB and protected mode

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.
Travfar

GRUB and protected mode

Post by Travfar »

Hi!

I am using GRUB to set up my kernel, which I wrote in C. I am currently using GRUB to boot it and I wanted to know if GRUB stes up the GDT. I also wanted to know if I could change the address of the GDT in the middle of my kernel.

Travfar
pini

Re:GRUB and protected mode

Post by pini »

When your kernel is executed, GRUB has already set up protected mode (and thus the GDT) , but it is highly recommended to load your own GDT. See the multiboot specification for more details on the machine state GRUB sets.

I guess you can change the address of the GDT anywhere in your kernel, but make sure to reload all the selectors to modified descriptors.
srg

Re:GRUB and protected mode

Post by srg »

AFAIK the GDT that GRUB sets up is only really for it's own uses and as far as the kernel is concerned it's "undefined". So it's best to make your own.

srg
travfar

Re:GRUB and protected mode

Post by travfar »

Hi! Another question.

I have written and borrowed some functions to load the new GDT. However, when I load the new selectors into the segment registers, the computer just reboots right when I boot my kernel.

here is the code:
gdt.c:

Code: Select all

#include "kernel.h"

//this is a GDT entry
struct gdt_entry
{
   unsigned short limit_low;
   unsigned short base_low;
   unsigned short base_middle;
   unsigned short access;
   unsigned short granularity;
   unsigned short base_high;
} __attribute__((packed));

// This is the GDT pointer
struct gdt_ptr
{
   unsigned short limit;
   unsigned int base;
} __attribute__((packed));

//define the GDT
struct gdt_entry gdt[3];
struct gdt_ptr gp;

extern void gdt_flush();

void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran)
{
   gdt[num].base_low=(base & 0xFFFF);
   gdt[num].base_middle=(base >> 16) & 0xFF;
   gdt[num].base_high=(base >> 24) & 0xFF;

   //descriptor limits
   gdt[num].limit_low=(limit & 0xFFFF);
   gdt[num].granularity = ((limit >>16) & 0x0f);

   //limits
   gdt[num].granularity |= (gran & 0xF0);
   gdt[num].access = access;
};

void gdt_install()
{
   const char* message="Loading new GDT. Well Flush isnt really there yet ;)\0";
   k_printf(message,1,WHITE_TXT);

   gp.limit=(sizeof(struct gdt_ptr) *3)-1;
   gp.base=(unsigned int)&gdt;

   gdt_set_gate(0,0,0,0,0);
   gdt_set_gate(1,0,0xffffffff,0x9a,0xcf);
   gdt_flush();
};

void gdt_flush_alert()
{
   const char* message="Flushing GDT now!";
   k_printf(message,2,WHITE_TXT);
};

asmfunc.asm:

Code: Select all

[BITS 32]
[global gdt_flush]
[extern gp]
[extern gdt_flush_alert]
gdt_flush:
   call gdt_flush_alert
   lgdt [gp]
   mov ax,0x10
   mov ds,ax
   mov es,ax
   mov fs,ax
   mov gs,ax
   jmp 0x08:flush2
flush2:
   ret
IF i do not load the segment registers, then it does not just reboot. kernel.h defines k_printf and WHITE_TXT

P.S. the functions I borrowed were in the public domain.
travfar

Re:GRUB and protected mode

Post by travfar »

SOrry!

gdt.c should be:

Code: Select all

#include "kernel.h"

//this is a GDT entry
struct gdt_entry
{
   unsigned short limit_low;
   unsigned short base_low;
   unsigned short base_middle;
   unsigned short access;
   unsigned short granularity;
   unsigned short base_high;
} __attribute__((packed));

// This is the GDT pointer
struct gdt_ptr
{
   unsigned short limit;
   unsigned int base;
} __attribute__((packed));

//define the GDT
struct gdt_entry gdt[3];
struct gdt_ptr gp;

extern void gdt_flush();

void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran)
{
   gdt[num].base_low=(base & 0xFFFF);
   gdt[num].base_middle=(base >> 16) & 0xFF;
   gdt[num].base_high=(base >> 24) & 0xFF;

   //descriptor limits
   gdt[num].limit_low=(limit & 0xFFFF);
   gdt[num].granularity = ((limit >>16) & 0x0f);

   //limits
   gdt[num].granularity |= (gran & 0xF0);
   gdt[num].access = access;
};

void gdt_install()
{
   const char* message="Loading new GDT. Well Flush isnt really there yet ;)\0";
   k_printf(message,1,WHITE_TXT);

   gp.limit=(sizeof(struct gdt_ptr) *3)-1;
   gp.base=(unsigned int)&gdt;

   gdt_set_gate(0,0,0,0,0);
   gdt_set_gate(1,0,0xffffffff,0x9a,0xcf);
   gdt_set_gate(2,0,0xffffffff,0x92,0xcf);
   gdt_flush();
};

void gdt_flush_alert()
{
   const char* message="Flushing GDT now!";
   k_printf(message,2,WHITE_TXT);
};
Warrior

Re:GRUB and protected mode

Post by Warrior »

From personal experience I suggest you learn how the GDT works and the vast ways it can be implemented to suit your individual design's needs.

I had the problem of using "cut n paste" code before and trust be it was bad..there are a lot of articles on how the GDT works and it's implementation floating around. I think the one I found was on osdcom.info in one of the protected mode tutorials.

Good luck.
travfar

Re:GRUB and protected mode

Post by travfar »

You know, I did not just copy from a tutorial and put it in my code. An anyway, I found out what was wrong.
first of all there should only be two unsigned shorts in the struct gdt_entry, the rest should be unsigned char's.

it should be:

Code: Select all

struct gdt_entry
{
  unsigned short limit_low;
  unsigned short base_low;
  unsigned char base_middle;
  unsigned char access;
  unsigned char granularity;
  unsigned char base_high;
} __attribute__((packed));
this is because the size of a GDT entry should only be 8 bytes.

Second of all, I *accidentally* set the limit attribute of the struct gdt_ptr to 3 times the size of the struct gdt_ptr not the struct gdt_entry.

It should be changed to:

Code: Select all

  gp.limit=(sizeof(struct gdt_entry) *3)-1;
  gp.base=(unsigned int)&gdt;
Warrior

Re:GRUB and protected mode

Post by Warrior »

I know, it was more me giving helpful advice. Good Luck.
AR

Re:GRUB and protected mode

Post by AR »

I suggest also using __attribute__((__packed__)) because people apparently have unreliable results with __attribute__((packed))
travfar

Re:GRUB and protected mode

Post by travfar »

I already have it working but what is the difference?
AR

Re:GRUB and protected mode

Post by AR »

Like I said, some people seem to get unreliable results with __attribute__((packed)). It may work or it may not, or it may work sometimes but not always but I've never had problems with __packed__.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:GRUB and protected mode

Post by Pype.Clicker »

surprisingly enough, i see no such thing like "__packed__" in my copy of gcc information (that should be for 3.3). If you're experiencing troubles with packed structures, you might want to compile with -Wpacked -Wpadded ...

Note also that you're supposed to pack fields that require it, not the whole structure (or the effect is simply to have the whole structure with poor alignment when used in something else)
// from "info gcc, variable attributes"
struct foo
{
char a;
int x[2] __attribute__ ((packed));
};
AR

Re:GRUB and protected mode

Post by AR »

Well it works, I have heaps of code that uses it. I avoid packing unless it is absolutely neccessary (stuff like BIOS structs which rarely contain any 32bit variables and are entirely unaligned even if they do). I don't see why you would pack a struct that is only used internally, alignment is good unless you are desperate for memory that is unless you are disassembling a larger variable into smaller parts using a union or something along those lines but then you could pack the whole struct anyway.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:GRUB and protected mode

Post by Pype.Clicker »

okay, googling further reveals that:
- "__name__" is equivalent to "name" for any attribute. It's just meant to avoid macro expansion (in case someone "#define packed" and want to __attribute__((packed)) aswell )
- using "packed" on a union/struct is equivalent to use it on every of its members
- the later rule cannot be applied on typedef's (which may be why people sometimes experiment troubles)

So if __attribute__((packed)) do not work and __attribute__((__packed__)) does, i suggest you use gcc -E and look at what the pre-processor made of your "packed" to find out what's wrong.
mar-rih

Re:GRUB and protected mode

Post by mar-rih »

Pype.Clicker wrote: surprisingly enough, i see no such thing like "__packed__" in my copy of gcc information (that should be for 3.3). If you're experiencing troubles with packed structures, you might want to compile with -Wpacked -Wpadded ...

Note also that you're supposed to pack fields that require it, not the whole structure (or the effect is simply to have the whole structure with poor alignment when used in something else)
// from "info gcc, variable attributes"
struct foo
{
char a;
int x[2] __attribute__ ((packed));
};
could you explain this statement __attribute__, why we are using it befor or after definig variables and what is benifit of.
Post Reply