Archive for the ‘General programming’ Category

[osdev] Invalidating a single page in the TLB

Sunday, November 16th, 2008

After a long time of no development on my kernel I decided to do some work on my paging unit. In the past I always had problems with invalidating a single page in the Translation Lookaside Buffer. I knew there was a way to do it with invlpg but I never really got to the correct inline assembly statement for a GCC compiler. It didn’t always work and had random crashes. Untill recently I was left a bit clueless since I didn’t had time to do some research on it (disassembling and looking into the opcodes.) Today I figured it out:

 
__asm__ __volatile__("invlpg (%%eax)" : : "a" (address) );

I hope this becomes useful for somebody.

[x86] LGDT and gcc inline assembly

Sunday, August 10th, 2008

I have gotten into the mood of writing a kernel again. My annoyance always has been that I needed a separate file for assembly operations like ‘lgdt’ or ‘lidt’. This post I will be handling the ‘lgdt’ instruction with inline gcc assembly. This will keep your ‘assembly’ file small and it will only define operations to call your kernel’s entry point. Also it makes your code more portable, because you’ll only need to exclude your ‘gdt.c’ file when compiling for other architectures. Rewriting your ‘assembly’ file becomes more easy then.

We need the following structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*! \struct GDTPointer
 *\brief GDTPointer
 *
 * This struct defines the GDT Pointer type
 */
 
struct GDTPointer {
 
     /*! The limit i.e number of descriptors in GDT table */
     unsigned short limit;
 
     /*! Base address of the GDT Table */
     unsigned int base;
 
} __attribute__((packed));

I will not discuss with you howto create a GDT table or how to fill this structure. It’s only there to show how to use it together with ‘lgdt’.

Let’s create ourself a new GDT pointer:

1
2
3
struct GDTPointer gdtPointer;
 
// fill it with the correct data

OK, good, now that we’ve got that, let’s do the fun part.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// load GDT pointer
asm volatile ("lgdt %0" : "=m" (gdtPointer));
 
// jump to new segment (0x08 in my case)
asm volatile("ljmp $(0x08), $reload_segments");
 
// we need to set al non-code segments to 0x10 (in my case)
asm volatile("reload_segments:");
asm volatile("movl $0x10, %eax");
asm volatile("movl %eax, %ds");
asm volatile("movl %eax, %es");
asm volatile("movl %eax, %fs");
asm volatile("movl %eax, %gs");
asm volatile("movl %eax, %ss");

If you have something like:

1
struct GDTPointer* gdtPointer = malloc(sizeof(struct GDTPointer));

You’ll need to dereference the variable like:

1
asm volatile ("lgdt %0" : "=m" (*gdtPointer));

You could use the same inline assembly to load an IDT pointer:

1
asm volatile ("lidt %0" : "=m" (idtPointer));