From 293f556a7ec6b88f2b3144c08cbd5f5e5cd98f04 Mon Sep 17 00:00:00 2001 From: Carlos Date: Wed, 1 Apr 2015 15:08:17 +0200 Subject: [PATCH] lesson 22, malloc --- 22-malloc/Makefile | 47 +++++++++++++++++++++++++++++++++++++++ 22-malloc/README.md | 18 +++++++++++++++ 22-malloc/boot | 1 + 22-malloc/cpu | 1 + 22-malloc/drivers | 1 + 22-malloc/kernel/kernel.c | 36 ++++++++++++++++++++++++++++++ 22-malloc/kernel/kernel.h | 6 +++++ 22-malloc/libc/function.h | 1 + 22-malloc/libc/mem.c | 33 +++++++++++++++++++++++++++ 22-malloc/libc/mem.h | 12 ++++++++++ 22-malloc/libc/string.c | 1 + 22-malloc/libc/string.h | 1 + 12 files changed, 158 insertions(+) create mode 100644 22-malloc/Makefile create mode 100644 22-malloc/README.md create mode 120000 22-malloc/boot create mode 120000 22-malloc/cpu create mode 120000 22-malloc/drivers create mode 100644 22-malloc/kernel/kernel.c create mode 100644 22-malloc/kernel/kernel.h create mode 120000 22-malloc/libc/function.h create mode 100644 22-malloc/libc/mem.c create mode 100644 22-malloc/libc/mem.h create mode 120000 22-malloc/libc/string.c create mode 120000 22-malloc/libc/string.h diff --git a/22-malloc/Makefile b/22-malloc/Makefile new file mode 100644 index 0000000..1478294 --- /dev/null +++ b/22-malloc/Makefile @@ -0,0 +1,47 @@ +C_SOURCES = $(wildcard kernel/*.c drivers/*.c cpu/*.c libc/*.c) +HEADERS = $(wildcard kernel/*.h drivers/*.h cpu/*.h libc/*.h) +# Nice syntax for file extension replacement +OBJ = ${C_SOURCES:.c=.o cpu/interrupt.o} + +# Change this if your cross-compiler is somewhere else +CC = /usr/local/i386elfgcc/bin/i386-elf-gcc +GDB = /usr/local/i386elfgcc/bin/i386-elf-gdb +# -g: Use debugging symbols in gcc +CFLAGS = -g -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs \ + -Wall -Wextra -Werror + +# First rule is run by default +os-image.bin: boot/bootsect.bin kernel.bin + cat $^ > os-image.bin + +# '--oformat binary' deletes all symbols as a collateral, so we don't need +# to 'strip' them manually on this case +kernel.bin: boot/kernel_entry.o ${OBJ} + i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary + +# Used for debugging purposes +kernel.elf: boot/kernel_entry.o ${OBJ} + i386-elf-ld -o $@ -Ttext 0x1000 $^ + +run: os-image.bin + qemu-system-i386 -fda os-image.bin + +# Open the connection to qemu and load our kernel-object file with symbols +debug: os-image.bin kernel.elf + qemu-system-i386 -s -fda os-image.bin -d guest_errors,int & + ${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf" + +# Generic rules for wildcards +# To make an object, always compile from its .c +%.o: %.c ${HEADERS} + ${CC} ${CFLAGS} -ffreestanding -c $< -o $@ + +%.o: %.asm + nasm $< -f elf -o $@ + +%.bin: %.asm + nasm $< -f bin -o $@ + +clean: + rm -rf *.bin *.dis *.o os-image.bin *.elf + rm -rf kernel/*.o boot/*.bin drivers/*.o boot/*.o cpu/*.o libc/*.o diff --git a/22-malloc/README.md b/22-malloc/README.md new file mode 100644 index 0000000..299db30 --- /dev/null +++ b/22-malloc/README.md @@ -0,0 +1,18 @@ +*Concepts you may want to Google beforehand: malloc* + +**Goal: Implement a memory allocator** + +We will add a kernel memory allocator to `libc/mem.c`. It is +implemented as a simple pointer to free memory, which keeps +growing. + +The `kmalloc()` function can be used to request an aligned page, +and it will also return the real, physical address, for later use. + +We'll change the `kernel.c` leaving all the "shell" code there, +Let's just try out the new `kmalloc()`, and check out that +our first page starts at 0x10000 (as hardcoded on `mem.c`) and +subsequent `kmalloc()`'s produce a new address which is +aligned 4096 bytes or 0x1000 from the previous one. + +The rest of the files are unchanged from last lesson. diff --git a/22-malloc/boot b/22-malloc/boot new file mode 120000 index 0000000..55cb5d2 --- /dev/null +++ b/22-malloc/boot @@ -0,0 +1 @@ +../21-shell/boot \ No newline at end of file diff --git a/22-malloc/cpu b/22-malloc/cpu new file mode 120000 index 0000000..48a218d --- /dev/null +++ b/22-malloc/cpu @@ -0,0 +1 @@ +../21-shell/cpu \ No newline at end of file diff --git a/22-malloc/drivers b/22-malloc/drivers new file mode 120000 index 0000000..d298ec0 --- /dev/null +++ b/22-malloc/drivers @@ -0,0 +1 @@ +../21-shell/drivers \ No newline at end of file diff --git a/22-malloc/kernel/kernel.c b/22-malloc/kernel/kernel.c new file mode 100644 index 0000000..fd6dc7f --- /dev/null +++ b/22-malloc/kernel/kernel.c @@ -0,0 +1,36 @@ +#include "../cpu/isr.h" +#include "../drivers/screen.h" +#include "kernel.h" +#include "../libc/string.h" +#include "../libc/mem.h" + +void main() { + isr_install(); + irq_install(); + + kprint("Type something, it will go through the kernel\n" + "Type END to halt the CPU or PAGE to request a kmalloc()\n> "); +} + +void user_input(char *input) { + if (strcmp(input, "END") == 0) { + kprint("Stopping the CPU. Bye!\n"); + asm volatile("hlt"); + } else if (strcmp(input, "PAGE") == 0) { + /* Lesson 22: Code to test kmalloc, the rest is unchanged */ + u32 phys_addr; + u32 page = kmalloc(1000, 1, &phys_addr); + char page_str[16]; + int_to_ascii(page, page_str); + char phys_str[16]; + int_to_ascii(phys_addr, phys_str); + kprint("Page: "); + kprint(page_str); + kprint(", physical address: "); + kprint(phys_str); + kprint("\n"); + } + kprint("You said: "); + kprint(input); + kprint("\n> "); +} diff --git a/22-malloc/kernel/kernel.h b/22-malloc/kernel/kernel.h new file mode 100644 index 0000000..1907a2d --- /dev/null +++ b/22-malloc/kernel/kernel.h @@ -0,0 +1,6 @@ +#ifndef KERNEL_H +#define KERNEL_H + +void user_input(char *input); + +#endif diff --git a/22-malloc/libc/function.h b/22-malloc/libc/function.h new file mode 120000 index 0000000..f0807b6 --- /dev/null +++ b/22-malloc/libc/function.h @@ -0,0 +1 @@ +../../21-shell/libc/function.h \ No newline at end of file diff --git a/22-malloc/libc/mem.c b/22-malloc/libc/mem.c new file mode 100644 index 0000000..90f5f70 --- /dev/null +++ b/22-malloc/libc/mem.c @@ -0,0 +1,33 @@ +#include "mem.h" + +void memory_copy(u8 *source, u8 *dest, int nbytes) { + int i; + for (i = 0; i < nbytes; i++) { + *(dest + i) = *(source + i); + } +} + +void memory_set(u8 *dest, u8 val, u32 len) { + u8 *temp = (u8 *)dest; + for ( ; len != 0; len--) *temp++ = val; +} + +/* This should be computed at link time, but a hardcoded + * value is fine for now. Remember that our kernel starts + * at 0x1000 as defined on the Makefile */ +u32 free_mem_addr = 0x10000; +/* Implementation is just a pointer to some free memory which + * keeps growing */ +u32 kmalloc(u32 size, int align, u32 *phys_addr) { + /* Pages are aligned to 4K, or 0x1000 */ + if (align == 1 && (free_mem_addr & 0xFFFFF000)) { + free_mem_addr &= 0xFFFFF000; + free_mem_addr += 0x1000; + } + /* Save also the physical address */ + if (phys_addr) *phys_addr = free_mem_addr; + + u32 ret = free_mem_addr; + free_mem_addr += size; /* Remember to increment the pointer */ + return ret; +} diff --git a/22-malloc/libc/mem.h b/22-malloc/libc/mem.h new file mode 100644 index 0000000..395a527 --- /dev/null +++ b/22-malloc/libc/mem.h @@ -0,0 +1,12 @@ +#ifndef MEM_H +#define MEM_H + +#include "../cpu/types.h" + +void memory_copy(u8 *source, u8 *dest, int nbytes); +void memory_set(u8 *dest, u8 val, u32 len); + +/* At this stage there is no 'free' implemented. */ +u32 kmalloc(u32 size, int align, u32 *phys_addr); + +#endif diff --git a/22-malloc/libc/string.c b/22-malloc/libc/string.c new file mode 120000 index 0000000..1ae6696 --- /dev/null +++ b/22-malloc/libc/string.c @@ -0,0 +1 @@ +../../21-shell/libc/string.c \ No newline at end of file diff --git a/22-malloc/libc/string.h b/22-malloc/libc/string.h new file mode 120000 index 0000000..3b5dadc --- /dev/null +++ b/22-malloc/libc/string.h @@ -0,0 +1 @@ +../../21-shell/libc/string.h \ No newline at end of file