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