OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 26, 2024 1:53 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 13 posts ] 
Author Message
 Post subject: question about sgdt
PostPosted: Mon Mar 24, 2008 1:49 pm 
Offline
Member
Member
User avatar

Joined: Wed Nov 28, 2007 4:15 am
Posts: 62
Hi there,
I am using `sgdt' instruction in my user space application and can't really
understand the results. The point is when I run application more time `sgdt'
doesn't return the same result every time. I am talking about returned base
address of GDT which is not same every time I run the instruction. See my code
below.

So my questions are:
Is that ok (I guess not)?
Might it be that linux changes GDTR content somehow?
Is the GDTR content constant all the time the linux is running?

Regards,
devel.

Code:
#include <stdio.h>

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

static inline gdt_t* inl_sgdt(gdt_t* m)
{
    __asm__ __volatile__("sgdt %0":"=m"(*m)::"memory");

    return m;
}

int main(void)
{
    gdt_t gdt;

    printf("--- Checking `inl_sgdt' ---\n");
    inl_sgdt((gdt_t*)&gdt);
    printf("base: 0x%X limit: 0x%X sizeof: %d\n", gdt.base, gdt.limit, sizeof(gdt));

    return 0;
}


Now if you run the code more times you should get different values for base address.


Last edited by devel on Tue Mar 25, 2008 2:40 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 24, 2008 2:34 pm 
Offline
Member
Member
User avatar

Joined: Fri Jun 22, 2007 12:47 pm
Posts: 1598
Location: New Hampshire, USA
I got a slightly modified version to return a constant memory address of the sgdt'd gdt every time.

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

unsigned long inl_gdt(unsigned long gdt_mem_base)
{
    __asm__ __volatile__("sgdt %0"
                        :"=m"(gdt_mem_base)
                        :
                        :"memory");

    return gdt_mem_base;
}

    struct gdt_ptr pGDT0;
    struct gdt_ptr pGDT1;
    unsigned long new_gdt_base0;
    unsigned long new_gdt_base1;
    new_gdt_base0 = inl_gdt((unsigned long)&pGDT0);
    new_gdt_base1 = inl_gdt((unsigned long)&pGDT1);
    printf("base0: 0x%X base1: 0x%X Base2: 0x%X Base3: 0x%X \n", (unsigned long)&pGDT0,(unsigned long)&pGDT1, new_gdt_base0, new_gdt_base1);
   


the printed bits are the memory addresses of (in order) the first gdt, second gdt, first sgdt'd loc, second sgdt'd loc.

im not exactly sure what you are asking though, but I think you just want to make sure that the sgdt instruction pushes the gdt to a fixed location every time?

_________________
Website: https://Joscor.com


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 25, 2008 2:26 am 
Offline
Member
Member
User avatar

Joined: Wed Nov 28, 2007 4:15 am
Posts: 62
01000101 wrote:
im not exactly sure what you are asking though, but I think you just want to make sure that the sgdt instruction pushes the gdt to a fixed location every time?

I am asking you why is value of gdt.base not constant every time I run the application.
In my case I get following results:
base: 0xC1813000 limit: 0xFF sizeof: 6
...
base: 0xC1809000 limit: 0xFF sizeof: 6

