Limine memmap request fail

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
MikyBart
Posts: 21
Joined: Tue Sep 03, 2024 9:21 am
Libera.chat IRC: MikyBart

Limine memmap request fail

Post by MikyBart »

Hi all, I have a problem with limine reading memory blocks, for my kernel in assembly.
In the code block I posted the instruction:

Code: Select all

mov rax, [limine_memmap_request_instance + limine_memmap_request.response]
resets qemu.

I tried other ways but the problem persists.

Code: Select all

BITS 64 

struc limine_memmap_request
    .id: resq 4                    
    .revision: resq 1               
    .response: resq 1               
endstruc

struc limine_memmap_entry
    .base: resq 1                  
    .length: resq 1                
    .type: resq 1                   
endstruc

struc limine_memmap_response
    .revision: resq 1              
    .entry_count: resq 1     
    .entries: resq 1               
endstruc

struc pmm_block_info
    .base_addr: resq 1             
    .length: resq 1                
endstruc

%define LIMINE_MEMMAP_USABLE                    0x0
%define LIMINE_MEMMAP_RESERVED                  0x1
%define LIMINE_MEMMAP_ACPI_RECLAIMABLE          0x3
%define LIMINE_MEMMAP_RESERVED_HIBERNATE        0x4
%define LIMINE_MEMMAP_BAD_MEMORY                0x5
%define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE    0x6
%define LIMINE_MEMMAP_KERNEL_AND_MODULES        0x7
%define LIMINE_MEMMAP_FRAMEBUFFER               0x8

SECTION .data
;align 8
limine_memmap_request_instance:
    istruc limine_memmap_request
        at limine_memmap_request.id, dq 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62
        at limine_memmap_request.revision, dq 0
        at limine_memmap_request.response, dq 0
    iend

SECTION .text
GLOBAL init_physical_memory_manager

init_physical_memory_manager:
    push rbp
    mov rbp, rsp

   mov rax, [limine_memmap_request_instance + limine_memmap_request.response]

.exit_pmm_init:

    pop rbp

User avatar
iansjack
Member
Member
Posts: 4779
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Limine memmap request fail

Post by iansjack »

This is only a fragment of code; do you have a link to all of your code right from when the boot manager hands over control, and your limine config file? (Presumably you are using the limine boot manager?)
MikyBart
Posts: 21
Joined: Tue Sep 03, 2024 9:21 am
Libera.chat IRC: MikyBart

Re: Limine memmap request fail

Post by MikyBart »

the full code:

Code: Select all

BITS 64

struc limine_memmap_request
    .id: resq 4
    .revision: resq 1
    .response: resq 1
endsstruc

struc limine_memmap_entry
    .base: resq 1
    .length: resq 1
    .type: resq 1
endsstruc

struc limine_memmap_response
    .revision: resq 1
    .entry_count: resq 1
    .entries: resq 1
endsstruc

struc pmm_block_info
    .base_addr: resq 1
    .length: resq 1
endsstruc

%define LIMINE_MEMMAP_USABLE             0x0
%define LIMINE_MEMMAP_RESERVED           0x1
%define LIMINE_MEMMAP_ACPI_RECLAIMABLE   0x3
%define LIMINE_MEMMAP_RESERVED_HIBERNATE 0x4
%define LIMINE_MEMMAP_BAD_MEMORY         0x5
%define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 0x6
%define LIMINE_MEMMAP_KERNEL_AND_MODULES 0x7
%define LIMINE_MEMMAP_FRAMEBUFFER        0x8

%define MAX_PMM_BLOCKS 256
%define PMM_BLOCK_INFO_SIZE 16
%define limine_memmap_entry_size 24

section .data
align 8
limine_memmap_request_instance:
    istruc limine_memmap_request
        at limine_memmap_request.id, dq 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62
        at limine_memmap_request.revision, dq 0
        at limine_memmap_request.response, dq 0
    iend

section .bss
align 8
pmm_usable_blocks:
    resb MAX_PMM_BLOCKS * PMM_BLOCK_INFO_SIZE
pmm_usable_block_count:
    resq 1
total_usable_memory_bytes:
    resq 1

section .text
global init_physical_memory_manager

init_physical_memory_manager:
    push rbp
    mov rbp, rsp
    push rbx
    push r12
    push r13
    push r14
    push r15

    xor rbx, rbx
    xor r15, r15

    mov rax, [rel limine_memmap_request_instance + limine_memmap_request.response]

    cmp rax, 0
    je .error_no_memmap_response

    mov r13, [rax + limine_memmap_response.entry_count]
    mov r12, [rax + limine_memmap_response.entries]

    cmp r13, 0
    je .no_memmap_entries

    xor r10, r10

.loop_memmap_entries:
    cmp r10, r13
    jge .end_memmap_scan

    mov rax, r10
    imul rax, limine_memmap_entry_size
    add rax, r12

    mov rdi, [rax + limine_memmap_entry.base]
    mov rsi, [rax + limine_memmap_entry.length]
    mov rdx, [rax + limine_memmap_entry.type]

    cmp rdx, LIMINE_MEMMAP_USABLE
    jne .skip_block_save

    add rbx, rsi

    cmp r15, MAX_PMM_BLOCKS
    jge .skip_block_save

    mov r14, r15
    imul r14, PMM_BLOCK_INFO_SIZE
    lea r14, [rel pmm_usable_blocks + r14]

    mov [r14 + pmm_block_info.base_addr], rdi
    mov [r14 + pmm_block_info.length], rsi

    inc r15

.skip_block_save:
    inc r10
    jmp .loop_memmap_entries

.end_memmap_scan:
    mov [rel pmm_usable_block_count], r15
    mov [rel total_usable_memory_bytes], rbx

    jmp .exit_pmm_init

.error_no_memmap_response:
    xor r15, r15
    xor rbx, rbx
    mov [rel pmm_usable_block_count], r15
    mov [rel total_usable_memory_bytes], rbx

.no_memmap_entries:
    xor r15, r15
    xor rbx, rbx
    mov [rel pmm_usable_block_count], r15
    mov [rel total_usable_memory_bytes], rbx

.exit_pmm_init:
    pop r15
    pop r14
    pop r13
    pop r12
    pop rbx
    pop rbp
    ret
User avatar
iansjack
Member
Member
Posts: 4779
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Limine memmap request fail

Post by iansjack »

And when you link your code you are placing it in the upper half of memory?
Octocontrabass
Member
Member
Posts: 5805
Joined: Mon Mar 25, 2013 7:01 pm

Re: Limine memmap request fail

Post by Octocontrabass »

MikyBart wrote: Fri May 23, 2025 11:40 amresets qemu.
Sounds like a triple fault. Run QEMU with "-d int" (and maybe also "-no-reboot") and share the log.
MikyBart
Posts: 21
Joined: Tue Sep 03, 2024 9:21 am
Libera.chat IRC: MikyBart

Re: Limine memmap request fail

Post by MikyBart »

Yes, in the upper half of memory
Qemu keeps resetting.
User avatar
iansjack
Member
Member
Posts: 4779
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Limine memmap request fail

Post by iansjack »

As you are running in qemu I would use gdb to single step your code from the entry point. You can then determine exactly where it is faulting and what the machine state is at that point (including the faulting address if it’s a page fault). You might like to first use objdump to produce a disassembly listing to make sure the code is what you think it is.
MikyBart
Posts: 21
Joined: Tue Sep 03, 2024 9:21 am
Libera.chat IRC: MikyBart

Re: Limine memmap request fail

Post by MikyBart »

the routine that tries to fetch data from limine is as follows:

Code: Select all

BITS 64

%include "include/macros.inc"

EXTERN debug_msg
GLOBAL get_limine_memory_info

section .data
   align 8
    limine_hhdm_request:
       ; ID (4 x uint64_t = 32 bytes totali)
       ; Offset 0: LIMINE_COMMON_MAGIC_0
       ; Offset 8: LIMINE_COMMON_MAGIC_1
       ; Offset 16: LIMINE_HHDM_REQUEST_ID_0
       ; Offset 24: LIMINE_HHDM_REQUEST_ID_1
       dq 0xc7b1dd30df4c8b88
       dq 0x0a82e883a194f07b
       dq 0x48dcf1cb8ad2b852
       dq 0x63984e959a98244b

       ; Revision (1 x uint64_t = 8 bytes)
       ; Offset 32
       dq 0

       ; Response pointer (1 x uint64_t* = 8 bytes)
       ; Offset 40
       dq 0

    align 8
    limine_paging_request:
        ; ID (4 x uint64_t = 32 bytes totali)
        ; Offset 0: LIMINE_COMMON_MAGIC_0
        ; Offset 8: LIMINE_COMMON_MAGIC_1
        ; Offset 16: LIMINE_PAGING_REQUEST_ID_0
        ; Offset 24: LIMINE_PAGING_REQUEST_ID_1
        dq 0xc7b1dd30df4c8b88
        dq 0x0a82e883a194f07b
        dq 0x95c1a0edab0944cb
        dq 0xa4e5cb3842f7488a

        ; Revision (1 x uint64_t = 8 bytes)
        ; Offset 32
        dq 0

        ; Response pointer (1 x uint64_t* = 8 bytes)
        ; Offset 40
        dq 0
        
    align 8
    limine_requests_ptr:
        dq limine_hhdm_request
        dq limine_paging_request
        dq 0

    debug_msg_hhdm_offset_str: db "HHDM Offset", 13, 10, 0
    debug_msg_pml4_addr_str:   db "PML4 Address", 13, 10, 0

section .bss
    align 8
    global_hhdm_offset: resq 1
    global_pml4_addr:   resq 1 

section .text


get_limine_memory_info:
    pusha64
    
    mov rdi, limine_hhdm_request

    mov rax, [rdi + 40]
    mov rax, [rax]
    test rax, rax
    jz .done_get_memory

    mov [global_hhdm_offset], rax

    mov rsi, debug_msg_hhdm_offset_str
    call debug_msg

    mov rdi, limine_paging_request
    mov rax, [rdi + 40]
    mov rax, [rax]
    test rax, rax
    jz .done_get_memory

    mov [global_pml4_addr], rax 

    mov rsi, rax        
    mov rsi, debug_msg_pml4_addr_str
    call debug_msg

.done_get_memory:
    popa64

    ret
and this is the linker script:

Code: Select all

/* Tell the linker that we want an x86_64 ELF64 output file */
OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)

/* We want the symbol _start to be our entry point */
ENTRY(_start)

/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions */
PHDRS
{
    text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
    rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */
    data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
    vm_data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
}

SECTIONS
{
    /* We wanna be placed in the topmost 2GiB of the address space, for optimisations */
    /* and because that is what the Limine spec mandates. */
    /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
    /* that is the beginning of the region. */
    . = 0xffffffff80000000;

    .text : {
        *(.text .text.*)
    } :text

    /* Move to the next memory page for .rodata */
    . += CONSTANT(MAXPAGESIZE);

    .rodata : {
        *(.rodata .rodata.*)
    } :rodata

    /* Move to the next memory page for .data */
    . += CONSTANT(MAXPAGESIZE);

    .data : {
        *(.data .data.*)
    } :data

    /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
    /* unnecessary zeros will be written to the binary. */
    /* If you need, for example, .init_array and .fini_array, those should be placed */
    /* above this. */
    .bss : {
        *(COMMON)
        *(.bss .bss.*)
    } :data

    .vm_data (NOLOAD) : {
        *(.vm_data)
    }
    vm_data_start = .;
    vm_data_end = . + SIZEOF(.vm_data);

    /* Discard .note.* and .eh_frame since they may cause issues on some hosts. */
    /DISCARD/ : {
        *(.eh_frame)
        *(.note .note.*)
    }
}
Post Reply