(SOLVED) Mapping VGA graphics ram to higher half not working

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
tunge
Posts: 11
Joined: Wed Jan 08, 2025 4:21 am

(SOLVED) Mapping VGA graphics ram to higher half not working

Post by tunge »

so i recently moved my kernel to the higher half, using the wikis "Higher half bare bones x86" as a refrence, ive changed the line in boot.s that maps 0xB8000 to the higher half so it maps 0xA0000 because im using 320x200x256 mode, but any time i try to write to it, my kernel triple faults.
this is my boot.s:

Code: Select all

# Declare constants for the multiboot header.
.set ALIGN,    1<<0             # align loaded modules on page boundaries
.set MEMINFO,  1<<1             # provide memory map
.set FLAGS,    ALIGN | MEMINFO  # this is the Multiboot 'flag' field
.set MAGIC,    0x1BADB002       # 'magic number' lets bootloader find the header
.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot

# Declare a multiboot header that marks the program as a kernel.
.section .multiboot.data, "aw"
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM

# Allocate the initial stack.
.section .bootstrap_stack, "aw", @nobits
stack_bottom:
.skip 16384 # 16 KiB
stack_top:

# Preallocate pages used for paging. Don't hard-code addresses and assume they
# are available, as the bootloader might have loaded its multiboot structures or
# modules there. This lets the bootloader know it must avoid the addresses.
.section .bss, "aw", @nobits
	.align 4096
boot_page_directory:
	.skip 4096
boot_page_table1:
	.skip 4096
# Further page tables may be required if the kernel grows beyond 3 MiB.

# The kernel entry point.
.section .multiboot.text, "a"
.global _start
.type _start, @function
_start:
	# Physical address of boot_page_table1.
	# TODO: I recall seeing some assembly that used a macro to do the
	#       conversions to and from physical. Maybe this should be done in this
	#       code as well?
	movl $(boot_page_table1 - 0xC0000000), %edi
	# First address to map is address 0.
	# TODO: Start at the first kernel page instead. Alternatively map the first
	#       1 MiB as it can be generally useful, and there's no need to
	#       specially map the VGA buffer.
	movl $0, %esi
	# Map 1023 pages. The 1024th will be the VGA text buffer.
	movl $1023, %ecx

1:
	# Only map the kernel.
	cmpl $_kernel_start, %esi
	jl 2f
	cmpl $(_kernel_end - 0xC0000000), %esi
	jge 3f

	# Map physical address as "present, writable". Note that this maps
	# .text and .rodata as writable. Mind security and map them as non-writable.
	movl %esi, %edx
	orl $0x003, %edx
	movl %edx, (%edi)

2:
	# Size of page is 4096 bytes.
	addl $4096, %esi
	# Size of entries in boot_page_table1 is 4 bytes.
	addl $4, %edi
	# Loop to the next entry if we haven't finished.
	loop 1b

3:
	# Map VGA video memory to 0xC03FF000 as "present, writable".
	movl $(0x000A0000 | 0x003), boot_page_table1 - 0xC0000000 + 1023 * 4

	# The page table is used at both page directory entry 0 (virtually from 0x0
	# to 0x3FFFFF) (thus identity mapping the kernel) and page directory entry
	# 768 (virtually from 0xC0000000 to 0xC03FFFFF) (thus mapping it in the
	# higher half). The kernel is identity mapped because enabling paging does
	# not change the next instruction, which continues to be physical. The CPU
	# would instead page fault if there was no identity mapping.

	# Map the page table to both virtual addresses 0x00000000 and 0xC0000000.
	movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 0
	movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 768 * 4

	# Set cr3 to the address of the boot_page_directory.
	movl $(boot_page_directory - 0xC0000000), %ecx
	movl %ecx, %cr3

	# Enable paging and the write-protect bit.
	movl %cr0, %ecx
	orl $0x80010000, %ecx
	movl %ecx, %cr0

	# Jump to higher half with an absolute jump. 
	lea 4f, %ecx
	jmp *%ecx

.section .text

4:
	# At this point, paging is fully set up and enabled.

	# Unmap the identity mapping as it is now unnecessary. 
	movl $0, boot_page_directory + 0

	# Reload crc3 to force a TLB flush so the changes to take effect.
	movl %cr3, %ecx
	movl %ecx, %cr3

	# Set up the stack.
	mov $stack_top, %esp

	# Enter the high-level kernel.
	call kernel_main

	# Infinite loop if the system has nothing more to do.
	cli
1:	hlt
	jmp 1b
