[SOLVED] Triple Fault on Setting SS Register
Posted: Thu Dec 23, 2021 7:19 am
Hello all,
I've been getting a triple fault when trying to set the SS register after loading my GDT. I was getting a bunch of very strange GP faults when working on interrupts, and realized I hadn't set the segment registers after creating and loading my GDT. When I tried to set them, it works for all of the registers except the SS register. The OS is 64-bit, already in long mode, and loaded via UEFI. I'm running it on a VirtualBox machine. I don't want to flood the post with too much code, but here's my GDT loading function
Here's the state of the registers at crash time:
You can see it actually triple faulted right on that mov instruction, and that the other segment registers were set properly. Lastly, here's VirtualBox's dump of my GDT on the crash:
I believe all the entries look good there. I even set all of the fields that the AMD manuals say are ignored in long mode, just in case. I'm sure the issue is something silly, I'm probably just being blind, but I've spent way too much time trying to figure this out. I'm happy to provide any other info you might need. Thanks ahead of time for any help!
I've been getting a triple fault when trying to set the SS register after loading my GDT. I was getting a bunch of very strange GP faults when working on interrupts, and realized I hadn't set the segment registers after creating and loading my GDT. When I tried to set them, it works for all of the registers except the SS register. The OS is 64-bit, already in long mode, and loaded via UEFI. I'm running it on a VirtualBox machine. I don't want to flood the post with too much code, but here's my GDT loading function
Code: Select all
GDTCodeOrDataEntry* initializeGDT(PhysicalMemoryLayout* physMemLayout) {
GDTCodeOrDataEntry* gdt = (GDTCodeOrDataEntry*) AllocatePage(physMemLayout);
gdt[0] = (GDTCodeOrDataEntry) { 0, 0, 0, 0, 0, 0 }; //Null entry
// Initialize table with "default" entries
for(int i = 1; i < GDT_BASE_ENTRIES; i++) {
gdt[i] = basicGDTEntry();
}
// Define kernel/userspace code segments
// Note: Default entries work for both data segments, as priviledge levels
// are ignored in 64-bit mode data segments
gdt[GDT_KERNEL_CODE_ARRAY_INDEX].accessByte |= ACCESS_EXECUTABLE_FLAG;
gdt[GDT_KERNEL_CODE_ARRAY_INDEX].limitPartTwoAndFlags |= LONG_MODE_CODE_FLAG;
gdt[GDT_USER_CODE_ARRAY_INDEX].accessByte |= ACCESS_EXECUTABLE_FLAG | ACCESS_USERSPACE_FLAG;
gdt[GDT_USER_CODE_ARRAY_INDEX].limitPartTwoAndFlags |= LONG_MODE_CODE_FLAG;
// Set up GDTR data
GDTRegister gdtr;
gdtr.limit = GDT_BASE_ENTRIES * sizeof(GDTCodeOrDataEntry) - 1;
gdtr.baseAddress = (UInt64) gdt;
// Load GDT and jump to new kernel code 'segment'
asm volatile goto (
"lgdt %0\n\t"
"mov %2,%%rax\n\t"
"mov %%rax,%%ds\n\t"
"mov %%rax,%%es\n\t"
"mov %%rax,%%fs\n\t"
"mov %%rax,%%gs\n\t"
"mov %%rax,%%ss\n\t"
"pushq %1\n\t"
"pushq $%l3\n\t"
"retfq\n\t"
: /* No output */
: "m"(gdtr), "r"(GDT_KERNEL_CODE_SELECTOR_INDEX), "r"(GDT_KERNEL_DATA_SELECTOR_INDEX)
: "rax", "memory", "cc"
: finish_lgdt
);
finish_lgdt:
return gdt;
}
Code: Select all
rax=0000000000000010 rbx=0000000000062020 rcx=0000000000000010 rdx=0000000000000008
rsi=0000000000041028 rdi=0000000000000061 r8 =000000000000007d r9 =00000000dfa082ce
r10=0000000000000078 r11=00000000dfa082ce r12=00000000de71f698 r13=0000000000000109
r14=0000000000000000 r15=0000000000000000 iopl=0 nv up di pl nz na pe nc
rip=0000000000402257 rsp=00000000df237830 rbp=00000000df237870
cs=0038 ds=0010 es=0010 fs=0010 gs=0010 ss=0030 rflags=00000002
%0000000000402257 8e d0 mov ss, eax
Code: Select all
0008 CodeEO Bas=00000000 Lim=000fffff DPL=0 P NA AVL=0 L=1
0010 DataRO Bas=00000000 Lim=000fffff DPL=0 P A AVL=0 L=0
0018 CodeEO Bas=00000000 Lim=000fffff DPL=3 P NA AVL=0 L=1
0020 DataRO Bas=00000000 Lim=000fffff DPL=0 P NA AVL=0 L=0