Reading to a certain memory address triple faults the system, only on VMware, Vbox or rh, not on Bochs or QEmu

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
LaCrak27
Posts: 5
Joined: Tue Dec 17, 2024 6:28 am

Reading to a certain memory address triple faults the system, only on VMware, Vbox or rh, not on Bochs or QEmu

Post by LaCrak27 »

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.

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
Then after that, the switch to protected mode is done like so:

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
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)

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");
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 :)
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Reading to a certain memory address triple faults the system, only on VMware, Vbox or rh, not on Bochs or QEmu

Post by Octocontrabass »

LaCrak27 wrote: Tue Dec 17, 2024 6:49 amAs 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.
Read or write?
LaCrak27 wrote: Tue Dec 17, 2024 6:49 am

Code: Select all

init_pm:
    sti
Enabling maskable interrupts before you've initialized the IDT (or much of anything else!) is a bad idea.
LaCrak27 wrote: Tue Dec 17, 2024 6:49 am- 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)
But did you check the A20 gate to make sure you're not overwriting your kernel? (This sort of thing is why we generally recommend using an existing bootloader: you can focus on writing your OS instead of debugging your bootloader!)
LaCrak27
Posts: 5
Joined: Tue Dec 17, 2024 6:28 am

Re: Reading to a certain memory address triple faults the system, only on VMware, Vbox or rh, not on Bochs or QEmu

Post by LaCrak27 »

It happens on writes, and not enabling the interrupts doesn't make a change, matter of fact they were not enabled at that point before, I enabled them while writing the post for some reason. The kernel is not getting overwritten, as it is loaded into 0x101F0, veeery far from all of this.
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Reading to a certain memory address triple faults the system, only on VMware, Vbox or rh, not on Bochs or QEmu

Post by Octocontrabass »

LaCrak27 wrote: Tue Dec 17, 2024 11:50 amThe kernel is not getting overwritten, as it is loaded into 0x101F0, veeery far from all of this.
It's not far at all if the A20 gate has made 0x101F0 and 0x1101F0 point to the same memory.
LaCrak27
Posts: 5
Joined: Tue Dec 17, 2024 6:28 am

Re: Reading to a certain memory address triple faults the system, only on VMware, Vbox or rh, not on Bochs or QEmu

Post by LaCrak27 »

Oh, I was not aware of that, I'll check it when I get back home, thanks a lot!
Post Reply