OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 7:23 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 23 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Setting up GDT in C ?
PostPosted: Sat Nov 25, 2017 8:32 am 
Offline
Member
Member

Joined: Sat Mar 26, 2016 1:25 pm
Posts: 36
Hi,
When trying to setup a new GDT using C code following Bran's tuto
http://www.osdever.net/tutorials/view/b ... t-tutorial
I get a triple fault.
here is the code:
Code:
#define GDTBASE    0x800      
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));

struct gdt_ptr
{
    unsigned short limit;
    unsigned int base;
} __attribute__((packed));

struct gdt_entry gdt[3];
struct gdt_ptr gdtp;

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;
    gdt[num].limit_low = (limit & 0xFFFF);
    gdt[num].granularity = ((limit >> 16) & 0x0F);
    gdt[num].granularity |= (gran & 0xF0);
    gdt[num].access = access;
}

void gdt_install()
{
    gdtp.limit = (sizeof(struct gdt_entry) * 3) - 1;
    gdtp.base = GDTBASE ;
    gdt_set_gate(0, 0, 0, 0, 0);
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
    memcpy((char *)gdtp.base, (char *)gdt, gdtp.limit);
    load_gdtr();
}

Code:
global _load_gdtr     
extern _gdtp           
_load_gdtr:
    lgdt [_gdtp]       
    mov ax, 0x10     
    mov ds, ax       
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:next     
next:
    ret               

