Reading to a certain memory address triple faults the system, only on VMware, Vbox or rh, not on Bochs or QEmu
Posted: Tue Dec 17, 2024 6:49 am
As the title, says, when I try to read to some address (changes on each compilation, but it's usually between the 0x100000 to the 0x110000 range), the system triple faults and crashes. You can see the complete code for my OS here. However, I will paste the relevant parts of the code here.
The bootloader sets up a GDT, which I will paste below, that simply consists of two segments spanning the whole memory of the system. Paging is disabled.
Then after that, the switch to protected mode is done like so:
After we are in PM, I call my C kernel, and inside it, I do the following:
- 1: Initialize and load a valid IDT (I'm saying it's valid because both my floppy, keyboard, timer driver works, and it does properly detect a division by zero exception. It's too large to paste here but it's on /interrupts in the github repo).
- Execute this piece of inline assembly code, which is just a simple code that starts sequentially writing to memory (I have ensured via the int 0x15 BIOS function that the memory is valid memory)
This triple faults the system. What's weird is that if I start writing at 0x110000, it completes without issue. I have tried to debug, but since I'm on windows and Bochs is the debugger that I use, and I cannot replicate the error there, I'm very lost.
Massive thanks to whoever tries to answer
The bootloader sets up a GDT, which I will paste below, that simply consists of two segments spanning the whole memory of the system. Paging is disabled.
Code: Select all
; GDT
gdt_start:
gdt_null: ; Mandatory null descriptor
dd 0x0 ; (Define double)
dd 0x0
gdt_code: ; code segment descriptor
; base=0x0, limit=0xfffff,
; 1st flags: (present)1 (privilege)00 (descriptor type)1 -> 1001b
; type flags: (code)1 (conforming)0 (readable)1 (accesed)0 -> 1010b
; 2nd flags: (granularity)1 (32-bit default)1 (64-bit seg)0 (AVL)0 -> 1100b
dw 0xffff ; Limit (0-15)
dw 0x0 ; Base (0-15)
db 00000000b ; Base (16-23)
db 10011010b ; 1st flags and type flags
db 11001111b ; 2nd flags and Limit (16-19)
db 0x0 ; Base (24-31)
gdt_data: ; data segment descriptor
; Same as code segment except type flags
; type flags: (code)0 (expand down)0 (writable)1 (accesed)0 -> 0010b
dw 0xffff ; Limit (0-15)
dw 0x0 ; Base (0-15)
db 00000000b ; Base (16-23)
db 10010010b ; 1st flags and type flags
db 11001111b ; 2nd flags and Limit (16-19)
db 0x0 ; Base (24-31)
gdt_end: ; Have the assembler calculate the size of the GDT for the GDT descriptor (below)
; GDT Descriptor
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; Size of the GDT minus one
dd gdt_start ; Start adress of the GDT
; Define some handy constants for the GDT segment descriptor offsets , which
; are what segment registers must contain when in protected mode. For example ,
; when we set DS = 0 x10 in PM , the CPU knows that we mean it to use the
; segment described at offset 0 x10 ( i.e. 16 bytes ) in our GDT , which in our
; case is the DATA segment (0 x0 -> NULL ; 0 x08 -> CODE ; 0 x10 -> DATA )
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
Code: Select all
switch_to_pm:
cli ; Disable interrupts
lgdt [gdt_descriptor] ; Load GDT
mov eax, cr0 ; Make the 1st bit of cr0 to be a one
or al, 0x1
mov cr0, eax ; We are in PM
jmp CODE_SEG:init_pm ; Far jump to 32-bit code, setting CS
[bits 32]
; Initialize registers and stack once in PM
init_pm:
sti
mov ax, DATA_SEG ; Point segment registers to the data segment
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000 ; Update stack position
mov esp, ebp
call begin_pm
- 1: Initialize and load a valid IDT (I'm saying it's valid because both my floppy, keyboard, timer driver works, and it does properly detect a division by zero exception. It's too large to paste here but it's on /interrupts in the github repo).
- Execute this piece of inline assembly code, which is just a simple code that starts sequentially writing to memory (I have ensured via the int 0x15 BIOS function that the memory is valid memory)
Code: Select all
__asm__ __volatile__(
" push %%eax\n"
" push %%ebx\n"
" mov $0xA5, %%ebx\n"
" mov $0x100000, %%eax\n" // 0x107D19 crashes
"1: \n"
" mov %%ebx, (%%eax)\n"
" inc %%eax\n"
" cmp $0x600000, %%eax\n"
" je 2f\n"
" jmp 1b\n"
"2: \n"
" pop %%ebx\n"
" pop %%eax\n"
:
:
: "memory", "esi", "edi", "eax", "ebx", "ecx", "edx");
Massive thanks to whoever tries to answer