Implemented Physical Memory Manager

This commit is contained in:
lucic71 2022-06-28 19:40:51 +03:00
parent 76a7ce2a8a
commit 7bb02930eb
5 changed files with 240 additions and 4 deletions

View File

@ -43,6 +43,8 @@ SECTIONS {
}
_kernel_bss_end = .;
. = ALIGN(4K);
_kernel_end = .;
/DISCARD/ : {

View File

@ -12,12 +12,12 @@
* pmm_init:
* Initializes the Physical Memory Manager.
*
* @param size - Size of available physical memory
* @param mmap_addr - Physical memory address of memory map data structure
* @param size - Size of available physical memory in KB
*
*/
void pmm_init(size_t size, uint32_t mmap_addr);
void pmm_init(uint32_t mmap_addr, size_t size);
/*
* pmm_init_region:
@ -30,6 +30,19 @@ void pmm_init(size_t size, uint32_t mmap_addr);
void pmm_init_region(uint32_t base, size_t size);
/*
* pmm_init_available_regions:
* ---------------------------
*
* Using multiboot info, initialize the available memory regions.
*
* @param mmap - Pointer to start of memory map info
* @param mmap_end - Pointe rto end of memory map info
*
*/
void pmm_init_available_regions(uint32_t mmap_, uint32_t mmap_end_);
/*
* pmm_deinit_region:
* Deinitializes a memory region of specified size.
@ -41,6 +54,16 @@ void pmm_init_region(uint32_t base, size_t size);
void pmm_deinit_region(uint32_t base, size_t size);
/*
* pmm_deinit_kernel:
* Deinitializes the memory where the kernel and the memory map data
* structure stay. It assumes that the memory map is placed after
* the end of kernel.
*
*/
void pmm_deinit_kernel(void);
/*
* pmm_alloc_block:
* Allocates a memory block and returns a generic pointer to its physical
@ -54,6 +77,8 @@ void *pmm_alloc_block(void);
* pmm_free_block:
* Frees a memory block.
*
* @param p - Pointer to be free'd
*
*/
void pmm_free_block(void *p);
@ -67,7 +92,7 @@ void pmm_free_block(void *p);
*
*/
void print_memory_map(multiboot_memory_map_t *mmap, multiboot_memory_map_t *mmap_end);
void print_memory_map(uint32_t mmap_, uint32_t mmap_end_);
/*
* print_ksections

View File

@ -0,0 +1,31 @@
#ifndef PMM_INTERNALS_H_
#define PMM_INTERNALS_H_
#define BLOCKS_PER_BYTE 8
#define BLOCK_SIZE 4096
#define BLOCK_ALIGN BLOCK_SIZE
/* Macros for testing and aligning memory. */
#define IS_ALIGNED(addr, align) !((addr) & ~((align) - 1))
#define ALIGN(addr, align) (((addr) & ~((align) - 1)) + (align))
/*
* Internal variables:
*
* mem_size - Size of availabe memory in KB
* used_blocks - Number of used blocks of size BLOCK_SIZE
* max_blocks - Maximum number of blocks of size BLOCK_SIZE
* pmmap - pointer to a data structure containing info about the
* state of each block (Physical Memory Map)
* pmmap_size - Number of double words occupied by pmmap
*
*/
static size_t mem_size;
static uint32_t used_blocks;
static uint32_t max_blocks;
static uint32_t *pmmap;
static size_t pmmap_size;
#endif

View File

@ -25,7 +25,10 @@ static char *mem_types[] = {
*
*/
void print_memory_map(multiboot_memory_map_t *mmap, multiboot_memory_map_t *mmap_end) {
void print_memory_map(uint32_t mmap_, uint32_t mmap_end_) {
multiboot_memory_map_t *mmap = (multiboot_memory_map_t *) mmap_;
multiboot_memory_map_t *mmap_end = (multiboot_memory_map_t *) mmap_end_;
printf("Physical Memory Map:\n");

175
kernel/pmm/src/pmm.c Normal file
View File

@ -0,0 +1,175 @@
#include "kernel/pmm.h"
#include "pmm_internals.h"
#include "lib/bitmap.h"
#include <string.h>
#include <stddef.h>
/*
* pmm_init:
* ---------
*
* Set the internal variables and initialize the pmmap data type.
* It initializes all memory zones as used by settings all bits in pmmap.
* At the moment, pmmap is a bitmap.
*
*/
void pmm_init(uint32_t mmap_addr, size_t size) {
mem_size = size;
max_blocks = (mem_size * 1024) / BLOCK_SIZE;
used_blocks = max_blocks;
pmmap = (uint32_t *) mmap_addr;
pmmap_size = mem_size / BLOCKS_PER_BYTE;
if (mem_size % BLOCKS_PER_BYTE)
pmmap_size++;
memset(pmmap, 0xFF, pmmap_size);
}
/*
* pmm_init_available_regions:
* ---------------------------
*
* Using multiboot info, it initializes all available memory zones.
*
*/
void pmm_init_available_regions(uint32_t mmap_, uint32_t mmap_end_) {
multiboot_memory_map_t *mmap = (multiboot_memory_map_t *) mmap_;
multiboot_memory_map_t *mmap_end = (multiboot_memory_map_t *) mmap_end_;
for (int i = 0; mmap < mmap_end; mmap++, i++)
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE)
pmm_init_region((uint32_t) mmap->addr, (size_t) mmap->len);
}
/*
* pmm_init_region:
* ----------------
*
* @var blocks - Number of blocks to be unset starting from @align
* @var align - Starting index in bitmap
*
*/
void pmm_init_region(uint32_t base, size_t size) {
size_t blocks = size / BLOCK_SIZE;
uint32_t align = base / BLOCK_SIZE;
for (size_t i = 0; i < blocks; i++) {
bitmap_unset(pmmap, align++);
used_blocks--;
}
bitmap_set(pmmap, 0);
}
/*
* pmm_deinit_region:
* ------------------
*
* Sets the corresponding bit in pmmap and increments the number of
* used blocks.
*
*/
void pmm_deinit_region(uint32_t base, size_t size) {
size_t blocks = size / BLOCK_SIZE;
uint32_t align = base / BLOCK_SIZE;
for (size_t i = 0; i < blocks; i++) {
bitmap_set(pmmap, align++);
used_blocks++;
}
}
/*
* pmm_deinit_kernel:
* ------------------
*
* Deinitializes the blocks containing the kernel and the memory map. There
* is an align operation because the routine tries to deinitialize all
* blocks where pmmap may sit in memory.
*
*/
void pmm_deinit_kernel(void) {
extern uint8_t *_kernel_start;
extern uint8_t *_kernel_end;
size_t kernel_size = (size_t) &_kernel_end - (size_t) &_kernel_start;
uint32_t pmmap_size_aligned = pmmap_size;
if (!IS_ALIGNED(pmmap_size_aligned, BLOCK_SIZE))
pmmap_size_aligned = ALIGN(pmmap_size_aligned, BLOCK_SIZE);
pmm_deinit_region((uint32_t) &_kernel_start, kernel_size);
pmm_deinit_region((uint32_t) &_kernel_end, pmmap_size_aligned);
}
/*
* pmm_alloc_block:
* ----------------
*
* Searches for a free block and returns a pointer to its physical memory
* location.
*
*/
void *pmm_alloc_block(void) {
if (used_blocks - max_blocks <= 0)
return NULL;
int p_index = bitmap_first_unset(pmmap, max_blocks);
if (p_index == -1)
return NULL;
bitmap_set(pmmap, p_index);
used_blocks++;
return (void *) (BLOCK_SIZE * p_index);
}
/*
* pmm_free_block:
* ---------------
*
* Checks if p is a valid pointer to free (is not first memory block)
* and frees its entry it pmmap.
*
*/
void pmm_free_block(void *p) {
if (p == NULL)
return;
uint32_t p_addr = (uint32_t) p;
int index = p_addr / BLOCK_SIZE;
bitmap_unset(pmmap, index);
used_blocks--;
}