If I understand well `sgdt' instruction should store 6 bytes content of GDTR at given
address (in my case &gdt). I don't understand why the result is not constant.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 25, 2008 5:17 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 3:45 am
Posts: 9301
Location: On the balcony, where I can actually keep 1½m distance
I noticed one interesting difference between the two pieces of inline assembly (note the pointer dereference):
... :"=m"(*m)
... :"=m"(gdt_mem_base)

I suck at GCC inlines, but have you checked that the correct assembly is generated, instead of having it read some garbage off the stack?

_________________
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 25, 2008 6:41 am 
Offline
Member
Member
User avatar

Joined: Wed Nov 28, 2007 4:15 am
Posts: 62
Well, regarding my code I think assembly seems to be correct:

Code:
<inl_sgdt>:
push   %ebp
mov    %esp,%ebp
mov    0x8(%ebp),%eax
sgdtl  (%eax)  <--- store the 6bytes content at given address
mov    0x8(%ebp),%eax
pop    %ebp
ret


Note that regardless the code is inlined or not result varies between two values.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 25, 2008 9:06 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 27, 2007 3:21 pm
Posts: 553
Location: Best, Netherlands
your declaration of gdt_ptr is fault use the one specified by 01000010

_________________
Author of COBOS


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 25, 2008 9:47 am 
Offline
Member
Member
User avatar

Joined: Wed Nov 28, 2007 4:15 am
Posts: 62
Did you try 01000010's code? .
I don't think that 01000010's inline function is correct and using 01000010's declaration makes no different. See assembly below:

Code:
<inl_gdt>:
push   %ebp
mov    %esp,%ebp
sgdtl  0x8(%ebp)     <---- this is faulty
mov    0x8(%ebp),%eax
pop    %ebp
ret

Btw I tried my implementation under qemu and it works fine I've problem only in linux
environment.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 25, 2008 2:33 pm 
Offline
Member
Member
User avatar

Joined: Fri Jun 22, 2007 12:47 pm
Posts: 1598
Location: New Hampshire, USA
get my ****ing name right! :twisted:

the code I supplied was tested on a real machine and I double checked the base and limits after using the sgdt and then lgdt instructions.

btw, The return value in the inline function (both mine and yours) is unnecessary and should just become a void function as the return value is the input value, therefor proving nothing.

_________________
Website: https://Joscor.com


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 25, 2008 4:59 pm 
Offline
Member
Member

Joined: Thu May 17, 2007 1:27 pm
Posts: 999
The correct GCC statement to store the gdt description struct is:
Code:
void store_gdt_desc(struct gdt_ptr *location) {
__asm__ __volatile__("sgdt %0" : : "m"(location) : "memory");
}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 25, 2008 5:50 pm 
Offline
Member
Member
User avatar

Joined: Fri Jun 22, 2007 12:47 pm
Posts: 1598
Location: New Hampshire, USA
? that's what my function did.
it took the memory location of the gdt struct and was then used with the SGDT instruction.

_________________
Website: https://Joscor.com


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 26, 2008 12:06 am 
Offline
Member
Member
User avatar

Joined: Wed Nov 28, 2007 4:15 am
Posts: 62
@01000101:
Your code gives following output on my machine:
First run:
base0: 0xBFCAAB86 base1: 0xBFCAAB80 Base2: 0x300000FF Base3: 0x300000FF
pGDT0.base: 0xBFCAABA8 pGDT0.limit: 0x804
pGDT1.base: 0x9FF4B7FC pGDT1.limit: 0x3FF4

Second run:
base0: 0xBFA6A146 base1: 0xBFA6A140 Base2: 0x900000FF Base3: 0x900000FF
pGDT0.base: 0xBFA6A168 pGDT0.limit: 0x804
pGDT1.base: 0x9FF4B7F8 pGDT1.limit: 0x2FF4

Third run:
base0: 0xBFDB8C96 base1: 0xBFDB8C90 Base2: 0x300000FF Base3: 0x300000FF
pGDT0.base: 0xBFDB8CB8 pGDT0.limit: 0x804
pGDT1.base: 0x9FF4B7F2 pGDT1.limit: 0x3FF4

Is the output really correct?


your code:
Code:
struct gdt_ptr
{
    unsigned short limit;
    unsigned int base;
} __attribute__((packed));

unsigned long inl_gdt(unsigned long gdt_mem_base)
{
    __asm__ __volatile__("sgdt %0"
                        :"=m"(gdt_mem_base)
                        :
                        :"memory");

    return gdt_mem_base;
}
int main(void)
{
    struct gdt_ptr pGDT0;
    struct gdt_ptr pGDT1;
    unsigned long new_gdt_base0;
    unsigned long new_gdt_base1;
    new_gdt_base0 = inl_gdt((unsigned long)&pGDT0);
    new_gdt_base1 = inl_gdt((unsigned long)&pGDT1);
    printf("base0: 0x%X base1: 0x%X Base2: 0x%X Base3: 0x%X \n", (unsigned long)&pGDT0,(unsigned long)&pGDT1, new_gdt_base0, new_gdt_base1);
    printf("pGDT0.base: 0x%X pGDT0.limit: 0x%X \n", pGDT0.base, pGDT0.limit);
    printf("pGDT1.base: 0x%X pGDT1.limit: 0x%X \n", pGDT1.base, pGDT1.limit);
}


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 26, 2008 6:11 am 
Offline
Member
Member

Joined: Thu May 17, 2007 1:27 pm
Posts: 999
01000101 wrote:
? that's what my function did.
it took the memory location of the gdt struct and was then used with the SGDT instruction.

No, your function did a
Code:
asm volatile ("sgdt %0" : "=m" (location) : : "memory");

Your inline assembly statement specifies location as an output operand. The sgdt instruction takes location as an input operand.

EDIT: It seems my code is not correct either.
The following code gives the expected results on linux 2.6.22-14-386.
Code:
#include "stdio.h"

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

void store_gdt_desc(struct gdt_desc *location) {
   asm volatile ("sgdt %0" : : "m"(*location) : "memory");
}

int main(int argc, char** args) {
   struct gdt_desc desc;
   
   store_gdt_desc(&desc);
   printf("First run, gdt base: 0x%X, limit: 0x%X\n", desc.base, desc.limit);
   store_gdt_desc(&desc);
   printf("Second run, gdt base: 0x%X, limit: 0x%X\n", desc.base, desc.limit);
   store_gdt_desc(&desc);
   printf("Third run, gdt base: 0x%X, limit: 0x%X\n", desc.base, desc.limit);
}


The result on my machine is:
Code:
First run, gdt base: 0xC039B000, limit: 0xFF
Second run, gdt base: 0xC039B000, limit: 0xFF
Third run, gdt base: 0xC039B000, limit: 0xFF

These values do not change if I run the program several times. It seems linux does not change the gdtr register.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 26, 2008 9:27 am 
Offline
Member
Member
User avatar

Joined: Wed Nov 28, 2007 4:15 am
Posts: 62
@Korona:
thnx for checking this.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 25 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