TSS troubles
Posted: Wed May 13, 2009 5:32 pm
I'm getting very close to being able to run actual loaded programs in usermode, but I've been stuck on one thing for a few days - the TSS. I've read and re-read the documentation, but I can't see what is wrong with my implementation. Perhaps someone could shed more light on the situation.
I have the GDT hard-coded in assembly, but with an open (and allocated) space for the TSS entry. It already has the granularity and permission flags set, because those are static:
There is a piece of C code run later in the setup that sets the values for the TSS and TSS entry (and has the TSS itself as a global variable):
Btw, memclr() is like memcpy but with all zeroes, which is a bit faster.
EDIT: Also, the reason that init_tss() is in ELF section ".ttext" is because I have the kernel free all memory used by initialization code and data after it is done booting by lumping init code together. It usually only saves ~5 pages of memory, but who knows when that will come in handy? I also know this is not the part of the problem.
And here is the "tss_flush" function called by that C function:
This is effectively all of the code that does any interfacing with the TSS. When I switch to usermode and turn on interrupts, Bochs triple faults with error 10, i.e. a bad TSS fault. Unfortuantely, it is not much more descriptive, other than informing me that the fault happened with EIP in user memory and the same instruction that should be the first in the user program, which at least means my loader is working. I also noticed that the system pauses for slightly varying amounts of time before faulting, so the fault is probably caused by the PIT firing in usermode.
Any help would be appreciated!
I have the GDT hard-coded in assembly, but with an open (and allocated) space for the TSS entry. It already has the granularity and permission flags set, because those are static:
Code: Select all
section .data
global gdt
gdt:
align 0x1000
dd 0x00000000, 0x00000000
dd 0x0000FFFF, 0x00CF9A00
dd 0x0000FFFF, 0x00CF9200
dd 0x0000FFFF, 0x00CFFA00
dd 0x0000FFFF, 0x00CFF200
dd 0x00000000, 0x0000E900 ; This will become the TSS
Code: Select all
struct tss {
u32int prev_tss;
u32int esp0;
u32int ss0;
u32int unused[15];
u32int es, cs, ss, ds, fs, gs;
u32int ldt;
u16int trap, iomap_base;
} __attribute__ ((packed)) tss;
extern u8int gdt[48];
__attribute__ ((section(".ttext")))
void init_tss() {
u32int base = (u32int) &tss;
u16int limit = sizeof(struct tss);
memclr(&tss, sizeof(struct tss));
tss.ss0 = 0x13;
extern u32int stack;
tss.esp0 = (u32int) &stack;
tss.cs = 0x0B;
tss.es = tss.ds = tss.fs = tss.gs = 0x13;
gdt[40] = (limit >> 8) & 0xFF;
gdt[41] = (limit) & 0xFF;
gdt[42] = (base >> 8) & 0xFF;
gdt[43] = base & 0xFF;
gdt[44] = (base >> 16) & 0xFF;
gdt[47] = (base >> 24) & 0xFF;
extern void tss_flush();
tss_flush();
}
EDIT: Also, the reason that init_tss() is in ELF section ".ttext" is because I have the kernel free all memory used by initialization code and data after it is done booting by lumping init code together. It usually only saves ~5 pages of memory, but who knows when that will come in handy? I also know this is not the part of the problem.
And here is the "tss_flush" function called by that C function:
Code: Select all
global tss_flush
tss_flush:
mov ax, 0x2B
ltr ax
ret
Any help would be appreciated!