repo: https://github.com/mikhail10101/os-test
I recently tried further implementing a simple page table setup in kernel/arch/i386/mem.c and I have some questions.
In kernel/arch/i386/tty.c, I read that I had to change VGA_MEMORY = 0xB8000 to 0xC00B8000 to keep printing.
I have 2 printf statements in kernel/kernel/kernel.c, one before initMem (defined in mem.c) and one after. The one before initMem would work whether VGA_MEMORY is equal to 0xB8000 or 0xC00B8000. Is this because in kernel/arch/i386/boot.S, I'm mapping both logical addresses to the same physical address? Just to ensure my understanding is correct.
Secondly, my printf statement works in QEMU but not in Bochs and I have no idea why. I've been playing around with it but I can't figure it out.
Any help would be appreciated, thank you!
Works in QEMU but not in Bochs
-
- Member
- Posts: 832
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: Works in QEMU but not in Bochs
Because you identity mapped the first 4MiB of memory and you also mapped 0xb8000 region to the higher half, you can use both addresses. If you were to remove the identity mapping of the first 4MiB after entering the higher half kernel then you wouldn't be able to access via 0xb8000 anymore.
I believe your printf function works but it is not being called in BOCHs. The timings when running in BOCHs and QEMU can be different. After setting up the IDT you do an `STI` instruction that enables interrupts. Each interrupt will call `exception_handler` which does a CLI/HLT which prevents any other code from executing. If a timer interrupt comes in before the first printf then your kernel will just stop in `exception_handler` and never return.
As an experiment in `idt_init` comment out the line that enables interrupts with `STI` and see what happens.
Note: your interrupt and exception stubs don't save and restore registers, and the stubs with an error code don't remove the the error code from the stack before doing the IRET.
I believe your printf function works but it is not being called in BOCHs. The timings when running in BOCHs and QEMU can be different. After setting up the IDT you do an `STI` instruction that enables interrupts. Each interrupt will call `exception_handler` which does a CLI/HLT which prevents any other code from executing. If a timer interrupt comes in before the first printf then your kernel will just stop in `exception_handler` and never return.
As an experiment in `idt_init` comment out the line that enables interrupts with `STI` and see what happens.
Note: your interrupt and exception stubs don't save and restore registers, and the stubs with an error code don't remove the the error code from the stack before doing the IRET.
Re: Works in QEMU but not in Bochs
I see, that makes more sense! I tried what you said and it worked. I'll also try working on what you noted. Thank you so much!MichaelPetch wrote: ↑Sat Jun 28, 2025 7:57 pm Because you identity mapped the first 4MiB of memory and you also mapped 0xb8000 region to the higher half, you can use both addresses. If you were to remove the identity mapping of the first 4MiB after entering the higher half kernel then you wouldn't be able to access via 0xb8000 anymore.
I believe your printf function works but it is not being called in BOCHs. The timings when running in BOCHs and QEMU can be different. After setting up the IDT you do an `STI` instruction that enables interrupts. Each interrupt will call `exception_handler` which does a CLI/HLT which prevents any other code from executing. If a timer interrupt comes in before the first printf then your kernel will just stop in `exception_handler` and never return.
As an experiment in `idt_init` comment out the line that enables interrupts with `STI` and see what happens.
Note: your interrupt and exception stubs don't save and restore registers, and the stubs with an error code don't remove the the error code from the stack before doing the IRET.