Physical memory manager

This commit is contained in:
Arnau Camprubí 2022-07-18 21:28:03 +02:00
pare 20d796515b
commit 1d64e83647
S'han modificat 8 arxius amb 308 adicions i 36 eliminacions

Veure arxiu

@ -26,6 +26,7 @@ call_kmain:
; Enable interrupts
sti
; Call kernel
push ebx ; pointer to multiboot info
call kmain
; If on qemu, shutdown
push 0x2000

Veure arxiu

@ -1,27 +1,10 @@
#include <stdbool.h>
#include <stdint.h>
#include "memory.h"
static void *g_free_memory = ALLOC_START;
void *kmalloc(size_t size){
void *ptr = g_free_memory;
g_free_memory += size;
return ptr;
void memset(void *s, uint8_t c, size_t n){
uint8_t *p = s;
while(n--) *(p++) = c;
}
void *kcalloc(size_t count, size_t size){
void *ptr = g_free_memory;
size *= count;
g_free_memory += size;
for(int i = 0; i < size; i++){
((uint8_t *)ptr)[i] = 0;
}
return ptr;
}
void memcpy(uint8_t *source, uint8_t *dest, size_t count){
for(size_t i = 0; i < count; i++){
dest[i] = source[i];
}
void memcpy(void *dest, void *src, size_t n){
while(n--) ((uint8_t *)dest)[n] = ((uint8_t *)src)[n];
}

Veure arxiu

@ -3,10 +3,5 @@
#include <stddef.h>
#include <stdint.h>
#define ALLOC_START (void *)0x1000
void *kmalloc(size_t size);
// TODO: void kfree(void *ptr);
void *kcalloc(size_t count, size_t size);
void memcpy(uint8_t *source, uint8_t *dest, size_t count);
void memset(void *ptr, uint8_t val, size_t n);
void memcpy(void *dest, void *src, size_t n);

Veure arxiu

@ -5,20 +5,46 @@
#include "drivers/keyboard.h"
#include "drivers/serial.h"
#include "fs/vfs.h"
#include "mm/pmm.h"
#include "multiboot.h"
void __attribute__((cdecl)) kmain(uint64_t magic, uint64_t addr){
extern uint8_t end; // Kernel end
void __attribute__((cdecl)) kmain(multiboot_info_t *multiboot_info){
// Clear screen
clear_screen();
// Initialize chip-specific hardware
hal_initialize();
// Initialize physical memory manager
uint32_t mem_size = 1024 + multiboot_info->mem_lower + multiboot_info->mem_upper*64;
pmm_initialize(mem_size, (int)(&end));
for(int i = 0; i < multiboot_info->mmap_length; i += sizeof(multiboot_memory_map_t)){
multiboot_memory_map_t *memory_map = (multiboot_memory_map_t *)(multiboot_info->mmap_addr + i);
printf("Start Addr: 0x%x%x | Length: 0x%x%x | Size: 0x%x | Type: %i\n", memory_map->addr_h, memory_map->addr_l, memory_map->len_h, memory_map->len_l, memory_map->size, memory_map->type);
if(memory_map->type == 1){
pmm_init_region(memory_map->addr_l, memory_map->len_l);
}
}
pmm_deinit_region(0x100000, (int)(&end) - 0x100000); // Deinit the section the kernel is in
// Initialize drivers
timer_initialize();
keyboard_initialize();
// Initialize FS
vfs_initialize();
// PMM test code
uint32_t *p1 = (uint32_t *)pmm_alloc_block();
printf("Allocated p1 at: 0x%x\n", p1);
uint32_t *p2 = (uint32_t *)pmm_alloc_block();
printf("Allocated p2 at: 0x%x\n", p2);
for(;;);
}

153
src/kernel/mm/pmm.c Normal file
Veure arxiu

@ -0,0 +1,153 @@
#include <stdint.h>
#include "pmm.h"
#include "../lib/memory.h"
static uint32_t g_pmm_memory_size = 0;
static uint32_t g_pmm_used_blocks = 0;
static uint32_t g_pmm_max_blocks = 0;
static uint32_t *g_pmm_memory_map = 0;
static inline void pmm_map_set(int bit){
g_pmm_memory_map[bit / 32] |= (1 << (bit % 32));
}
static inline void pmm_map_unset(int bit){
g_pmm_memory_map[bit / 32] &= ~(1 << (bit % 32));
}
static inline bool pmm_map_get(int bit){
return g_pmm_memory_map[bit / 32] & (1 << (bit % 32));
}
int pmm_map_first_free(){
for(uint32_t i = 0; i < pmm_get_block_count() / 32; i++){
if(g_pmm_memory_map[i] != 0xffffffff){
for(int j = 0; j < 32; j++){
if(!(g_pmm_memory_map[i] & (1 << j))){
return i*4*8+j;
}
}
}
}
return -1;
}
int pmm_map_first_free_s(size_t size){
if(size == 0) return -1;
if(size == 1) return pmm_map_first_free();
for(uint32_t i = 0; i < pmm_get_block_count() / 32; i++){
if(g_pmm_memory_map[i] != 0xffffffff){
for(int j = 0; j < 32; j++){
int bit = 1 << j;
if(!(g_pmm_memory_map[i] & bit)){
int start_bit = i*32;
start_bit+=bit;
uint32_t free = 0;
for(uint32_t count = 0; count <= size; count++){
if(!pmm_map_get(start_bit+count)) free++;
if(free == size) return i*4*8+j;
}
}
}
}
}
return -1;
}
void pmm_initialize(size_t mem_size, phys_addr bitmap){
g_pmm_memory_size = mem_size;
g_pmm_memory_map = (uint32_t *)bitmap;
g_pmm_max_blocks = (pmm_get_memory_size()*1024) / PMM_BLOCK_SIZE;
g_pmm_used_blocks = g_pmm_max_blocks;
// FIXME
memset(g_pmm_memory_map, 0xFF, pmm_get_block_count() / PMM_BLOCKS_PER_BYTE);
}
void pmm_init_region(phys_addr base, size_t size){
int align = base / PMM_BLOCK_SIZE;
int blocks = size / PMM_BLOCK_SIZE;
for(; blocks >= 0; blocks--){
pmm_map_unset(align++);
g_pmm_used_blocks--;
}
pmm_map_set(0); // First block always set
}
void pmm_deinit_region(phys_addr base, size_t size){
int align = base / PMM_BLOCK_SIZE;
int blocks = size / PMM_BLOCK_SIZE;
for(; blocks >= 0; blocks--){
pmm_map_set(align++);
g_pmm_used_blocks++;
}
pmm_map_set(0); // First block always set
}
void *pmm_alloc_block(){
if(pmm_get_free_block_count() <= 0) return 0; // Out of memory
int frame = pmm_map_first_free();
if(frame == -1) return 0; // Out of memory
pmm_map_set(frame);
phys_addr addr = frame * PMM_BLOCK_SIZE;
g_pmm_used_blocks++;
return (void *)addr;
}
void pmm_free_block(void *p){
phys_addr addr = (phys_addr)p;
int frame = addr / PMM_BLOCK_SIZE;
pmm_map_unset(frame);
g_pmm_used_blocks--;
}
void *pmm_alloc_blocks(size_t size){
if(pmm_get_free_block_count() <= size) return 0; // Out of memory
int frame = pmm_map_first_free_s(size);
if(frame == -1) return 0; // Out of memory
for(uint32_t i = 0; i < size; i++) pmm_map_set(frame+i);
phys_addr addr = frame * PMM_BLOCK_SIZE;
g_pmm_used_blocks += size;
return (void *)addr;
}
void pmm_free_blocks(void *p, size_t size){
phys_addr addr = (phys_addr)p;
int frame = addr / PMM_BLOCK_SIZE;
for(uint32_t i = 0; i < size; i++) pmm_map_unset(frame+i);
g_pmm_used_blocks -= size;
}
size_t pmm_get_memory_size(){
return g_pmm_memory_size;
}
uint32_t pmm_get_block_count(){
return g_pmm_max_blocks;
}
uint32_t pmm_get_used_block_count(){
return g_pmm_used_blocks;
}
uint32_t pmm_get_free_block_count(){
return g_pmm_max_blocks - g_pmm_used_blocks;
}

24
src/kernel/mm/pmm.h Normal file
Veure arxiu

@ -0,0 +1,24 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#define PMM_BLOCKS_PER_BYTE 8
#define PMM_BLOCK_SIZE 4096
#define PMM_BLOCK_ALIGN PMM_BLOCK_SIZE
typedef uint32_t phys_addr;
int pmm_map_first_free();
int pmm_map_first_free_s(size_t size);
void pmm_initialize(size_t mem_size, phys_addr bitmap);
void pmm_init_region(phys_addr base, size_t size);
void pmm_deinit_region(phys_addr base, size_t size);
void *pmm_alloc_block();
void pmm_free_block(void *p);
void *pmm_alloc_blocks(size_t size);
void pmm_free_blocks(void *p, size_t size);
size_t pmm_get_memory_size();
uint32_t pmm_get_block_count();
uint32_t pmm_get_used_block_count();
uint32_t pmm_get_free_block_count();

96
src/kernel/multiboot.h Normal file
Veure arxiu

@ -0,0 +1,96 @@
#pragma once
#include <stdint.h>
typedef struct{
uint32_t size;
uint32_t addr_l;
uint32_t addr_h;
uint32_t len_l;
uint32_t len_h;
uint32_t type;
} __attribute__((packed)) multiboot_memory_map_t;
typedef struct{
uint32_t tabsize;
uint32_t strsize;
uint32_t addr;
uint32_t reserved;
} multiboot_aout_symbol_table_t;
typedef struct{
uint32_t num;
uint32_t size;
uint32_t addr;
uint32_t shndx;
} multiboot_elf_section_header_table_t;
typedef struct{
/* Multiboot info version number */
uint32_t flags;
/* Available memory from BIOS */
uint32_t mem_lower;
uint32_t mem_upper;
/* "root" partition */
uint32_t boot_device;
/* Kernel command line */
uint32_t cmdline;
/* Boot-Module list */
uint32_t mods_count;
uint32_t mods_addr;
union{
multiboot_aout_symbol_table_t aout_sym;
multiboot_elf_section_header_table_t elf_sec;
} u;
/* Memory Mapping buffer */
uint32_t mmap_length;
uint32_t mmap_addr;
/* Drive Info buffer */
uint32_t drives_length;
uint32_t drives_addr;
/* ROM configuration table */
uint32_t config_table;
/* Boot Loader Name */
uint32_t boot_loader_name;
/* APM table */
uint32_t apm_table;
/* Video */
uint32_t vbe_control_info;
uint32_t vbe_mode_info;
uint16_t vbe_mode;
uint16_t vbe_interface_seg;
uint16_t vbe_interface_off;
uint16_t vbe_interface_len;
uint64_t framebuffer_addr; // FIXME: This may fail, as we are not in 64 bit (long) mode
uint32_t framebuffer_pitch;
uint32_t framebuffer_width;
uint32_t framebuffer_height;
uint8_t framebuffer_bpp;
uint8_t framebuffer_type;
union{
struct{
uint32_t framebuffer_palette_addr;
uint16_t framebuffer_palette_num_colors;
};
struct{
uint8_t framebuffer_red_field_position;
uint8_t framebuffer_red_mask_size;
uint8_t framebuffer_green_field_position;
uint8_t framebuffer_green_mask_size;
uint8_t framebuffer_blue_field_position;
uint8_t framebuffer_blue_mask_size;
};
};
} __attribute__((packed)) multiboot_info_t;

Veure arxiu

@ -14,12 +14,6 @@ int shell_run(char *cmd){
else if(!strcmp(cmd, "version")){
printf("%s\n", OS_VERSION);
}
else if(!strcmp(cmd, "malloc")){
printf("Allocated 10 bytes:\n%x\n", kmalloc(10));
}
else if(!strcmp(cmd, "calloc")){
printf("Allocated and zeroed 10 chars:\n%x\n", kcalloc(10, sizeof(char)));
}
else if(!strcmp(cmd, "clear")){
clear_screen();
}