Assignment 4 p1 completed
This commit is contained in:
164
notes/work-summary-2026-04-14.md
Normal file
164
notes/work-summary-2026-04-14.md
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
# Assignment 4 – Part 1: Memory Management
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
In this part of the assignment, a basic memory management system was implemented for a simple OS kernel. The goal was to initialize kernel memory, enable paging, and implement dynamic memory allocation using `malloc()` and `free()`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implemented Features
|
||||||
|
|
||||||
|
### Kernel Memory Initialization
|
||||||
|
- Used:
|
||||||
|
```c
|
||||||
|
extern uint32_t end;
|
||||||
|
```
|
||||||
|
to get the end address of the kernel from the linker.
|
||||||
|
- Implemented:
|
||||||
|
```c
|
||||||
|
init_kernel_memory(&end);
|
||||||
|
```
|
||||||
|
- Set up:
|
||||||
|
- `heap_begin`
|
||||||
|
- `heap_end`
|
||||||
|
- `pheap_begin` (page-aligned heap)
|
||||||
|
- `pheap_end`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Paging
|
||||||
|
- Implemented:
|
||||||
|
```c
|
||||||
|
init_paging();
|
||||||
|
```
|
||||||
|
- Set up:
|
||||||
|
- Page directory at `0x400000`
|
||||||
|
- Page tables starting at `0x404000`
|
||||||
|
- Identity-mapped:
|
||||||
|
- `0x00000000 → 0x00000000`
|
||||||
|
- `0x400000 → 0x400000`
|
||||||
|
- Enabled paging by modifying `cr0` and `cr3`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Dynamic Memory Allocation
|
||||||
|
|
||||||
|
#### malloc()
|
||||||
|
- Implemented a simple heap allocator.
|
||||||
|
- Stores metadata using:
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
uint8_t status;
|
||||||
|
uint32_t size;
|
||||||
|
} alloc_t;
|
||||||
|
```
|
||||||
|
- Supports:
|
||||||
|
- Sequential allocation
|
||||||
|
- Reuse of freed blocks
|
||||||
|
- Zeroes allocated memory using `memset`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### free()
|
||||||
|
- Frees memory by marking the block as unused.
|
||||||
|
- Prevents errors by:
|
||||||
|
```c
|
||||||
|
if (!mem) return;
|
||||||
|
```
|
||||||
|
- Correctly updates `memory_used`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Block Reuse
|
||||||
|
- When a block is freed, it can be reused by future `malloc()` calls.
|
||||||
|
- Verified by:
|
||||||
|
- Freeing a block
|
||||||
|
- Allocating a smaller block
|
||||||
|
- Observing same address reused
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Page-Aligned Allocation (pmalloc)
|
||||||
|
- Implemented `pmalloc()` and `pfree()`:
|
||||||
|
- Allocates memory in 4KB pages
|
||||||
|
- Uses a descriptor array (`pheap_desc`)
|
||||||
|
- Located in upper memory region near `0x400000`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Memory Utility Functions
|
||||||
|
Implemented:
|
||||||
|
- `memcpy()`
|
||||||
|
- `memset()`
|
||||||
|
- `memset16()`
|
||||||
|
|
||||||
|
These replace standard library functions in kernel space.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Debug Output
|
||||||
|
|
||||||
|
#### Memory Layout
|
||||||
|
- Implemented:
|
||||||
|
```c
|
||||||
|
print_memory_layout();
|
||||||
|
```
|
||||||
|
- Displays:
|
||||||
|
- Memory used
|
||||||
|
- Memory free
|
||||||
|
- Heap size
|
||||||
|
- Heap start/end
|
||||||
|
- Page heap start/end
|
||||||
|
|
||||||
|
#### Allocation Logs
|
||||||
|
- Outputs allocation details:
|
||||||
|
```
|
||||||
|
Allocated X bytes from 0x... to 0x...
|
||||||
|
Re-allocated X bytes from 0x... to 0x...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Hex Output for Addresses
|
||||||
|
- Implemented:
|
||||||
|
```c
|
||||||
|
TerminalWriteHex(uint32_t num);
|
||||||
|
```
|
||||||
|
- Ensures correct formatting of memory addresses (base 16)
|
||||||
|
- Avoids confusion from decimal output
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing & Verification
|
||||||
|
|
||||||
|
### Allocation Test
|
||||||
|
```c
|
||||||
|
void* memory1 = malloc(48261);
|
||||||
|
void* memory2 = malloc(27261);
|
||||||
|
void* memory3 = malloc(12617);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Free and Reuse Test
|
||||||
|
```c
|
||||||
|
free(memory2);
|
||||||
|
void* memory4 = malloc(1000);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Result
|
||||||
|
- `memory4` reused the same address as `memory2`
|
||||||
|
- Confirms:
|
||||||
|
- `free()` works
|
||||||
|
- allocator reuses memory correctly
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
- Successfully implemented a basic kernel memory manager
|
||||||
|
- Paging is enabled and functioning
|
||||||
|
- `malloc()` and `free()` work correctly
|
||||||
|
- Memory reuse is verified
|
||||||
|
- Debug output is clear and correctly formatted
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Step
|
||||||
|
Proceed to **Part 2: PIT and Sleep Functions**
|
||||||
@@ -67,6 +67,9 @@ add_executable(uiaos-kernel
|
|||||||
src/interrupt.c
|
src/interrupt.c
|
||||||
src/interrupt.asm
|
src/interrupt.asm
|
||||||
src/keyboard.c
|
src/keyboard.c
|
||||||
|
src/malloc.c
|
||||||
|
src/memutils.c
|
||||||
|
src/memory.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
26
src/OSDev_18/include/kernel/memory.h
Normal file
26
src/OSDev_18/include/kernel/memory.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef KERNEL_MEMORY_H
|
||||||
|
#define KERNEL_MEMORY_H
|
||||||
|
|
||||||
|
#include <libc/stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t status;
|
||||||
|
uint32_t size;
|
||||||
|
} alloc_t;
|
||||||
|
|
||||||
|
void init_kernel_memory(uint32_t* kernel_end);
|
||||||
|
|
||||||
|
void init_paging(void);
|
||||||
|
void paging_map_virtual_to_phys(uint32_t virt, uint32_t phys);
|
||||||
|
|
||||||
|
char* pmalloc(size_t size);
|
||||||
|
void* malloc(size_t size);
|
||||||
|
void free(void *mem);
|
||||||
|
|
||||||
|
void* memcpy(void* dest, const void* src, size_t num);
|
||||||
|
void* memset (void* ptr, int value, size_t num);
|
||||||
|
void* memset16 (void* ptr, uint16_t value, size_t num);
|
||||||
|
|
||||||
|
void print_memory_layout(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
#include <kernel/idt.h>
|
#include <kernel/idt.h>
|
||||||
#include <kernel/interrupt.h>
|
#include <kernel/interrupt.h>
|
||||||
#include <kernel/keyboard.h>
|
#include <kernel/keyboard.h>
|
||||||
|
#include <kernel/memory.h>
|
||||||
|
|
||||||
|
extern uint32_t end;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
TerminalInitialize();
|
TerminalInitialize();
|
||||||
@@ -12,6 +15,34 @@ void main(void) {
|
|||||||
|
|
||||||
RegisterInterruptHandler(IRQ1, KeyboardHandler);
|
RegisterInterruptHandler(IRQ1, KeyboardHandler);
|
||||||
|
|
||||||
|
init_kernel_memory(&end);
|
||||||
|
init_paging();
|
||||||
|
print_memory_layout();
|
||||||
|
|
||||||
|
void* memory1 = malloc(48261);
|
||||||
|
void* memory2 = malloc(27261);
|
||||||
|
void* memory3 = malloc(12617);
|
||||||
|
|
||||||
|
TerminalWriteString("memory1 = ");
|
||||||
|
TerminalWriteHex((uint32_t)memory1);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
|
TerminalWriteString("memory2 = ");
|
||||||
|
TerminalWriteHex((uint32_t)memory2);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
|
TerminalWriteString("memory3 = ");
|
||||||
|
TerminalWriteHex((uint32_t)memory3);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
|
free(memory2);
|
||||||
|
|
||||||
|
void* memory4 = malloc(1000);
|
||||||
|
|
||||||
|
TerminalWriteString("memory4 = ");
|
||||||
|
TerminalWriteHex((uint32_t)memory4);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
__asm__ volatile("hlt");
|
__asm__ volatile("hlt");
|
||||||
}
|
}
|
||||||
|
|||||||
161
src/OSDev_18/src/malloc.c
Normal file
161
src/OSDev_18/src/malloc.c
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
#include <kernel/memory.h>
|
||||||
|
#include <kernel/terminal.h>
|
||||||
|
#include <libc/stdint.h>
|
||||||
|
|
||||||
|
#define MAX_PAGE_ALIGNED_ALLOCS 32
|
||||||
|
|
||||||
|
static uint32_t last_alloc = 0;
|
||||||
|
static uint32_t heap_end = 0;
|
||||||
|
static uint32_t heap_begin = 0;
|
||||||
|
static uint32_t pheap_begin = 0;
|
||||||
|
static uint32_t pheap_end = 0;
|
||||||
|
static uint8_t *pheap_desc = 0;
|
||||||
|
static uint32_t memory_used = 0;
|
||||||
|
|
||||||
|
void init_kernel_memory(uint32_t* kernel_end) {
|
||||||
|
uint32_t kernelEndAddr = (uint32_t)kernel_end;
|
||||||
|
|
||||||
|
last_alloc = kernelEndAddr + 0x1000;
|
||||||
|
heap_begin = last_alloc;
|
||||||
|
pheap_end = 0x400000;
|
||||||
|
pheap_begin = pheap_end - (MAX_PAGE_ALIGNED_ALLOCS * 4096);
|
||||||
|
heap_end = pheap_begin;
|
||||||
|
memset((char*)heap_begin, 0, heap_end - heap_begin);
|
||||||
|
pheap_desc = (uint8_t *)malloc(MAX_PAGE_ALIGNED_ALLOCS);
|
||||||
|
|
||||||
|
TerminalWriteString("Kernel heap starts at 0x");
|
||||||
|
TerminalWriteUInt(last_alloc);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_memory_layout(void) {
|
||||||
|
TerminalWriteString("Memory used:");
|
||||||
|
TerminalWriteUInt(memory_used);
|
||||||
|
TerminalWriteString(" bytes\n");
|
||||||
|
|
||||||
|
TerminalWriteString("Memory free:");
|
||||||
|
TerminalWriteUInt(heap_end - heap_begin - memory_used);
|
||||||
|
TerminalWriteString(" bytes\n");
|
||||||
|
|
||||||
|
TerminalWriteString("Heap size:");
|
||||||
|
TerminalWriteUInt(heap_end - heap_begin);
|
||||||
|
TerminalWriteString(" bytes\n");
|
||||||
|
|
||||||
|
TerminalWriteString("Heap start: ");
|
||||||
|
TerminalWriteHex(heap_begin);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
|
TerminalWriteString("Heap end: ");
|
||||||
|
TerminalWriteHex(heap_end);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
|
TerminalWriteString("PHeap start: ");
|
||||||
|
TerminalWriteHex(pheap_begin);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
|
TerminalWriteString("PHeap end: ");
|
||||||
|
TerminalWriteHex(pheap_end);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *mem) {
|
||||||
|
if (!mem) return;
|
||||||
|
|
||||||
|
alloc_t* alloc = (alloc_t*)((uint8_t*)mem - sizeof(alloc_t));
|
||||||
|
|
||||||
|
if (alloc->status) {
|
||||||
|
memory_used -= alloc->size + sizeof(alloc_t) + 4;
|
||||||
|
alloc->status = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pfree(void *mem) {
|
||||||
|
uint32_t addr = (uint32_t)mem;
|
||||||
|
|
||||||
|
if (addr < pheap_begin || addr >= pheap_end) return;
|
||||||
|
|
||||||
|
addr -= pheap_begin;
|
||||||
|
addr /= 4096;
|
||||||
|
pheap_desc[addr] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* pmalloc(size_t size) {
|
||||||
|
(void) size;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_PAGE_ALIGNED_ALLOCS; i++) {
|
||||||
|
if (pheap_desc[i]) continue;
|
||||||
|
|
||||||
|
pheap_desc[i] = 1;
|
||||||
|
TerminalWriteString("PAllocated from 0x");
|
||||||
|
TerminalWriteUInt(pheap_begin + i * 4096);
|
||||||
|
TerminalWriteString(" to 0x");
|
||||||
|
TerminalWriteUInt(pheap_begin + (i+1) * 4096);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
|
return (char*)(pheap_begin + i * 4096);
|
||||||
|
}
|
||||||
|
TerminalWriteString("pmalloc: FATAL: failure!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* malloc(size_t size) {
|
||||||
|
if(!size) return 0;
|
||||||
|
|
||||||
|
uint8_t* mem = (uint8_t*)heap_begin;
|
||||||
|
|
||||||
|
while ((uint32_t)mem < last_alloc) {
|
||||||
|
alloc_t* a = (alloc_t*)mem;
|
||||||
|
|
||||||
|
if(!a->size) goto nalloc;
|
||||||
|
|
||||||
|
if(a->status) {
|
||||||
|
mem += sizeof(alloc_t) + a->size + 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(a->size >= size) {
|
||||||
|
a->status = 1;
|
||||||
|
memset(mem + sizeof(alloc_t), 0, size);
|
||||||
|
memory_used += a->size + sizeof(alloc_t) + 4;
|
||||||
|
|
||||||
|
TerminalWriteString("Re-allocated ");
|
||||||
|
TerminalWriteUInt(size);
|
||||||
|
TerminalWriteString(" bytes from 0x");
|
||||||
|
TerminalWriteUInt((uint32_t)(mem + sizeof(alloc_t)));
|
||||||
|
TerminalWriteString(" to 0x");
|
||||||
|
TerminalWriteUInt((uint32_t)(mem + sizeof(alloc_t) + size));
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
|
return (char*)(mem + sizeof(alloc_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
mem += a->size + sizeof(alloc_t) + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
nalloc:;
|
||||||
|
if (last_alloc + size + sizeof(alloc_t) + 4 >= heap_end) {
|
||||||
|
TerminalWriteString("Cannot allocate bytes! Out of memory.\n");
|
||||||
|
for (;;) {
|
||||||
|
__asm__ volatile("hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc_t* alloc = (alloc_t*)last_alloc;
|
||||||
|
alloc->status = 1;
|
||||||
|
alloc->size = size;
|
||||||
|
|
||||||
|
last_alloc += size + sizeof(alloc_t) + 4;
|
||||||
|
memory_used += size + 4 + sizeof(alloc_t);
|
||||||
|
|
||||||
|
memset((char *)((uint32_t)alloc + sizeof(alloc_t)), 0, size);
|
||||||
|
|
||||||
|
TerminalWriteString("Allocated ");
|
||||||
|
TerminalWriteUInt(size);
|
||||||
|
TerminalWriteString(" bytes from 0x");
|
||||||
|
TerminalWriteUInt((uint32_t)alloc + sizeof(alloc_t));
|
||||||
|
TerminalWriteString(" to 0x");
|
||||||
|
TerminalWriteUInt(last_alloc);
|
||||||
|
TerminalWriteString("\n");
|
||||||
|
|
||||||
|
return (char*)((uint32_t)alloc + sizeof(alloc_t));
|
||||||
|
}
|
||||||
44
src/OSDev_18/src/memory.c
Normal file
44
src/OSDev_18/src/memory.c
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#include <kernel/memory.h>
|
||||||
|
#include <kernel/terminal.h>
|
||||||
|
#include <libc/stdint.h>
|
||||||
|
|
||||||
|
static uint32_t* page_directory = 0;
|
||||||
|
static uint32_t page_dir_loc = 0;
|
||||||
|
static uint32_t* last_page = 0;
|
||||||
|
|
||||||
|
void paging_map_virtual_to_phys(uint32_t virt, uint32_t phys) {
|
||||||
|
uint16_t id = virt >> 22;
|
||||||
|
|
||||||
|
for(int i = 0; i < 1024; i++) {
|
||||||
|
last_page[i] = phys | 3;
|
||||||
|
phys += 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
page_directory[id] = ((uint32_t)last_page) | 3;
|
||||||
|
last_page = (uint32_t*)(((uint32_t)last_page) + 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
void paging_enable() {
|
||||||
|
asm volatile("mov %%eax, %%cr3": :"a"(page_dir_loc));
|
||||||
|
asm volatile("mov %cr0, %eax");
|
||||||
|
asm volatile("orl $0x80000000, %eax");
|
||||||
|
asm volatile("mov %eax, %cr0");
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_paging(void) {
|
||||||
|
TerminalWriteString("Setting up paging\n");
|
||||||
|
|
||||||
|
page_directory = (uint32_t*)0x400000;
|
||||||
|
page_dir_loc = (uint32_t)page_directory;
|
||||||
|
last_page = (uint32_t*)0x404000;
|
||||||
|
|
||||||
|
for(int i = 0; i < 1024; i++) {
|
||||||
|
page_directory[i] = 0 | 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
paging_map_virtual_to_phys(0, 0);
|
||||||
|
paging_map_virtual_to_phys(0x400000, 0x400000);
|
||||||
|
|
||||||
|
paging_enable();
|
||||||
|
TerminalWriteString("Paging was successfully enabled!\n");
|
||||||
|
}
|
||||||
44
src/OSDev_18/src/memutils.c
Normal file
44
src/OSDev_18/src/memutils.c
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#include <kernel/memory.h>
|
||||||
|
#include <libc/stdint.h>
|
||||||
|
|
||||||
|
void* memcpy(void* dest, const void* src, size_t count ) {
|
||||||
|
char* dst8 = (char*)dest;
|
||||||
|
char* src8 = (char*)src;
|
||||||
|
|
||||||
|
if (count & 1) {
|
||||||
|
dst8[0] = src8[0];
|
||||||
|
dst8 += 1;
|
||||||
|
src8 += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
count /= 2;
|
||||||
|
while (count--) {
|
||||||
|
dst8[0] = src8[0];
|
||||||
|
dst8[1] = src8[1];
|
||||||
|
|
||||||
|
dst8 += 2;
|
||||||
|
src8 += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memset16 (void* ptr, uint16_t value, size_t num) {
|
||||||
|
uint16_t* p = ptr;
|
||||||
|
|
||||||
|
while(num--) {
|
||||||
|
*p++ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memset (void* ptr, int value, size_t num ) {
|
||||||
|
unsigned char* p = ptr;
|
||||||
|
|
||||||
|
while(num--) {
|
||||||
|
*p++ = (unsigned char)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
@@ -116,3 +116,13 @@ void TerminalWriteUInt(uint32_t num) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalWriteHex(uint32_t num) {
|
||||||
|
TerminalWriteString("0x");
|
||||||
|
|
||||||
|
char hexChars[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
for (int i = 28; i >= 0; i -= 4) {
|
||||||
|
uint8_t digit = (num >> i) & 0xF;
|
||||||
|
TerminalPutChar(hexChars[digit]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user