whats going on?
Last edited by tunge on Mon Sep 01, 2025 2:43 am, edited 1 time in total.
VSlezak
Member
Member
Posts: 341
Joined: Sat Mar 10, 2018 10:16 am

Re: (i686/i386) Mapping VGA graphics ram to higher half not working

Post by VSlezak »

It seems that you mapped only one page of videobuffer. One page has 4096 bytes. Videobuffer of mode 320x200 has 64000 bytes. Are you sure you are not writing to unmapped part of videobuffer?
User avatar
GoingNuts
Posts: 9
Joined: Fri Jun 17, 2022 7:36 pm
Libera.chat IRC: GoingNuts

Re: (i686/i386) Mapping VGA graphics ram to higher half not working

Post by GoingNuts »

I thought you'd need to tinker with vga settings through the use of registers 0x3ce and 0x3cf with appropriate index because the default display memory value is text mode (0xb8000 - 0xbffff) ?
Octocontrabass
Member
Member
Posts: 6245
Joined: Mon Mar 25, 2013 7:01 pm

Re: (i686/i386) Mapping VGA graphics ram to higher half not working

Post by Octocontrabass »

GoingNuts wrote: Mon Aug 25, 2025 4:35 pmI thought you'd need to tinker with vga settings through the use of registers 0x3ce and 0x3cf with appropriate index because the default display memory value is text mode (0xb8000 - 0xbffff) ?
Not if you tell your bootloader to set up VGA mode 0x13.
tunge
Posts: 11
Joined: Wed Jan 08, 2025 4:21 am

Re: (i686/i386) Mapping VGA graphics ram to higher half not working

Post by tunge »

i set up my vga to 320x200x256
tunge
Posts: 11
Joined: Wed Jan 08, 2025 4:21 am

Re: (i686/i386) Mapping VGA graphics ram to higher half not working

Post by tunge »

VSlezak wrote: Mon Aug 25, 2025 9:37 am It seems that you mapped only one page of videobuffer. One page has 4096 bytes. Videobuffer of mode 320x200 has 64000 bytes. Are you sure you are not writing to unmapped part of videobuffer?
how do i map the full videobuffer then? i dont really know about multiboot/paging yet so its a bit confusing to me
Octocontrabass
Member
Member
Posts: 6245
Joined: Mon Mar 25, 2013 7:01 pm

Re: (i686/i386) Mapping VGA graphics ram to higher half not working

Post by Octocontrabass »

tunge wrote: Tue Aug 26, 2025 1:29 amhow do i map the full videobuffer then?
How does the existing code map one page of the framebuffer? What do you think needs to change to map the entire framebuffer?
tunge wrote: Tue Aug 26, 2025 1:29 ami dont really know about multiboot/paging yet so its a bit confusing to me
This is a good time to learn.
tunge
Posts: 11
Joined: Wed Jan 08, 2025 4:21 am

Re: (i686/i386) Mapping VGA graphics ram to higher half not working

Post by tunge »

afaik im not writing to an unmapped address:

Code: Select all

((unsigned char *)0xC03FF000) = 0;
that is all im writing.
User avatar
iansjack
Member
Member
Posts: 4908
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: (i686/i386) Mapping VGA graphics ram to higher half not working

Post by iansjack »

If you are running under qemu you can use the monitor command “info mem” to check your page mappings.
MichaelPetch
Member
Member
Posts: 857
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: (i686/i386) Mapping VGA graphics ram to higher half not working

Post by MichaelPetch »

tunge wrote: Wed Aug 27, 2025 2:08 am afaik im not writing to an unmapped address:

Code: Select all

((unsigned char *)0xC03FF000) = 0;
that is all im writing.
I assume you meant

Code: Select all

*((unsigned char *)0xC03FF000) = 0;
. If you make that the only thing (comment out everything else) in kernel_main does the problems still occur? It might be easier to put your project in GitHub so we can see everything you are doing. I also concur with the previous poster who pointed out using QEMU's monitor to find out memory map. You could try to use this:

Code: Select all

qemu-system-i386 -cdrom myos.iso -d int -no-shutdown -no-reboot -M smm=off -monitor stdio
where myos.iso is the name of your CDROM ISO image. I assume you are creating/using an ISO since you have a grub.cfg file?

If you run the command above you will see any exceptions thrown with a trace dump of info for each exception. You can also enter commands like `info mem` and `info tlb` in the terminal to get an idea what memory is mapped into memory and to which physical addresses. If you could post all the exception information you get as well as the output of `info mem` and `info tlb` it might give us a better idea of where the problem may be.
Post Reply