OSDev.org https://forum.osdev.org/ |
|
question about sgdt https://forum.osdev.org/viewtopic.php?f=13&t=16600 |
Page 1 of 1 |
Author: | devel [ Mon Mar 24, 2008 1:49 pm ] |
Post subject: | question about sgdt |
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. |
Author: | 01000101 [ Mon Mar 24, 2008 2:34 pm ] |
Post subject: | |
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? |
Author: | devel [ Tue Mar 25, 2008 2:26 am ] |
Post subject: | |
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. |
Author: | Combuster [ Tue Mar 25, 2008 5:17 am ] |
Post subject: | |
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? |
Author: | devel [ Tue Mar 25, 2008 6:41 am ] |
Post subject: | |
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. |
Author: | os64dev [ Tue Mar 25, 2008 9:06 am ] |
Post subject: | |
your declaration of gdt_ptr is fault use the one specified by 01000010 |
Author: | devel [ Tue Mar 25, 2008 9:47 am ] |
Post subject: | |
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. |
Author: | 01000101 [ Tue Mar 25, 2008 2:33 pm ] |
Post subject: | |
get my ****ing name right! 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. |
Author: | Korona [ Tue Mar 25, 2008 4:59 pm ] |
Post subject: | |
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"); } |
Author: | 01000101 [ Tue Mar 25, 2008 5:50 pm ] |
Post subject: | |
? that's what my function did. it took the memory location of the gdt struct and was then used with the SGDT instruction. |
Author: | devel [ Wed Mar 26, 2008 12:06 am ] |
Post subject: | |
@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); } |
Author: | Korona [ Wed Mar 26, 2008 6:11 am ] |
Post subject: | |
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. |
Author: | devel [ Wed Mar 26, 2008 9:27 am ] |
Post subject: | |
@Korona: thnx for checking this. |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |