0

I am developing a physical memory manager for my OS. So, to get the memory map, I used the BIOS int 0x15, eax = 0xE820 interrupt to get the memory map. I store the map at a location (0x7e00) and then loop through each entry and try to store it in a C structure array. But it doesn't work in a loop.

The file containing the memory manager code is -

physmm.h

#ifndef __PHYSMM_H
#define __PHYSMM_H

#include <stdint.h>

#define NUM_REGIONS 10

// Structure defining a type to store Memory Map Entry
typedef struct {
    uint32_t base;
    uint32_t length;
    uint32_t type;
    uint32_t ext_attr;
}mmap_t;

mmap_t* physmm_mmap;

uint32_t mem_blocks[NUM_REGIONS];

uint32_t memoryKB;
uint16_t memoryMB;

void get_mem_details();

void initialize_physmm();

void set_block(uint8_t block_num, uint8_t region);
void clear_block(uint8_t block_num, uint8_t region);

uint8_t* malloc();
uint8_t* dump(uint8_t* block);

#endif

physmm.c

#include "physmm.h"

void get_mem_details(){
    if(*((uint8_t*) 0x4ff)==0xff){
        printC("Memory Not Recognized!!", 0x1c);
        return;
    }
    uint16_t conmB =  *((uint16_t*) 0x500);
    uint16_t extmB =  *((uint16_t*) 0x502);
    uint32_t mem1to16 = *((uint32_t*) 0x504);
    uint32_t memgreater16 = *((uint32_t*) 0x508);

    memoryKB = conmB/1024 + extmB/1024 + mem1to16 + memgreater16*64;
    memoryMB = memoryKB/1024;
}

void initialize_physmm(){
    uint16_t i=0, j=0;
    uint64_t y = 0;

    uint16_t no_of_regions = *((uint16_t*)0x50c);

    get_mem_details();

    for(i=0;i<NUM_REGIONS;i++)
    {
        mem_blocks[i] = 0xffffffff;
    }

    uint8_t* entry = (uint8_t*) 0x7e00;

    j=0;
    for(i=0; i < no_of_regions ; i++){
        physmm_mmap[i].base = (uint32_t) entry[j];
        physmm_mmap[i].length = (uint32_t) entry[j+8];
        physmm_mmap[i].type = (uint32_t) entry[j+16];
        physmm_mmap[i].ext_attr = (uint32_t) entry[j+20];
        j += 24;
    }

    for(i=0;i < no_of_regions;i++){
        printfNum(physmm_mmap[i].base, 16);
        printfNum(physmm_mmap[i].length, 16);
        printfNum(physmm_mmap[i].type, 16);
    }
}

This returns zero for base and length but returns perhaps a correct value for type. When I use a uint32_t* entry pointer, it doesn't even return the correct values for type. Returns some numbers that are unwanted (probably near to the address 0x7e00 but incorrectly pointed to).

I am storing the memory map at the location 0x7e00. I get the correct values if I manually add the pointer's value one by one and store the value. So, the memory map is at the correct location.

According to me, I am not able to point the entry pointer to the correct location on the memory. Can anyone help me resolve the code?

EDIT

The stage 1 bootloader -

[org 0x7c00]

mov [BOOT_DRIVE], dl
mov [0x7fe], byte dl

STAGE2 equ 0x800

STAGE2_SECTORS equ 2+1
TRACKS equ 2

mov [BOOT_DRIVE],dl

mov bp,0x9000
mov sp,bp

mov bx, msgReal
call print_string

call load_stage2

call STAGE2

jmp $

%include 'boot/bios.ASM'

[bits 16]
load_stage2:
    mov bx, msgStage2
    call print_string
    mov cl, 2
    mov bx, STAGE2
    mov dh, 1
    mov dl, [BOOT_DRIVE]
load_sector:
    call disk_load
    cmp cl, STAGE2_SECTORS
    je loaded
    cmp cl, 15
    add cl, 1
    add bx, 512
    jmp load_sector
loaded:
    ret

BOOT_DRIVE db 0
msgReal db "Booted in 16-bit mode",0
msgStage2 db "Loading the stage2 boot loader onto memory",0

times 510-($-$$) db 0
dw 0xaa55

The stage 2 bootloader code -

[org 0x800]

KERNEL equ 0x1000
KERNEL_SECTORS equ 25

mov dl, byte[0x7fe]
mov [BOOT_DRIVE], dl

mov bx, msgStage2
call print_string

call load_kernel

mov bx, msg
call print_string

mov [0x4ff], byte 0x00

int 0x12
jc memError
mov [0x500], ax

clc
mov ah, 0x88
int 0x15
jc memError
mov [0x502], ax

xor cx, cx
xor dx, dx
mov eax, 0x0000E801
int 0x15
jc memError
cmp ah, 0x86
je memError
cmp ah, 0x80
je memError
jcxz useax
mov eax, ecx
mov ebx, edx
useax:
mov [0x504], eax
mov [0x508], ebx

jmp memDone

memError:
    mov [0x4ff], byte 0xff

memDone:

mov bx, 0x7e0
mov es, bx
mov di, 0x0
call do_e820
mov bx, bp
mov [0x50C], bx

call switch_to_pm

%include 'boot/bios.ASM'

%include 'boot/gdt.ASM'
%include 'boot/protected_mode.ASM'
%include 'boot/print32.ASM'

[bits 16]

load_kernel:
    mov bx, msgKernel
    call print_string
    mov ax, 3
    mov cl, 4
    mov ch, 0
    mov bx, KERNEL
    mov dl, [BOOT_DRIVE]
    mov dh, 0
    mov ch, 0
load_sector:
    mov ah, 0x02
    mov al, 1
    int 0x13
    jc error1
    cmp al, 1
    jne error2
    push bx
    mov bl, [Sector]
    cmp bl, KERNEL_SECTORS
    pop bx
    je loaded
    push bx
    mov bl, [Sector]
    inc bl
    mov [Sector], bl
    pop bx
    inc cl
    cmp cl, 18
    jne continue
    add ch, 1
    mov cl, 1
continue:
    add bx, BytesPerSector
    jmp load_sector
loaded:
    ret

error1:
    mov bx, errorMsg1
    call print_string
    jmp $

error2:
    mov bx, errorMsg2
    call print_string
    jmp $

; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map
; inputs: es:di -> destination buffer for 24 byte entries
; outputs: bp = entry count, trashes all registers except esi
do_e820:
    xor ebx, ebx        ; ebx must be 0 to start
    xor bp, bp      ; keep an entry count in bp
    mov edx, 0x0534D4150    ; Place "SMAP" into edx
    mov eax, 0xe820
    mov [es:di + 20], dword 1   ; force a valid ACPI 3.X entry
    mov ecx, 24     ; ask for 24 bytes
    int 0x15
    jc short .failed    ; carry set on first call means "unsupported function"
    mov edx, 0x0534D4150    ; Some BIOSes apparently trash this register?
    cmp eax, edx        ; on success, eax must have been reset to "SMAP"
    jne short .failed
    test ebx, ebx       ; ebx = 0 implies list is only 1 entry long (worthless)
    je short .failed
    jmp short .jmpin
.e820lp:
    mov eax, 0xe820     ; eax, ecx get trashed on every int 0x15 call
    mov [es:di + 20], dword 1   ; force a valid ACPI 3.X entry
    mov ecx, 24     ; ask for 24 bytes again
    int 0x15
    jc short .e820f     ; carry set means "end of list already reached"
    mov edx, 0x0534D4150    ; repair potentially trashed register
.jmpin:
    jcxz .skipent       ; skip any 0 length entries
    cmp cl, 20      ; got a 24 byte ACPI 3.X response?
    jbe short .notext
    test byte [es:di + 20], 1   ; if so: is the "ignore this data" bit clear?
    je short .skipent
.notext:
    mov ecx, [es:di + 8]    ; get lower uint32_t of memory region length
    or ecx, [es:di + 12]    ; "or" it with upper uint32_t to test for zero
    jz .skipent     ; if length uint64_t is 0, skip entry
    inc bp          ; got a good entry: ++count, move to next storage spot
    add di, 24
.skipent:
    test ebx, ebx       ; if ebx resets to 0, list is complete
    jne short .e820lp
.e820f:
    mov [mmap_ent], bp  ; store the entry count
    clc         ; there is "jc" on end of list to this point, so the carry must be cleared
    ret
.failed:
    stc         ; "function unsupported" error exit
    ret


[bits 32]

BEGIN_PM:
    mov ebx, msgProt
    call print_string32
    call KERNEL
    jmp $

BytesPerSector equ 512
NumHeads equ 2
SectorsPerTrack equ 18

Sector db 0

mmap_ent dw 0

BOOT_DRIVE db 0

msgStage2 db "Stage 2 reched!", 0
msgProt db "Successfully switched to 32-bit mode",0
msgKernel db "Loading the kernel onto memory",0
msg db "Loaded!!", 0
errorMsg1 db "Error1", 0
errorMsg2 db "Error2", 0

times 1024-($-$$) db 0

Kernel code -

#include <stdint.h>
#include <stddef.h>
#include "../physmm/physmm.h"

void print_menu(uint8_t n);

void main()
{
    /*Declarations*/
    #ifdef DEBUG
        char* status = "MOS V2.0 Copyright 2017 | Welcome Anish Sharma | Development Build";
    #else
        char* status = "Welcome Anish Sharma";
    #endif

    fillScreen();

    hal_initialize();

    clrscr();

    initialize_physmm();

    write_status(status);

    showNumber("Total Memory (in KB):", memoryKB, 10, 0x1e);
    showNumber("Total Memory (in MB):", memoryMB, 10, 0x1e);
    showNumber("Number of Regions:", *((uint16_t*)0x50c), 10, 0x1e);
    print("Hello");

    for(;;){
        write_string_line(0x0f, "Current Tick Count : ", 23);
        printNum(get_tick(), 21, 23, 0x0f, 10);
        if(get_tick() % 10 == 0)
            update_cursor(0,getCLine());
    }
}

The makefile -

DIRECTORIES = boot kernel drivers HALx86 dataman physmm

C_SOURCES = $(wildcard drivers/*.c HALx86/*.c dataman/*.c physmm/*.c)
ASM_SOURCES = $(wildcard HALx86/*.asm)

CC = gcc
CFLAGS = -DDEBUG -m32 -ffreestanding -c -nostdlib -lgcc

KERNEL = kernel/kernel_start.o kernel/kernel.o

ASM = nasm
AOFLAGS = -f elf32 -o
ABINFLAGS = -f bin -o

OBJ = ${C_SOURCES:.c=.o}
ASMOBJ = ${ASM_SOURCES:.asm=.o}

all: os-image.img

os-image.img: boot/boot_sector.bin boot/boot_stage2.bin kernel/kernel.bin
    cat $^ > $@
    echo "OS Image size:"
    wc -c os-image.img

kernel/kernel.bin: $(KERNEL) ${OBJ} ${ASMOBJ}
    ld -melf_i386 -o $@ -Ttext 0x1000 $^ --oformat binary

%.o : %.c
    $(CC) $(CFLAGS) $< -o $@

%.o : %.asm
    $(ASM) $< $(AOFLAGS) $@

%.bin : %.asm 
    nasm $< $(ABINFLAGS) $@

clean:
    rm -fr kernel/*.o
    rm -fr drivers/*.o
    rm -fr HALx86/*.o
    rm -fr dataman/*.o
    rm -fr physmm/*.o
    rm -fr boot/*.bin
    rm -fr os-image.img *.bin *.o

rebuild:
    make clean
    make

backup:
    make clean
    zip -r backups/BACKUP_DATE-`date +%d-%m-%Y_%H-%M-%S`.zip $(DIRECTORIES) README.txt makefile
    make
Anish Sharma
  • 314
  • 3
  • 18
  • I'd start changing `()` to `(void)` for all your functions... – LPs May 18 '17 at 07:30
  • 1
    You code does not intialize `physmm_mmap` pointer.... Is it somewhere initialized? – LPs May 18 '17 at 07:44
  • Do I need to initialize it with values or make it point to a memory location? I initialized it with all values as zero, but that doesn't help. @LPs – Anish Sharma May 18 '17 at 07:49
  • What I meant is: `physmm_mmap` is a pointer to what? In the piece of code shown it is pointing to, most probably, to address `0`. So `physmm_mmap[i]` invokes [UB](https://en.wikipedia.org/wiki/Undefined_behavior). You must allocate memory for that pointer or init it to a specific (allowed) address. – LPs May 18 '17 at 07:54
  • You define variables in a header? Seriously? – Gerhardh May 18 '17 at 07:55
  • I tried that. I made the `physmm` variable point to a location `0x7ef0` (which is free) and executed the code, but it gave the same output. @LPs – Anish Sharma May 18 '17 at 08:00
  • initializing `physmm_mmap` to `0x7ef0`, and initializing `entry = 0x7e00`, they overlap from `entry[16]` and following indeces – LPs May 18 '17 at 09:11
  • but I never reach entry[16] @LPs – Anish Sharma May 18 '17 at 09:12
  • With `j=0`, from `physmm_mmap[i].type = (uint32_t) entry[j+16];` and following.. – LPs May 18 '17 at 09:14
  • This isn't a minimal complete verifiable example. Clearly one problem is `physmm_mmap` but there may be other issues besides the code you showed. Show us all your files, and how yo build them so we can test it out. – Michael Petch May 18 '17 at 09:14
  • I have added the code @MichaelPetch – Anish Sharma May 18 '17 at 09:29
  • The biggest problems are the lines that look like this `physmm_mmap[i].base = (uint32_t) entry[j];` . The problem is that you defined `entry` as a pointer to an array of `uint8_t` . So things like `entry[j]` are a byte. Casting it with `(uint32_t)` just takes the one byte and zero extends it to 32-bits and stores it. You need to process the data in `entry` as `uint32_t` not `uint8_t` – Michael Petch May 18 '17 at 16:54
  • You can do that by changing `entry` to `uint32_t* entry = (uint32_t*) 0x7e00;` Now you are dealing with 32-bit values. Then in the assignment statements change `entry[j+8]` to `entry[j+2]` and `entry[j+16]` to `entry[j+4]` and `entry[j+20]` to `entry[j+5]` . You then need to increment `j` by 6 on each pass. So `j += 24;` becomes `j += 6;` – Michael Petch May 18 '17 at 17:00
  • It was 4am when I last saw this and I missed the obvious. First off as has been mentioned `mmap_t* physmm_mmap;` is a pointer but it doesn't point to anything and is never initialized. If you have actually implemented `malloc` then you could allocate `physmm_mmap` that way. If you haven't implemented `malloc` you can just reserve the largest array of `mmap_t` items you think you need with `mmap_t physmm_mmap[NUM_REGIONS];` – Michael Petch May 18 '17 at 17:09
  • Thanks! It works now. Reserving the array for `physmm_mmap` and using an `uint32_t*` pointer made it work. @MichaelPetch – Anish Sharma May 19 '17 at 07:05

0 Answers0