Page 1 of 1

Weird Memory Outputs after Loading Kernel Higher Half

Posted: Sat Nov 11, 2023 6:56 am
by leventkaya
Hello, I just loaded my kernel as a higher half one. And every thing works fine, i can able to write VGA buffer, interrupts and exceptions work, except when i dump the memory information my kernel, i get weird outcomes. Here is the screenshot of it:
mem_bug.png
as you can see in the attachment some uint32_t variables retuns negative outputs and weird characters when i want to print them hexedecimal. I touth this is a simple integer overflow issiue related with my stdio implementations since everything works fine and expected in the kernel but i can't be sure.
I have very simle/generic higher half and memory information code. Here is the related part of the code in my kernel:

loader.asm:

Code: Select all

[BITS 32]
global loader                           ; the entry point for the linker
global boot_page_directory

extern kernel_main                            ; kmain is defined in kmain.c
extern end_of_kernel
extern kernel_virtual_end               ; these are defined in the link script
extern kernel_virtual_start
extern kernel_physical_end
extern kernel_physical_start

; setting up the multiboot headers for GRUB
MODULEALIGN equ 1<<0                    ; align loaded modules on page 
                                        ; boundaries
MEMINFO     equ 1<<1                    ; provide memory map
FLAGS       equ MODULEALIGN | MEMINFO   ; the multiboot flag field
MAGIC       equ 0x1BADB002              ; magic number for bootloader to 
                                        ; find the header
CHECKSUM    equ -(MAGIC + FLAGS)        ; checksum required

; paging for the kernel
KERNEL_VIRTUAL_BASE     equ 0xC0000000                  ; we start at 3GB
KERNEL_PAGE_IDX         equ (KERNEL_VIRTUAL_BASE >> 22) ; PDT index for 4MB PDE

; the page directory used to boot the kernel into the higher half
section .data
align 4096                               ; align on 4kB blocks
boot_page_directory:
    dd 00000000000000000000000010001011b ; identity mapped first 4MB
    times (KERNEL_PAGE_IDX-1) dd 0       ; no pages here
    dd 00000000000000000000000010001011b ; map 0xC0000000 to the first 4MB
    times (1024-KERNEL_PAGE_IDX-1) dd 0  ; no more pages


section .text
align 4
    dd MAGIC
    dd FLAGS
    dd CHECKSUM

; the entry point, called by GRUB
loader:
    mov ecx, (boot_page_directory-KERNEL_VIRTUAL_BASE)
    and ecx, 0xFFFFF000     ; we only care about the upper 20 bits
    or  ecx, 0x08           ; PWT, enable page write through?
    mov cr3, ecx            ; load pdt

    mov ecx, cr4            ; read current config from cr4
    or  ecx, 0x00000010     ; set bit enabling 4MB pages
    mov cr4, ecx            ; enable it by writing to cr4

    mov	ecx, cr0		    ; read current config from cr0
	or	ecx, 0x80000000	    ; the highest bit controls paging
	mov cr0, ecx		    ; enable paging by writing config to cr0

    lea ecx, [higher_half]  ; store the address higher_half in ecx
    jmp ecx                 ; now we jump into 0xC0100000

; code executing from here on uses the page table, and is accessed through
; the upper half, 0xC0100000
higher_half:
    mov     DWORD [boot_page_directory], 0  ; erase identity mapping of kernel
    invlpg  [0]                             ; and flush any tlb-references to it

    mov esp, stack+STACKSIZE            ; sets up the stack pointer

    push boot_page_directory
    
    push kernel_virtual_end             ; these are used by kmain, see
    push kernel_virtual_start           ; kernel_limits_t in kmain.c
    push kernel_physical_end
    push kernel_physical_start
    
    push eax                            ; eax contains the MAGIC number
    push ebx                            ; ebx contains the multiboot data 
                                        ; structure
    call kernel_main                          ; call the main function of the kernel

hang:
    jmp hang                            ; loop forever

; reserve initial stack space
STACKSIZE equ 0x4000                    ; 16kB

section .bss
align 4
stack:
    resb STACKSIZE                      ; reserve memory for stack on 
                                        ; doubleworded memory
multiboot_util.c (responsible for printing memory information etc.) :

Code: Select all

void display_memory_info(multiboot_info_t *mbinfo,
			 kernel_mem_limits_t *kmlimits)
{
	qemu_write_string("\n%s %s START\n", DEBUG_OUTPUT, MEMORY_OUTPUT);
	/* From the GRUB multiboot manual section 3.3 boot information format
     * If flags[0] is set, then the fields mem_lower and mem_upper can be 
     * accessed.
     * If flags[6] is set, then the fields mmap_length and mmap_addr can be
     * accessed, which contains a complete memory map. 
	 */
	if (mbinfo->flags & 0x00000001) {
		qemu_write_string("%s Size of the lower memory: %d kB\n",
				  INFORMATION_OUTPUT, mbinfo->mem_lower);
		qemu_write_string("%s Size of the upper memory: %d kB\n",
				  INFORMATION_OUTPUT, mbinfo->mem_upper);
	}

	if (mbinfo->flags & 0x00000020) {
		multiboot_memory_map_t *entry =
			(multiboot_memory_map_t *)mbinfo->mmap_addr;
		while ((uint32_t)entry <
		       mbinfo->mmap_addr + mbinfo->mmap_length) {
			if (entry->type == MULTIBOOT_MEMORY_AVAILABLE) {
				qemu_write_string("%s Avaliable memory: ",
						  INFORMATION_OUTPUT);
			} else {
				qemu_write_string("%s Reserved memory: ",
						  INFORMATION_OUTPUT);
			}
			/*
			* FIX: lld needed, %d overflows
			*/
			qemu_write_string("address: %d", (uint32_t)entry->addr);
			qemu_write_string(", length: %d\n",
					  (uint32_t)entry->len);

			entry = (multiboot_memory_map_t *)(((uint32_t)entry) +
							   entry->size +
							   sizeof(entry->size));
		}
	}
	qemu_write_string("%s Kernel physical start: 0x%x\n",
			  INFORMATION_OUTPUT, kmlimits->kernel_physical_start);
	qemu_write_string("%s Kernel physical end: 0x%x\n", INFORMATION_OUTPUT,
			  kmlimits->kernel_physical_end);
	qemu_write_string("%s Kernel virtual start: 0x%x\n", INFORMATION_OUTPUT,
			  kmlimits->kernel_virtual_start);
	qemu_write_string("%s Kernel virtual end: 0x%x\n", INFORMATION_OUTPUT,
			  kmlimits->kernel_virtual_end);

	qemu_write_string("%s %s END\n\n", DEBUG_OUTPUT, MEMORY_OUTPUT);
}
this is my code that responsible for making my kernel higher half and printing the memory information but again im not sure why i am getting the weird outcomes especially when the size of the memory is increases. I think it's related with that how i print the values on screen but i need to ask and get further information why this is happening. Thank you!

Re: Weird Memory Outputs after Loading Kernel Higher Half

Posted: Sat Nov 11, 2023 4:26 pm
by Octocontrabass
leventkaya wrote:some uint32_t variables retuns negative outputs and weird characters when i want to print them hexedecimal.
Your print function is using signed integers when you want it to use unsigned integers. For decimal numbers, a typical printf-like function has separate "%d" and "%u" for signed and unsigned numbers. For hexadecimal numbers, that's a bug in your printf-like formatting code.