IDT troubles... part 2
Posted: Sun Nov 17, 2024 1:16 pm
Since my last post on this forum, I've come a long way, yet I'm again getting very frustrated with the IDT.
My kernel is modular, and the default modules are loaded from a boot-time initramfs. They can include a hook, which is called after loading like so:
It's somewhat ugly, but it's worked perfectly so far. I've also created a kernel device registry, with the following way of adding new stuff:
The registry device has the following form:
For simplicity, I'm starting off with a PCI driver, since there's not much I could do without it either. The hook performs the standard mechanism of brute-force listing all 8192 bus-device combinations. It registers the valid devices it encounters with the main kernel by means of an interrupt via
with the following ISR:
However, when I run my driver, it finds two devices, then causes a general protection fault (which in turn causes a double, then a triple, fault, then a full machine reboot). What's bamboozling me is that none of the following criteria listed on the wiki seem to apply:
- No segment-related errors, since the interrupt works the first time it's called and we don't change CS, SS or the GDT.
- We're in ring 0.
- We don't change CR0.
- We're in 32-bit mode, without paging yet.
- The reg_device structure should be 32-bit aligned.
It's also well-known that a GPF can occur from a nonexistent vector, which was my first suspicion but isn't the case here either.
Here's the evidence that it's a GPF, in the form of QEMU interrupt logs (minus SMIs):
0d is a GPF. de is the interrupt vector used by the modules. I also confirmed that it is going straight from int 0xDE to reset by single-stepping in GDB, where we're taken to the destination jumped to by the reset vector, 0x0000e05b (which seems to consist of a bunch of add %al, (%eax)'s).
Can anyone help figure out why this is happening?
My kernel is modular, and the default modules are loaded from a boot-time initramfs. They can include a hook, which is called after loading like so:
Code: Select all
if (mod_info->entry != 0) {
((void (*)()) ((uint32_t) load_addr + mod_info->entry - CONTENT_OFFSET(mod_info)))();
}
Code: Select all
#define REG_ENTRIES 65536
static struct reg_device devices[REG_ENTRIES];
size_t last_dev = 0;
void register_dev (struct reg_device dev) {
devices[last_dev++] = dev;
}
Code: Select all
struct reg_device {
enum proto proto;
uint32_t ident_lo;
uint32_t ident_hi;
uint32_t pad;
};
Code: Select all
__asm__ __volatile__ ( "int $0xDE" : : "a"(ident_hi), "c"(PROTO_PCI_OLD), "d"(ident_lo) : );
Code: Select all
void isr_222 () {
uint32_t eax;
uint32_t ecx;
uint32_t edx;
struct reg_device dev;
__asm__ ( "movl %%eax, %0\n\t"
"movl %%ecx, %1\n\t"
"movl %%edx, %2" : "=m"(eax), "=m"(ecx), "=m"(edx) : : );
dev.proto = (enum proto) ecx;
dev.ident_hi = eax;
dev.ident_lo = edx;
dev.pad = 0;
register_dev(dev);
}
- No segment-related errors, since the interrupt works the first time it's called and we don't change CS, SS or the GDT.
- We're in ring 0.
- We don't change CR0.
- We're in 32-bit mode, without paging yet.
- The reg_device structure should be 32-bit aligned.
It's also well-known that a GPF can occur from a nonexistent vector, which was my first suspicion but isn't the case here either.
Here's the evidence that it's a GPF, in the form of QEMU interrupt logs (minus SMIs):
Code: Select all
0: v=de e=0000 i=1 cpl=0 IP=0008:002103b5 pc=002103b5 SP=0010:00304f50 env->regs[R_EAX]=12378086
EAX=12378086 EBX=002114d4 ECX=00000001 EDX=06000000
ESI=00000000 EDI=00210469 EBP=00304f98 ESP=00304f50
EIP=002103b5 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
[...]
1: v=de e=0000 i=1 cpl=0 IP=0008:002103b5 pc=002103b5 SP=0010:00304f50 env->regs[R_EAX]=70008086
EAX=70008086 EBX=002114d4 ECX=00000001 EDX=06010008
ESI=00000000 EDI=00210469 EBP=00304f98 ESP=00304f50
EIP=002103b5 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
[...]
2: v=0d e=06f2 i=0 cpl=0 IP=0008:002103b5 pc=002103b5 SP=0010:00304f50 env->regs[R_EAX]=70008086
EAX=70008086 EBX=002114d4 ECX=00000001 EDX=06010008
ESI=00000000 EDI=00210469 EBP=00304f98 ESP=00304f50
EIP=002103b5 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
[...]
Can anyone help figure out why this is happening?