and Bochs logout:
Code:
00014963370i[BIOS  ] Booting from 0000:7c00
00015845034i[FLOPPY] partial read() on floppy image returns 180/512
00015933925i[FLOPPY] read() on floppy image returns 0
.....................................................
00017711733i[FLOPPY] read() on floppy image returns 0
00017826504e[CPU0  ] load_seg_reg(SS): not writable data segment
00017826504e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00017826504e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00017826504i[CPU0  ] CPU is in protected mode (active)
00017826504i[CPU0  ] CS.mode = 32 bit
00017826504i[CPU0  ] SS.mode = 32 bit
00017826504i[CPU0  ] EFER   = 0x00000000
00017826504i[CPU0  ] | EAX=00000010  EBX=00007d04  ECX=00000016  EDX=00000816
00017826504i[CPU0  ] | ESP=0008ffa4  EBP=0008ffd0  ESI=000e0000  EDI=0000ffac
00017826504i[CPU0  ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00017826504i[CPU0  ] | SEG sltr(index|ti|rpl)     base    limit G D
00017826504i[CPU0  ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00017826504i[CPU0  ] |  DS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00017826504i[CPU0  ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00017826504i[CPU0  ] |  ES:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00017826504i[CPU0  ] |  FS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00017826504i[CPU0  ] |  GS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00017826504i[CPU0  ] | EIP=0000101d (0000101d)
00017826504i[CPU0  ] | CR0=0x60000011 CR2=0x00000000
00017826504i[CPU0  ] | CR3=0x00000000 CR4=0x00000000
00017826504i[CPU0  ] 0x000000000000101d>> mov ss, ax : 8ED0
00017826504p[CPU0  ] >>PANIC<< exception(): 3rd (13) exception with no resolution

It seems that the fault occures when doing the far jump: jmp 0x08:next
I've spent many hours trying to fix it, alas with no success.
Edit:
Unlike Bran, I'm not loading the kernel with GRUB, I'm using Blundell's bootsector.
Many thanks for your help


Last edited by osdevnewbie on Sat Nov 25, 2017 11:05 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sat Nov 25, 2017 9:24 am 
Offline
Member
Member
User avatar

Joined: Fri Oct 03, 2008 4:13 am
Posts: 153
Location: Ogre, Latvia, EU
Quote:
GDTBASE

What is that?

_________________
If something looks overcomplicated, most likely it is.


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sat Nov 25, 2017 10:59 am 
Offline
Member
Member

Joined: Sat Mar 26, 2016 1:25 pm
Posts: 36
Velko wrote:
Quote:
GDTBASE

What is that?


I want to put the IDT at adress 0X00 and the GDT just after at 0x800.
Even without moving the GDT to 0x800 I get the triple fault any way.


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sat Nov 25, 2017 11:21 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
You are going to have to show all your code, including the bootsector you are using and the commands you use to build the kernel. Placing your project into github or similar service would be beneficial.


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sat Nov 25, 2017 12:33 pm 
Offline
Member
Member

Joined: Mon Jan 03, 2011 6:58 pm
Posts: 283
Code:
00017826504e[CPU0  ] load_seg_reg(SS): not writable data segment
00017826504e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00017826504e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)


hmm......

- Amy


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sat Nov 25, 2017 12:55 pm 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
You appear to be copying one less byte of the GDT than you need to. This could leave you with an invalid data (and stack) selector.

You don't show your memcpy function, but presumably you are sure it works correctly. Single-step the code and check the values in your GDT after moving it.


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sat Nov 25, 2017 3:15 pm 
Offline
Member
Member

Joined: Sat Mar 26, 2016 1:25 pm
Posts: 36
iansjack wrote:
You don't show your memcpy function, but presumably you are sure it works correctly.

Thanks all for your help.
here's the dump of memory at 0x800 after memcpy():

0x00000800 --> 0x00000000
0x00000804 --> 0x00000000
0x00000808 --> 0x0000FFFF
0x0000080C --> 0x00CF9A00
0x00000810 --> 0x0000FFFF
0x00000814 --> 0x00CF9200


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sat Nov 25, 2017 4:57 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
I took the Blundell boot_sect.asm built it up, put it in a disk image a the first sector. used the link.ld that is in the Bran tutorial and changed the origin point to 0x1000 instead of 0x100000. Created a C file with your code + a copy of memcpy from Bran's tutorial. Added an entry point in an assembler that calls a main C function. I created such a function that simply calls gdt_install and then goes into an infinite loop. I linked it altogether listing the object file with the entry point first to an ELF executable. Converted it to a binary kernel file. Placed the kernel file on the subsequent sectors and it ran as expected and the GDT loaded. I agree with iansjack about the memcpy - you have to add 1 to the limit to copy the whole thing. My code worked without that change, but it really needs to be done.

I suspect the problem is related to code you haven't shown, or in how you build and link your kernel. You really leave it as a guessing game as to what is wrong without providing code and the process you use to build your kernel and disk image, but I had no problem taking the Blundell and Bran code and getting it to work with no hassles.As it stands with the exception of the memcpy copying one fewer byte than it should the code you have runs properly.

If you made all your code and the build process available we'd be able to identify what you don't get right. I assume with the leading underscores on your external labels that you are building on the Windows platform? If not using a cross compiler and you are using MinGW or Cygwin compilers - they are temperamental and often require extra command line options or linker script changes to get the desired output. I can't stress enough how valuable a cross compiler is to avoid those hassles.

You should eaily be able to tell where things go wrong by simply setting a breakpoint at 0x1000 in Bochs and then you can single step to the failure. It shouldn't be too many instructions. I'd make sure the instructions being stepped match what you would expect from the code.


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sun Nov 26, 2017 2:35 am 
Offline
Member
Member

Joined: Sat Mar 26, 2016 1:25 pm
Posts: 36
Thanks MichaelPetch for spending some of your precious time in helping me.
MichaelPetch wrote:
you have to add 1 to the limit to copy the whole thing.

In many tutos I've seen they did it the same manner with -1 !!
cause we start counting from ZERO no?
MichaelPetch wrote:
If you made all your code and the build process available we'd be able to identify what you don't get right.

I'll attach a ziped file of the code when I go back home.
MichaelPetch wrote:
you are building on the Windows platform?

Yes, using NASM and MINGW.
MichaelPetch wrote:
simply setting a breakpoint at 0x1000 in Bochs and then you can single step to the failure.

I've done that. The fault happens when executing: jmp 0x08:next.


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sun Nov 26, 2017 2:47 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
The third parameter of memcpy() is the number of bytes that you want to copy. You want to copy the whole of the GDT, i.e. its size, not its size minus one. Depending upon what is in the byte that you don't copy, in both the source and the destination, this may or may not matter. But it is undefined behaviour.

I think you are getting confused with the fact that array indexes start at zero.

The moral is that you shouldn't copy tutorials blindly without understanding every step. Most (all?) tutorials contain errors.


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sun Nov 26, 2017 3:03 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
osdevnewbie wrote:
In many tutos I've seen they did it the same manner with -1 !! cause we start counting from ZERO no?
While it is true that you subtract 1 when filling in the gdtp structure (the CPU internally will add 1 to that value to get the true size), when your own code is dealing with the actual structure you have to use its true size. So if you tell memcpy to copy 23 bytes it will copy 23 bytes. But the structure is actually 24 bytes. You need to deal in the real size, not the value passed through the gdtp limit value.

osdevnewbie wrote:
Yes, using NASM and MINGW.
I could have guessed. If you build the code in a certain way you may not find the code fixes up reliocations as exepected. there is a part of me that thinks that may be the case here. I'm curious if when you stepped through your code whether you noticed if the gdtp variable was filled in properly ahead of time. Although you say the `memcpy` worked (the data at 0x800 looks okay) I am under the impression that there is a problem with gdtp. One thing you can do is use bochs to step to the instruction just past the `lgdt` and then issue the command `info gdt` in the debugger. If the `gdtp` variable was filled in properly it should result in output that is similar to this:
Code:
Global Descriptor Table (base=0x0000000000000800, limit=23):
The base ix 0x800 and limit 23. I suspect yours is not that at all since the dump of memory 0x800 looks correct BUT your Bochs debug output has this:
Code:
00017826504i[CPU0  ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00017826504i[CPU0  ] |  DS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00017826504i[CPU0  ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00017826504i[CPU0  ] |  ES:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00017826504i[CPU0  ] |  FS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00017826504i[CPU0  ] |  GS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
Of note is the fact that the base value is 0xffffffff for DS, ES, FS, GS. That's incorrect given that your base for the 0x10 descriptor is 0x00000000. This suggests to me that your gdtp is wrong and is pointing at the wrong memory address for the address of the GDT and/or the limit is wrong
osdevnewbie wrote:
I've done that. The fault happens when executing: jmp 0x08:next.
According to the Bochs debugging output you provided the failure is actually on the mov ss, ax instruction, not the JMP. The instruction is listed in the output as:
Code:
0x000000000000101d>> mov ss, ax : 8ED0
The 0x10 descriptor entry is effectively invalid and thus causes a fault to occur when moved into SS.


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sun Nov 26, 2017 3:34 am 
Offline
Member
Member

Joined: Sat Mar 26, 2016 1:25 pm
Posts: 36
Even without moving the GDT to 0x800, with memcpy(), I get the fault.
Code:
void gdt_install()
{
    gdtp.limit = (sizeof(struct gdt_entry) * 3) - 1;
    gdtp.base = &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);
   // memcpy((char *)gdtp.base, (char *)gdt, gdtp.limit);
    load_gdtr();
}


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sun Nov 26, 2017 3:39 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
I don't believe the code is executing the way you think it is. I don't actually believe the generated C code after linking is correct. Among other things, I hope you assemble your NASM as Win32 and not COFF. COFF can cause issues with relocations in my experience. You also have to make sure that when you jump to 0x0000:0x1000 that there is a piece of code at the beginning of the kernel binary that transfers control to your main C function. The last thing you want it to do is start executing the code of some other functions first (which might even be the case).


Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sun Nov 26, 2017 8:29 am 
Offline
Member
Member

Joined: Sat Mar 26, 2016 1:25 pm
Posts: 36
MichaelPetch wrote:
I don't believe the code is executing the way you think it is.

The code is working if I don't resetup the GDT.

I've joint the code and generated binary image.


Attachments:
GDT.rar [6.18 KiB]
Downloaded 24 times
Top
 Profile  
 
 Post subject: Re: Setting up GDT in C ?
PostPosted: Sun Nov 26, 2017 8:56 am 
Offline
Member
Member

Joined: Sat Mar 26, 2016 1:25 pm
Posts: 36
iansjack wrote:
The third parameter of memcpy() is the number of bytes that you want to copy. You want to copy the whole of the GDT, i.e. its size, not its size minus one.
I think you are getting confused with the fact that array indexes start at zero.


Yes, you're right iansjack, thanks.
But it did'nt fix the fault.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 23 posts ]  Go to page 1, 2  Next

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 64 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group