Kernel: add very WIP implementation of initrd
This commit is contained in:
parent
7b912d6abe
commit
e84e4719a4
|
@ -0,0 +1,57 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct initrd_header
|
||||||
|
{
|
||||||
|
unsigned char magic; // The magic number is there to check for consistency.
|
||||||
|
char name[64];
|
||||||
|
unsigned int offset; // Offset in the initrd the file starts.
|
||||||
|
unsigned int length; // Length of the file.
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(char argc, char **argv)
|
||||||
|
{
|
||||||
|
int nheaders = (argc-1)/2;
|
||||||
|
struct initrd_header headers[64];
|
||||||
|
printf("size of header: %d\n", sizeof(struct initrd_header));
|
||||||
|
unsigned int off = sizeof(struct initrd_header) * 64 + sizeof(int);
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < nheaders; i++)
|
||||||
|
{
|
||||||
|
printf("writing file %s->%s at 0x%x\n", argv[i*2+1], argv[i*2+2], off);
|
||||||
|
strcpy(headers[i].name, argv[i*2+2]);
|
||||||
|
headers[i].offset = off;
|
||||||
|
FILE *stream = fopen(argv[i*2+1], "r");
|
||||||
|
if(stream == 0)
|
||||||
|
{
|
||||||
|
printf("Error: file not found: %s\n", argv[i*2+1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fseek(stream, 0, SEEK_END);
|
||||||
|
headers[i].length = ftell(stream);
|
||||||
|
off += headers[i].length;
|
||||||
|
fclose(stream);
|
||||||
|
headers[i].magic = 0xBF;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *wstream = fopen("./initrd.img", "w");
|
||||||
|
unsigned char *data = (unsigned char *)malloc(off);
|
||||||
|
fwrite(&nheaders, sizeof(int), 1, wstream);
|
||||||
|
fwrite(headers, sizeof(struct initrd_header), 64, wstream);
|
||||||
|
|
||||||
|
for(i = 0; i < nheaders; i++)
|
||||||
|
{
|
||||||
|
FILE *stream = fopen(argv[i*2+1], "r");
|
||||||
|
unsigned char *buf = (unsigned char *)malloc(headers[i].length);
|
||||||
|
fread(buf, 1, headers[i].length, stream);
|
||||||
|
fwrite(buf, 1, headers[i].length, wstream);
|
||||||
|
fclose(stream);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(wstream);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
2
iso.sh
2
iso.sh
|
@ -7,9 +7,11 @@ mkdir -p isodir/boot
|
||||||
mkdir -p isodir/boot/grub
|
mkdir -p isodir/boot/grub
|
||||||
|
|
||||||
cp sysroot/boot/orion.kernel isodir/boot/orion.kernel
|
cp sysroot/boot/orion.kernel isodir/boot/orion.kernel
|
||||||
|
cp sysroot/boot/initrd.img isodir/boot/initrd.img
|
||||||
cat > isodir/boot/grub/grub.cfg << EOF
|
cat > isodir/boot/grub/grub.cfg << EOF
|
||||||
menuentry "orion" {
|
menuentry "orion" {
|
||||||
multiboot /boot/orion.kernel
|
multiboot /boot/orion.kernel
|
||||||
|
module /boot/initrd.img
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
grub-mkrescue -o orion.iso isodir
|
grub-mkrescue -o orion.iso isodir
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include <kernel/tty.h>
|
#include <kernel/tty.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -8,8 +9,14 @@
|
||||||
//#include "timer.c"
|
//#include "timer.c"
|
||||||
#include "keyboard.c"
|
#include "keyboard.c"
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
|
//#include "fs.c"
|
||||||
|
#include "initrd.c"
|
||||||
|
#include "multiboot.h"
|
||||||
|
|
||||||
void kernel_early_main(void) {
|
extern heap_t *kheap;
|
||||||
|
extern fs_node_t *fs_root; // The root of the filesystem.
|
||||||
|
|
||||||
|
void kernel_early_main(struct multiboot *mboot_ptr) {
|
||||||
gdt_init();
|
gdt_init();
|
||||||
init_serial();
|
init_serial();
|
||||||
serial_printf("gdt initialized!\n");
|
serial_printf("gdt initialized!\n");
|
||||||
|
@ -17,9 +24,25 @@ void kernel_early_main(void) {
|
||||||
serial_printf("idt initialized!\n");
|
serial_printf("idt initialized!\n");
|
||||||
//init_timer(50); // Initialise timer to 50Hz
|
//init_timer(50); // Initialise timer to 50Hz
|
||||||
//serial_printf("timer initialized!\n");
|
//serial_printf("timer initialized!\n");
|
||||||
|
|
||||||
|
// Find the location of our initial ramdisk.
|
||||||
|
//assert(mboot_ptr->mods_count > 0);
|
||||||
|
if (!(mboot_ptr->mods_count > 0)) {
|
||||||
|
serial_printf("PANIC!!");
|
||||||
|
}
|
||||||
|
uint32_t initrd_location = *((uint32_t*)mboot_ptr->mods_addr);
|
||||||
|
uint32_t initrd_end = *(uint32_t*)(mboot_ptr->mods_addr+4);
|
||||||
|
// Don't trample our module with placement accesses, please!
|
||||||
|
placement_address = initrd_end;
|
||||||
|
|
||||||
init_paging();
|
init_paging();
|
||||||
serial_printf("paging initialized!\n");
|
serial_printf("paging initialized!\n");
|
||||||
|
//open_fs(fs_root, 1, 0);
|
||||||
|
fs_root = init_initrd(initrd_location);
|
||||||
|
serial_printf("initrd!\n");
|
||||||
init_keyboard();
|
init_keyboard();
|
||||||
serial_printf("keyboard initialized!\n");
|
serial_printf("keyboard initialized!\n");
|
||||||
terminal_initialize();
|
terminal_initialize(); // FIXME
|
||||||
|
int a = kmalloc(23); // FIXME
|
||||||
|
free(a, kheap);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
typedef uint32_t (*read_type_t)(struct fs_node*,uint32_t,uint32_t,uint8_t*);
|
||||||
|
typedef uint32_t (*write_type_t)(struct fs_node*,uint32_t,uint32_t,uint8_t*);
|
||||||
|
typedef void (*open_type_t)(struct fs_node*);
|
||||||
|
typedef void (*close_type_t)(struct fs_node*);
|
||||||
|
typedef struct dirent * (*readdir_type_t)(struct fs_node*,uint32_t);
|
||||||
|
typedef struct fs_node * (*finddir_type_t)(struct fs_node*,char *name);
|
||||||
|
|
||||||
|
typedef struct fs_node
|
||||||
|
{
|
||||||
|
char name[128]; // The filename.
|
||||||
|
uint32_t mask; // The permissions mask.
|
||||||
|
uint32_t uid; // The owning user.
|
||||||
|
uint32_t gid; // The owning group.
|
||||||
|
uint32_t flags; // Includes the node type. See #defines above.
|
||||||
|
uint32_t inode; // This is device-specific - provides a way for a filesystem to identify files.
|
||||||
|
uint32_t length; // Size of the file, in bytes.
|
||||||
|
uint32_t impl; // An implementation-defined number.
|
||||||
|
read_type_t read;
|
||||||
|
write_type_t write;
|
||||||
|
open_type_t open;
|
||||||
|
close_type_t close;
|
||||||
|
readdir_type_t readdir;
|
||||||
|
finddir_type_t finddir;
|
||||||
|
struct fs_node *ptr; // Used by mountpoints and symlinks.
|
||||||
|
} fs_node_t;
|
||||||
|
|
||||||
|
struct dirent // One of these is returned by the readdir call, according to POSIX.
|
||||||
|
{
|
||||||
|
char name[128]; // Filename.
|
||||||
|
uint32_t ino; // Inode number. Required by POSIX.
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FS_FILE 0x01
|
||||||
|
#define FS_DIRECTORY 0x02
|
||||||
|
#define FS_CHARDEVICE 0x03
|
||||||
|
#define FS_BLOCKDEVICE 0x04
|
||||||
|
#define FS_PIPE 0x05
|
||||||
|
#define FS_SYMLINK 0x06
|
||||||
|
#define FS_MOUNTPOINT 0x08
|
||||||
|
|
||||||
|
//extern fs_node_t *fs_root; // The root of the filesystem.
|
||||||
|
|
||||||
|
// Standard read/write/open/close functions. Note that these are all suffixed with
|
||||||
|
// _fs to distinguish them from the read/write/open/close which deal with file descriptors
|
||||||
|
// not file nodes.
|
||||||
|
//uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
|
||||||
|
//uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
|
||||||
|
//void open_fs(fs_node_t *node, uint8_t read, uint8_t write);
|
||||||
|
//void close_fs(fs_node_t *node);
|
||||||
|
//struct dirent *readdir_fs(fs_node_t *node, uint32_t index);
|
||||||
|
//fs_node_t *finddir_fs(fs_node_t *node, char *name);
|
||||||
|
|
||||||
|
fs_node_t *fs_root = 0; // The root of the filesystem.
|
||||||
|
|
||||||
|
uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer)
|
||||||
|
{
|
||||||
|
// Has the node got a read callback?
|
||||||
|
if (node->read != 0)
|
||||||
|
return node->read(node, offset, size, buffer);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer)
|
||||||
|
{
|
||||||
|
// Has the node got a write callback?
|
||||||
|
if (node->write != 0)
|
||||||
|
return node->write(node, offset, size, buffer);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void open_fs(fs_node_t *node, uint8_t read, uint8_t write)
|
||||||
|
{
|
||||||
|
// Has the node got an open callback?
|
||||||
|
if (node->open != 0)
|
||||||
|
return node->open(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_fs(fs_node_t *node)
|
||||||
|
{
|
||||||
|
// Has the node got a close callback?
|
||||||
|
if (node->close != 0)
|
||||||
|
return node->close(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent *readdir_fs(fs_node_t *node, uint32_t index)
|
||||||
|
{
|
||||||
|
// Is the node a directory, and does it have a callback?
|
||||||
|
if ( (node->flags&0x7) == FS_DIRECTORY &&
|
||||||
|
node->readdir != 0 )
|
||||||
|
return node->readdir(node, index);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_node_t *finddir_fs(fs_node_t *node, char *name)
|
||||||
|
{
|
||||||
|
// Is the node a directory, and does it have a callback?
|
||||||
|
if ( (node->flags&0x7) == FS_DIRECTORY &&
|
||||||
|
node->finddir != 0 )
|
||||||
|
return node->finddir(node, name);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include "fs.c"
|
||||||
|
#include "kheap.c"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t nfiles; // The number of files in the ramdisk.
|
||||||
|
} initrd_header_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t magic; // Magic number, for error checking.
|
||||||
|
int8_t name[64]; // Filename.
|
||||||
|
uint32_t offset; // Offset in the initrd that the file starts.
|
||||||
|
uint32_t length; // Length of the file.
|
||||||
|
} initrd_file_header_t;
|
||||||
|
|
||||||
|
// Initialises the initial ramdisk. It gets passed the address of the multiboot module,
|
||||||
|
// and returns a completed filesystem node.
|
||||||
|
fs_node_t *initialise_initrd(uint32_t location);
|
||||||
|
|
||||||
|
initrd_header_t *initrd_header; // The header.
|
||||||
|
initrd_file_header_t *file_headers; // The list of file headers.
|
||||||
|
fs_node_t *initrd_root; // Our root directory node.
|
||||||
|
fs_node_t *initrd_dev; // We also add a directory node for /dev, so we can mount devfs later on.
|
||||||
|
fs_node_t *root_nodes; // List of file nodes.
|
||||||
|
int nroot_nodes; // Number of file nodes.
|
||||||
|
|
||||||
|
struct dirent dirent;
|
||||||
|
|
||||||
|
static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer)
|
||||||
|
{
|
||||||
|
initrd_file_header_t header = file_headers[node->inode];
|
||||||
|
if (offset > header.length)
|
||||||
|
return 0;
|
||||||
|
if (offset+size > header.length)
|
||||||
|
size = header.length-offset;
|
||||||
|
memcpy(buffer, (uint8_t*) (header.offset+offset), size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index)
|
||||||
|
{
|
||||||
|
if (node == initrd_root && index == 0)
|
||||||
|
{
|
||||||
|
strcpy(dirent.name, "dev");
|
||||||
|
dirent.name[3] = 0; // Make sure the string is NULL-terminated.
|
||||||
|
dirent.ino = 0;
|
||||||
|
return &dirent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index-1 >= nroot_nodes)
|
||||||
|
return 0;
|
||||||
|
strcpy(dirent.name, root_nodes[index-1].name);
|
||||||
|
dirent.name[strlen(root_nodes[index-1].name)] = 0; // Make sure the string is NULL-terminated.
|
||||||
|
dirent.ino = root_nodes[index-1].inode;
|
||||||
|
return &dirent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fs_node_t *initrd_finddir(fs_node_t *node, char *name)
|
||||||
|
{
|
||||||
|
if (node == initrd_root &&
|
||||||
|
!strcmp(name, "dev") )
|
||||||
|
return initrd_dev;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < nroot_nodes; i++)
|
||||||
|
if (!strcmp(name, root_nodes[i].name))
|
||||||
|
return &root_nodes[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_node_t *init_initrd(uint32_t location)
|
||||||
|
{
|
||||||
|
// Initialise the main and file header pointers and populate the root directory.
|
||||||
|
initrd_header = (initrd_header_t *)location;
|
||||||
|
file_headers = (initrd_file_header_t *) (location+sizeof(initrd_header_t));
|
||||||
|
|
||||||
|
// Initialise the root directory.
|
||||||
|
initrd_root = (fs_node_t*)kmalloc(sizeof(fs_node_t));
|
||||||
|
strcpy(initrd_root->name, "initrd");
|
||||||
|
initrd_root->mask = initrd_root->uid = initrd_root->gid = initrd_root->inode = initrd_root->length = 0;
|
||||||
|
initrd_root->flags = FS_DIRECTORY;
|
||||||
|
initrd_root->read = 0;
|
||||||
|
initrd_root->write = 0;
|
||||||
|
initrd_root->open = 0;
|
||||||
|
initrd_root->close = 0;
|
||||||
|
initrd_root->readdir = &initrd_readdir;
|
||||||
|
initrd_root->finddir = &initrd_finddir;
|
||||||
|
initrd_root->ptr = 0;
|
||||||
|
initrd_root->impl = 0;
|
||||||
|
|
||||||
|
// Initialise the /dev directory (required!)
|
||||||
|
initrd_dev = (fs_node_t*)kmalloc(sizeof(fs_node_t));
|
||||||
|
strcpy(initrd_dev->name, "dev");
|
||||||
|
initrd_dev->mask = initrd_dev->uid = initrd_dev->gid = initrd_dev->inode = initrd_dev->length = 0;
|
||||||
|
initrd_dev->flags = FS_DIRECTORY;
|
||||||
|
initrd_dev->read = 0;
|
||||||
|
initrd_dev->write = 0;
|
||||||
|
initrd_dev->open = 0;
|
||||||
|
initrd_dev->close = 0;
|
||||||
|
initrd_dev->readdir = &initrd_readdir;
|
||||||
|
initrd_dev->finddir = &initrd_finddir;
|
||||||
|
initrd_dev->ptr = 0;
|
||||||
|
initrd_dev->impl = 0;
|
||||||
|
|
||||||
|
root_nodes = (fs_node_t*)kmalloc(sizeof(fs_node_t) * initrd_header->nfiles);
|
||||||
|
nroot_nodes = initrd_header->nfiles;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < initrd_header->nfiles; i++)
|
||||||
|
{
|
||||||
|
// Edit the file's header - currently it holds the file offset
|
||||||
|
// relative to the start of the ramdisk. We want it relative to the start
|
||||||
|
// of memory.
|
||||||
|
file_headers[i].offset += location;
|
||||||
|
// Create a new file node.
|
||||||
|
strcpy(root_nodes[i].name, &file_headers[i].name);
|
||||||
|
root_nodes[i].mask = root_nodes[i].uid = root_nodes[i].gid = 0;
|
||||||
|
root_nodes[i].length = file_headers[i].length;
|
||||||
|
root_nodes[i].inode = i;
|
||||||
|
root_nodes[i].flags = FS_FILE;
|
||||||
|
root_nodes[i].read = &initrd_read;
|
||||||
|
root_nodes[i].write = 0;
|
||||||
|
root_nodes[i].readdir = 0;
|
||||||
|
root_nodes[i].finddir = 0;
|
||||||
|
root_nodes[i].open = 0;
|
||||||
|
root_nodes[i].close = 0;
|
||||||
|
root_nodes[i].impl = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return initrd_root;
|
||||||
|
}
|
|
@ -1,5 +1,44 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
//#include "fs.c"
|
||||||
|
//#include "initrd.c"
|
||||||
|
|
||||||
|
|
||||||
|
typedef uint32_t (*read_type_t)(struct fs_node*,uint32_t,uint32_t,uint8_t*);
|
||||||
|
typedef uint32_t (*write_type_t)(struct fs_node*,uint32_t,uint32_t,uint8_t*);
|
||||||
|
typedef void (*open_type_t)(struct fs_node*);
|
||||||
|
typedef void (*close_type_t)(struct fs_node*);
|
||||||
|
typedef struct dirent * (*readdir_type_t)(struct fs_node*,uint32_t);
|
||||||
|
typedef struct fs_node * (*finddir_type_t)(struct fs_node*,char *name);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct fs_node
|
||||||
|
{
|
||||||
|
char name[128]; // The filename.
|
||||||
|
uint32_t mask; // The permissions mask.
|
||||||
|
uint32_t uid; // The owning user.
|
||||||
|
uint32_t gid; // The owning group.
|
||||||
|
uint32_t flags; // Includes the node type. See #defines above.
|
||||||
|
uint32_t inode; // This is device-specific - provides a way for a filesystem to identify files.
|
||||||
|
uint32_t length; // Size of the file, in bytes.
|
||||||
|
uint32_t impl; // An implementation-defined number.
|
||||||
|
read_type_t read;
|
||||||
|
write_type_t write;
|
||||||
|
open_type_t open;
|
||||||
|
close_type_t close;
|
||||||
|
readdir_type_t readdir;
|
||||||
|
finddir_type_t finddir;
|
||||||
|
struct fs_node *ptr; // Used by mountpoints and symlinks.
|
||||||
|
} fs_node_t;
|
||||||
|
|
||||||
|
struct dirent // One of these is returned by the readdir call, according to POSIX.
|
||||||
|
{
|
||||||
|
char name[128]; // Filename.
|
||||||
|
uint32_t ino; // Inode number. Required by POSIX.
|
||||||
|
};
|
||||||
|
|
||||||
|
extern fs_node_t *fs_root; // The root of the filesystem.
|
||||||
|
|
||||||
void kernel_main(void) {
|
void kernel_main(void) {
|
||||||
printf("Hello from OrionOS!\n");
|
printf("Hello from OrionOS!\n");
|
||||||
|
@ -10,9 +49,37 @@ void kernel_main(void) {
|
||||||
serial_printf("This is string from variable: %s\n", test_string);
|
serial_printf("This is string from variable: %s\n", test_string);
|
||||||
printf("Test finished success!\n");
|
printf("Test finished success!\n");
|
||||||
asm volatile("sti");
|
asm volatile("sti");
|
||||||
uint32_t *ptr = (uint32_t*)0xA0000000;
|
|
||||||
uint32_t do_page_fault = *ptr;
|
// list the contents of /
|
||||||
printf("%s", do_page_fault);
|
int i = 0;
|
||||||
|
struct dirent *node = 0;
|
||||||
|
while ( (node = readdir_fs(fs_root, i)) != 0)
|
||||||
|
{
|
||||||
|
serial_printf("Found file %s", node->name);
|
||||||
|
fs_node_t *fsnode = finddir_fs(fs_root, node->name);
|
||||||
|
|
||||||
|
if ((fsnode->flags&0x7) == 0x02)//FS_DIRECTORY)
|
||||||
|
serial_printf("\n\t(directory)\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("\n\t contents: \"");
|
||||||
|
char buf[256];
|
||||||
|
uint32_t sz = read_fs(fsnode, 0, 256, buf);
|
||||||
|
uint32_t j;
|
||||||
|
for (j = 0; j < sz; j++)
|
||||||
|
serial_printf("%c", buf[j]);
|
||||||
|
|
||||||
|
serial_printf("\"\n");
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
//printf("%x\n", 0x0);
|
||||||
|
//printf("%x\n", a);
|
||||||
|
printf("%x");
|
||||||
|
/*for (int i = 0; i < 1000; i++) {
|
||||||
|
printf("A: %c\n", i);
|
||||||
|
}*/
|
||||||
|
close_fs(fs_root);
|
||||||
for(;;) {
|
for(;;) {
|
||||||
asm("hlt");
|
asm("hlt");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,365 @@
|
||||||
|
#include "ordered_map.c"
|
||||||
|
|
||||||
|
extern uint32_t page_directory[1024];
|
||||||
|
|
||||||
|
#define KHEAP_START 0xC0000000
|
||||||
|
#define KHEAP_INITIAL_SIZE 0x100000
|
||||||
|
#define HEAP_INDEX_SIZE 0x20000
|
||||||
|
#define HEAP_MAGIC 0x123890AB
|
||||||
|
#define HEAP_MIN_SIZE 0x70000
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t magic; // Magic number, used for error checking and identification.
|
||||||
|
uint8_t is_hole; // 1 if this is a hole. 0 if this is a block.
|
||||||
|
uint32_t size; // size of the block, including the end footer.
|
||||||
|
} header_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t magic; // Magic number, same as in header_t.
|
||||||
|
header_t *header; // Pointer to the block header.
|
||||||
|
} footer_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ordered_array_t index;
|
||||||
|
uint32_t start_address; // The start of our allocated space.
|
||||||
|
uint32_t end_address; // The end of our allocated space. May be expanded up to max_address.
|
||||||
|
uint32_t max_address; // The maximum address the heap can be expanded to.
|
||||||
|
uint8_t supervisor; // Should extra pages requested by us be mapped as supervisor-only?
|
||||||
|
uint8_t readonly; // Should extra pages requested by us be mapped as read-only?
|
||||||
|
} heap_t;
|
||||||
|
|
||||||
|
heap_t *kheap;
|
||||||
|
|
||||||
|
static int32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap)
|
||||||
|
{
|
||||||
|
// Find the smallest hole that will fit.
|
||||||
|
uint32_t iterator = 0;
|
||||||
|
while (iterator < heap->index.size)
|
||||||
|
{
|
||||||
|
header_t *header = (header_t *)lookup_ordered_array(iterator, &heap->index);
|
||||||
|
// If the user has requested the memory be page-aligned
|
||||||
|
if (page_align > 0)
|
||||||
|
{
|
||||||
|
// Page-align the starting point of this header.
|
||||||
|
uint32_t location = (uint32_t)header;
|
||||||
|
int32_t offset = 0;
|
||||||
|
if (((location+sizeof(header_t)) & 0xFFFFF000) != 0)
|
||||||
|
offset = 0x1000 /* page size */ - (location+sizeof(header_t))%0x1000;
|
||||||
|
int32_t hole_size = (int32_t)header->size - offset;
|
||||||
|
// Can we fit now?
|
||||||
|
if (hole_size >= (int32_t)size)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (header->size >= size)
|
||||||
|
break;
|
||||||
|
iterator++;
|
||||||
|
}
|
||||||
|
// Why did the loop exit?
|
||||||
|
if (iterator == heap->index.size)
|
||||||
|
return -1; // We got to the end and didn't find anything.
|
||||||
|
else
|
||||||
|
return iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int8_t header_t_less_than(void*a, void *b)
|
||||||
|
{
|
||||||
|
return (((header_t*)a)->size < ((header_t*)b)->size)?1:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_t *create_heap(uint32_t start, uint32_t end_addr, uint32_t max, uint8_t supervisor, uint8_t readonly)
|
||||||
|
{
|
||||||
|
heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t));
|
||||||
|
|
||||||
|
// All our assumptions are made on startAddress and endAddress being page-aligned.
|
||||||
|
assert(start%0x1000 == 0);
|
||||||
|
assert(end_addr%0x1000 == 0);
|
||||||
|
|
||||||
|
// Initialise the index.
|
||||||
|
heap->index = place_ordered_array( (void*)start, HEAP_INDEX_SIZE, &header_t_less_than);
|
||||||
|
|
||||||
|
// Shift the start address forward to resemble where we can start putting data.
|
||||||
|
start += sizeof(type_t)*HEAP_INDEX_SIZE;
|
||||||
|
|
||||||
|
// Make sure the start address is page-aligned.
|
||||||
|
if ((start & 0xFFFFF000) != 0)
|
||||||
|
{
|
||||||
|
start &= 0xFFFFF000;
|
||||||
|
start += 0x1000;
|
||||||
|
}
|
||||||
|
// Write the start, end and max addresses into the heap structure.
|
||||||
|
heap->start_address = start;
|
||||||
|
heap->end_address = end_addr;
|
||||||
|
heap->max_address = max;
|
||||||
|
heap->supervisor = supervisor;
|
||||||
|
heap->readonly = readonly;
|
||||||
|
|
||||||
|
// We start off with one large hole in the index.
|
||||||
|
header_t *hole = (header_t *)start;
|
||||||
|
hole->size = end_addr-start;
|
||||||
|
hole->magic = HEAP_MAGIC;
|
||||||
|
hole->is_hole = 1;
|
||||||
|
insert_ordered_array((void*)hole, &heap->index);
|
||||||
|
|
||||||
|
return heap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expand(uint32_t new_size, heap_t *heap)
|
||||||
|
{
|
||||||
|
// Sanity check.
|
||||||
|
assert(new_size > heap->end_address - heap->start_address);
|
||||||
|
// Get the nearest following page boundary.
|
||||||
|
if ((new_size&0xFFFFF000) != 0)
|
||||||
|
{
|
||||||
|
new_size &= 0xFFFFF000;
|
||||||
|
new_size += 0x1000;
|
||||||
|
}
|
||||||
|
// Make sure we are not overreaching ourselves.
|
||||||
|
assert(heap->start_address+new_size <= heap->max_address);
|
||||||
|
|
||||||
|
// This should always be on a page boundary.
|
||||||
|
uint32_t old_size = heap->end_address-heap->start_address;
|
||||||
|
uint32_t i = old_size;
|
||||||
|
while (i < new_size)
|
||||||
|
{
|
||||||
|
alloc_frame( get_page(heap->start_address+i, 1, /*kernel*/page_directory),
|
||||||
|
(heap->supervisor)?1:0, (heap->readonly)?0:1);
|
||||||
|
i += 0x1000 /* page size */;
|
||||||
|
}
|
||||||
|
heap->end_address = heap->start_address+new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t contract(uint32_t new_size, heap_t *heap)
|
||||||
|
{
|
||||||
|
// Sanity check.
|
||||||
|
assert(new_size < heap->end_address-heap->start_address);
|
||||||
|
// Get the nearest following page boundary.
|
||||||
|
if (new_size&0x1000)
|
||||||
|
{
|
||||||
|
new_size &= 0x1000;
|
||||||
|
new_size += 0x1000;
|
||||||
|
}
|
||||||
|
// Don't contract too far!
|
||||||
|
if (new_size < HEAP_MIN_SIZE)
|
||||||
|
new_size = HEAP_MIN_SIZE;
|
||||||
|
uint32_t old_size = heap->end_address-heap->start_address;
|
||||||
|
uint32_t i = old_size - 0x1000;
|
||||||
|
while (new_size < i)
|
||||||
|
{
|
||||||
|
free_frame(get_page(heap->start_address+i, 0, /*kernel*/page_directory));
|
||||||
|
i -= 0x1000;
|
||||||
|
}
|
||||||
|
heap->end_address = heap->start_address + new_size;
|
||||||
|
return new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Make sure we take the size of header/footer into account.
|
||||||
|
uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t);
|
||||||
|
// Find the smallest hole that will fit.
|
||||||
|
int32_t iterator = find_smallest_hole(new_size, page_align, heap);
|
||||||
|
|
||||||
|
if (iterator == -1) // If we didn't find a suitable hole
|
||||||
|
{
|
||||||
|
// Save some previous data.
|
||||||
|
uint32_t old_length = heap->end_address - heap->start_address;
|
||||||
|
uint32_t old_end_address = heap->end_address;
|
||||||
|
|
||||||
|
// We need to allocate some more space.
|
||||||
|
expand(old_length+new_size, heap);
|
||||||
|
uint32_t new_length = heap->end_address-heap->start_address;
|
||||||
|
|
||||||
|
// Find the endmost header. (Not endmost in size, but in location).
|
||||||
|
iterator = 0;
|
||||||
|
// Vars to hold the index of, and value of, the endmost header found so far.
|
||||||
|
uint32_t idx = -1; uint32_t value = 0x0;
|
||||||
|
while (iterator < heap->index.size)
|
||||||
|
{
|
||||||
|
uint32_t tmp = (uint32_t)lookup_ordered_array(iterator, &heap->index);
|
||||||
|
if (tmp > value)
|
||||||
|
{
|
||||||
|
value = tmp;
|
||||||
|
idx = iterator;
|
||||||
|
}
|
||||||
|
iterator++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find ANY headers, we need to add one.
|
||||||
|
if (idx == -1)
|
||||||
|
{
|
||||||
|
header_t *header = (header_t *)old_end_address;
|
||||||
|
header->magic = HEAP_MAGIC;
|
||||||
|
header->size = new_length - old_length;
|
||||||
|
header->is_hole = 1;
|
||||||
|
footer_t *footer = (footer_t *) (old_end_address + header->size - sizeof(footer_t));
|
||||||
|
footer->magic = HEAP_MAGIC;
|
||||||
|
footer->header = header;
|
||||||
|
insert_ordered_array((void*)header, &heap->index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The last header needs adjusting.
|
||||||
|
header_t *header = lookup_ordered_array(idx, &heap->index);
|
||||||
|
header->size += new_length - old_length;
|
||||||
|
// Rewrite the footer.
|
||||||
|
footer_t *footer = (footer_t *) ( (uint32_t)header + header->size - sizeof(footer_t) );
|
||||||
|
footer->header = header;
|
||||||
|
footer->magic = HEAP_MAGIC;
|
||||||
|
}
|
||||||
|
// We now have enough space. Recurse, and call the function again.
|
||||||
|
return alloc(size, page_align, heap);
|
||||||
|
}
|
||||||
|
header_t *orig_hole_header = (header_t *)lookup_ordered_array(iterator, &heap->index);
|
||||||
|
uint32_t orig_hole_pos = (uint32_t)orig_hole_header;
|
||||||
|
uint32_t orig_hole_size = orig_hole_header->size;
|
||||||
|
// Here we work out if we should split the hole we found into two parts.
|
||||||
|
// Is the original hole size - requested hole size less than the overhead for adding a new hole?
|
||||||
|
if (orig_hole_size-new_size < sizeof(header_t)+sizeof(footer_t))
|
||||||
|
{
|
||||||
|
// Then just increase the requested size to the size of the hole we found.
|
||||||
|
size += orig_hole_size-new_size;
|
||||||
|
new_size = orig_hole_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we need to page-align the data, do it now and make a new hole in front of our block.
|
||||||
|
if (page_align && orig_hole_pos & 0xFFFFF000)
|
||||||
|
{
|
||||||
|
uint32_t new_location = orig_hole_pos + 0x1000 /* page size */ - (orig_hole_pos&0xFFF) - sizeof(header_t);
|
||||||
|
header_t *hole_header = (header_t *)orig_hole_pos;
|
||||||
|
hole_header->size = 0x1000 /* page size */ - (orig_hole_pos&0xFFF) - sizeof(header_t);
|
||||||
|
hole_header->magic = HEAP_MAGIC;
|
||||||
|
hole_header->is_hole = 1;
|
||||||
|
footer_t *hole_footer = (footer_t *) ( (uint32_t)new_location - sizeof(footer_t) );
|
||||||
|
hole_footer->magic = HEAP_MAGIC;
|
||||||
|
hole_footer->header = hole_header;
|
||||||
|
orig_hole_pos = new_location;
|
||||||
|
orig_hole_size = orig_hole_size - hole_header->size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Else we don't need this hole any more, delete it from the index.
|
||||||
|
remove_ordered_array(iterator, &heap->index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite the original header...
|
||||||
|
header_t *block_header = (header_t *)orig_hole_pos;
|
||||||
|
block_header->magic = HEAP_MAGIC;
|
||||||
|
block_header->is_hole = 0;
|
||||||
|
block_header->size = new_size;
|
||||||
|
// ...And the footer
|
||||||
|
footer_t *block_footer = (footer_t *) (orig_hole_pos + sizeof(header_t) + size);
|
||||||
|
block_footer->magic = HEAP_MAGIC;
|
||||||
|
block_footer->header = block_header;
|
||||||
|
|
||||||
|
// We may need to write a new hole after the allocated block.
|
||||||
|
// We do this only if the new hole would have positive size...
|
||||||
|
if (orig_hole_size - new_size > 0)
|
||||||
|
{
|
||||||
|
header_t *hole_header = (header_t *) (orig_hole_pos + sizeof(header_t) + size + sizeof(footer_t));
|
||||||
|
hole_header->magic = HEAP_MAGIC;
|
||||||
|
hole_header->is_hole = 1;
|
||||||
|
hole_header->size = orig_hole_size - new_size;
|
||||||
|
footer_t *hole_footer = (footer_t *) ( (uint32_t)hole_header + orig_hole_size - new_size - sizeof(footer_t) );
|
||||||
|
if ((uint32_t)hole_footer < heap->end_address)
|
||||||
|
{
|
||||||
|
hole_footer->magic = HEAP_MAGIC;
|
||||||
|
hole_footer->header = hole_header;
|
||||||
|
}
|
||||||
|
// Put the new hole in the index;
|
||||||
|
insert_ordered_array((void*)hole_header, &heap->index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *) ( (uint32_t)block_header+sizeof(header_t) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *p, heap_t *heap)
|
||||||
|
{
|
||||||
|
// Exit gracefully for null pointers.
|
||||||
|
if (p == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get the header and footer associated with this pointer.
|
||||||
|
header_t *header = (header_t*) ( (uint32_t)p - sizeof(header_t) );
|
||||||
|
footer_t *footer = (footer_t*) ( (uint32_t)header + header->size - sizeof(footer_t) );
|
||||||
|
|
||||||
|
// Sanity checks.
|
||||||
|
assert(header->magic == HEAP_MAGIC);
|
||||||
|
assert(footer->magic == HEAP_MAGIC);
|
||||||
|
|
||||||
|
// Make us a hole.
|
||||||
|
header->is_hole = 1;
|
||||||
|
|
||||||
|
// Do we want to add this header into the 'free holes' index?
|
||||||
|
char do_add = 1;
|
||||||
|
|
||||||
|
// Unify left
|
||||||
|
// If the thing immediately to the left of us is a footer...
|
||||||
|
footer_t *test_footer = (footer_t*) ( (uint32_t)header - sizeof(footer_t) );
|
||||||
|
if (test_footer->magic == HEAP_MAGIC &&
|
||||||
|
test_footer->header->is_hole == 1)
|
||||||
|
{
|
||||||
|
uint32_t cache_size = header->size; // Cache our current size.
|
||||||
|
header = test_footer->header; // Rewrite our header with the new one.
|
||||||
|
footer->header = header; // Rewrite our footer to point to the new header.
|
||||||
|
header->size += cache_size; // Change the size.
|
||||||
|
do_add = 0; // Since this header is already in the index, we don't want to add it again.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unify right
|
||||||
|
// If the thing immediately to the right of us is a header...
|
||||||
|
header_t *test_header = (header_t*) ( (uint32_t)footer + sizeof(footer_t) );
|
||||||
|
if (test_header->magic == HEAP_MAGIC &&
|
||||||
|
test_header->is_hole)
|
||||||
|
{
|
||||||
|
header->size += test_header->size; // Increase our size.
|
||||||
|
test_footer = (footer_t*) ( (uint32_t)test_header + // Rewrite it's footer to point to our header.
|
||||||
|
test_header->size - sizeof(footer_t) );
|
||||||
|
footer = test_footer;
|
||||||
|
// Find and remove this header from the index.
|
||||||
|
uint32_t iterator = 0;
|
||||||
|
while ( (iterator < heap->index.size) &&
|
||||||
|
(lookup_ordered_array(iterator, &heap->index) != (void*)test_header) )
|
||||||
|
iterator++;
|
||||||
|
|
||||||
|
// Make sure we actually found the item.
|
||||||
|
assert(iterator < heap->index.size);
|
||||||
|
// Remove it.
|
||||||
|
remove_ordered_array(iterator, &heap->index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the footer location is the end address, we can contract.
|
||||||
|
if ( (uint32_t)footer+sizeof(footer_t) == heap->end_address)
|
||||||
|
{
|
||||||
|
uint32_t old_length = heap->end_address-heap->start_address;
|
||||||
|
uint32_t new_length = contract( (uint32_t)header - heap->start_address, heap);
|
||||||
|
// Check how big we will be after resizing.
|
||||||
|
if (header->size - (old_length-new_length) > 0)
|
||||||
|
{
|
||||||
|
// We will still exist, so resize us.
|
||||||
|
header->size -= old_length-new_length;
|
||||||
|
footer = (footer_t*) ( (uint32_t)header + header->size - sizeof(footer_t) );
|
||||||
|
footer->magic = HEAP_MAGIC;
|
||||||
|
footer->header = header;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We will no longer exist :(. Remove us from the index.
|
||||||
|
uint32_t iterator = 0;
|
||||||
|
while ( (iterator < heap->index.size) &&
|
||||||
|
(lookup_ordered_array(iterator, &heap->index) != (void*)test_header) )
|
||||||
|
iterator++;
|
||||||
|
// If we didn't find ourselves, we have nothing to remove.
|
||||||
|
if (iterator < heap->index.size)
|
||||||
|
remove_ordered_array(iterator, &heap->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (do_add == 1)
|
||||||
|
insert_ordered_array((void*) header, &heap->index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
#define MULTIBOOT_FLAG_MEM 0x001
|
||||||
|
#define MULTIBOOT_FLAG_DEVICE 0x002
|
||||||
|
#define MULTIBOOT_FLAG_CMDLINE 0x004
|
||||||
|
#define MULTIBOOT_FLAG_MODS 0x008
|
||||||
|
#define MULTIBOOT_FLAG_AOUT 0x010
|
||||||
|
#define MULTIBOOT_FLAG_ELF 0x020
|
||||||
|
#define MULTIBOOT_FLAG_MMAP 0x040
|
||||||
|
#define MULTIBOOT_FLAG_CONFIG 0x080
|
||||||
|
#define MULTIBOOT_FLAG_LOADER 0x100
|
||||||
|
#define MULTIBOOT_FLAG_APM 0x200
|
||||||
|
#define MULTIBOOT_FLAG_VBE 0x400
|
||||||
|
|
||||||
|
struct multiboot
|
||||||
|
{
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t mem_lower;
|
||||||
|
uint32_t mem_upper;
|
||||||
|
uint32_t boot_device;
|
||||||
|
uint32_t cmdline;
|
||||||
|
uint32_t mods_count;
|
||||||
|
uint32_t mods_addr;
|
||||||
|
uint32_t num;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t shndx;
|
||||||
|
uint32_t mmap_length;
|
||||||
|
uint32_t mmap_addr;
|
||||||
|
uint32_t drives_length;
|
||||||
|
uint32_t drives_addr;
|
||||||
|
uint32_t config_table;
|
||||||
|
uint32_t boot_loader_name;
|
||||||
|
uint32_t apm_table;
|
||||||
|
uint32_t vbe_control_info;
|
||||||
|
uint32_t vbe_mode_info;
|
||||||
|
uint32_t vbe_mode;
|
||||||
|
uint32_t vbe_interface_seg;
|
||||||
|
uint32_t vbe_interface_off;
|
||||||
|
uint32_t vbe_interface_len;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
typedef struct multiboot_header multiboot_header_t;
|
|
@ -0,0 +1,84 @@
|
||||||
|
#include <string.h>
|
||||||
|
typedef void* type_t;
|
||||||
|
|
||||||
|
typedef int8_t (*lessthan_predicate_t)(type_t,type_t);
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
type_t *array;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t max_size;
|
||||||
|
lessthan_predicate_t less_than;
|
||||||
|
} ordered_array_t;
|
||||||
|
|
||||||
|
standard_lessthan_predicate(type_t a, type_t b)
|
||||||
|
{
|
||||||
|
return (a<b)?1:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than)
|
||||||
|
{
|
||||||
|
ordered_array_t to_ret;
|
||||||
|
to_ret.array = (void*)kmalloc(max_size*sizeof(type_t));
|
||||||
|
memset(to_ret.array, 0, max_size*sizeof(type_t));
|
||||||
|
to_ret.size = 0;
|
||||||
|
to_ret.max_size = max_size;
|
||||||
|
to_ret.less_than = less_than;
|
||||||
|
return to_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than)
|
||||||
|
{
|
||||||
|
ordered_array_t to_ret;
|
||||||
|
to_ret.array = (type_t*)addr;
|
||||||
|
memset(to_ret.array, 0, max_size*sizeof(type_t));
|
||||||
|
to_ret.size = 0;
|
||||||
|
to_ret.max_size = max_size;
|
||||||
|
to_ret.less_than = less_than;
|
||||||
|
return to_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_ordered_array(ordered_array_t *array)
|
||||||
|
{
|
||||||
|
// kfree(array->array);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert_ordered_array(type_t item, ordered_array_t *array)
|
||||||
|
{
|
||||||
|
assert(array->less_than);
|
||||||
|
uint32_t iterator = 0;
|
||||||
|
while (iterator < array->size && array->less_than(array->array[iterator], item))
|
||||||
|
iterator++;
|
||||||
|
if (iterator == array->size) // just add at the end of the array.
|
||||||
|
array->array[array->size++] = item;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type_t tmp = array->array[iterator];
|
||||||
|
array->array[iterator] = item;
|
||||||
|
while (iterator < array->size)
|
||||||
|
{
|
||||||
|
iterator++;
|
||||||
|
type_t tmp2 = array->array[iterator];
|
||||||
|
array->array[iterator] = tmp;
|
||||||
|
tmp = tmp2;
|
||||||
|
}
|
||||||
|
array->size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type_t lookup_ordered_array(uint32_t i, ordered_array_t *array)
|
||||||
|
{
|
||||||
|
assert(i < array->size);
|
||||||
|
return array->array[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_ordered_array(uint32_t i, ordered_array_t *array)
|
||||||
|
{
|
||||||
|
while (i < array->size)
|
||||||
|
{
|
||||||
|
array->array[i] = array->array[i+1];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
array->size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
//#include "kheap.c"
|
||||||
|
uint32_t placement_address; //FIXME
|
||||||
|
|
||||||
|
uint32_t *frames;
|
||||||
|
uint32_t nframes;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Handler for page faults.
|
Handler for page faults.
|
||||||
|
@ -26,14 +32,184 @@ void page_fault(registers_t regs){
|
||||||
printf("PAGE FAULT\n");
|
printf("PAGE FAULT\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t kmalloc(uint32_t sz) // FIXME
|
||||||
|
{
|
||||||
|
uint32_t tmp = placement_address;
|
||||||
|
placement_address += sz;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct page
|
||||||
|
{
|
||||||
|
uint32_t present : 1; // Page present in memory
|
||||||
|
uint32_t rw : 1; // Read-only if clear, readwrite if set
|
||||||
|
uint32_t user : 1; // Supervisor level only if clear
|
||||||
|
uint32_t accessed : 1; // Has the page been accessed since last refresh?
|
||||||
|
uint32_t dirty : 1; // Has the page been written to since last refresh?
|
||||||
|
uint32_t unused : 7; // Amalgamation of unused and reserved bits
|
||||||
|
uint32_t frame : 20; // Frame address (shifted right 12 bits)
|
||||||
|
} page_t;
|
||||||
|
|
||||||
|
typedef struct page_table
|
||||||
|
{
|
||||||
|
page_t pages[1024];
|
||||||
|
} page_table_t;
|
||||||
|
|
||||||
|
typedef struct page_directory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
Array of pointers to pagetables.
|
||||||
|
**/
|
||||||
|
page_table_t *tables[1024];
|
||||||
|
/**
|
||||||
|
Array of pointers to the pagetables above, but gives their *physical*
|
||||||
|
location, for loading into the CR3 register.
|
||||||
|
**/
|
||||||
|
uint32_t tablesPhysical[1024];
|
||||||
|
/**
|
||||||
|
The physical address of tablesPhysical. This comes into play
|
||||||
|
when we get our kernel heap allocated and the directory
|
||||||
|
may be in a different location in virtual memory.
|
||||||
|
**/
|
||||||
|
uint32_t physicalAddr;
|
||||||
|
} page_directory_t;
|
||||||
|
|
||||||
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
||||||
uint32_t first_page_table[1024] __attribute__((aligned(4096)));
|
uint32_t first_page_table[1024] __attribute__((aligned(4096)));
|
||||||
|
|
||||||
extern void loadPageDirectory(unsigned int*);
|
extern void loadPageDirectory(unsigned int*);
|
||||||
extern void enable_paging();
|
extern void enable_paging();
|
||||||
|
//extern heap_t *kheap;
|
||||||
|
|
||||||
|
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys)
|
||||||
|
{
|
||||||
|
if (placement_address & 0xFFFFF000) // If the address is not already page-aligned
|
||||||
|
{
|
||||||
|
// Align it.
|
||||||
|
placement_address &= 0xFFFFF000;
|
||||||
|
placement_address += 0x1000;
|
||||||
|
}
|
||||||
|
if (phys)
|
||||||
|
{
|
||||||
|
*phys = placement_address;
|
||||||
|
}
|
||||||
|
uint32_t tmp = placement_address;
|
||||||
|
placement_address += sz;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Macros used in the bitset algorithms.
|
||||||
|
#define INDEX_FROM_BIT(a) (a/(8*4))
|
||||||
|
#define OFFSET_FROM_BIT(a) (a%(8*4))
|
||||||
|
|
||||||
|
// Static function to set a bit in the frames bitset
|
||||||
|
static void set_frame(uint32_t frame_addr)
|
||||||
|
{
|
||||||
|
uint32_t frame = frame_addr/0x1000;
|
||||||
|
uint32_t idx = INDEX_FROM_BIT(frame);
|
||||||
|
uint32_t off = OFFSET_FROM_BIT(frame);
|
||||||
|
frames[idx] |= (0x1 << off);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static function to clear a bit in the frames bitset
|
||||||
|
static void clear_frame(uint32_t frame_addr)
|
||||||
|
{
|
||||||
|
uint32_t frame = frame_addr/0x1000;
|
||||||
|
uint32_t idx = INDEX_FROM_BIT(frame);
|
||||||
|
uint32_t off = OFFSET_FROM_BIT(frame);
|
||||||
|
frames[idx] &= ~(0x1 << off);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static function to find the first free frame.
|
||||||
|
static uint32_t first_frame()
|
||||||
|
{
|
||||||
|
uint32_t i, j;
|
||||||
|
for (i = 0; i < INDEX_FROM_BIT(nframes); i++)
|
||||||
|
{
|
||||||
|
if (frames[i] != 0xFFFFFFFF) // nothing free, exit early.
|
||||||
|
{
|
||||||
|
// at least one bit is free here.
|
||||||
|
for (j = 0; j < 32; j++)
|
||||||
|
{
|
||||||
|
uint32_t toTest = 0x1 << j;
|
||||||
|
if ( !(frames[i]&toTest) )
|
||||||
|
{
|
||||||
|
return i*4*8+j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void alloc_frame(page_t *page, int is_kernel, int is_writeable)
|
||||||
|
{
|
||||||
|
if (page->frame != 0)
|
||||||
|
{
|
||||||
|
return; // Frame was already allocated, return straight away.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t idx = first_frame(); // idx is now the index of the first free frame.
|
||||||
|
if (idx == (uint32_t)-1)
|
||||||
|
{
|
||||||
|
// PANIC is just a macro that prints a message to the screen then hits an infinite loop.
|
||||||
|
printf("No free frames!");
|
||||||
|
}
|
||||||
|
set_frame(idx*0x1000); // this frame is now ours!
|
||||||
|
page->present = 1; // Mark it as present.
|
||||||
|
page->rw = (is_writeable)?1:0; // Should the page be writeable?
|
||||||
|
page->user = (is_kernel)?0:1; // Should the page be user-mode?
|
||||||
|
page->frame = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to deallocate a frame.
|
||||||
|
void free_frame(page_t *page)
|
||||||
|
{
|
||||||
|
uint32_t frame;
|
||||||
|
if (!(frame=page->frame))
|
||||||
|
{
|
||||||
|
return; // The given page didn't actually have an allocated frame!
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clear_frame(frame); // Frame is now free again.
|
||||||
|
page->frame = 0x0; // Page now doesn't have a frame.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
page_t *get_page(uint32_t address, int make, page_directory_t *dir)
|
||||||
|
{
|
||||||
|
// Turn the address into an index.
|
||||||
|
address /= 0x1000;
|
||||||
|
// Find the page table containing this address.
|
||||||
|
uint32_t table_idx = address / 1024;
|
||||||
|
if (dir->tables[table_idx]) // If this table is already assigned
|
||||||
|
{
|
||||||
|
return &dir->tables[table_idx]->pages[address%1024];
|
||||||
|
}
|
||||||
|
else if(make)
|
||||||
|
{
|
||||||
|
uint32_t tmp;
|
||||||
|
dir->tables[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp);
|
||||||
|
memset(dir->tables[table_idx], 0, 0x1000);
|
||||||
|
dir->tablesPhysical[table_idx] = tmp | 0x7; // PRESENT, RW, US.
|
||||||
|
return &dir->tables[table_idx]->pages[address%1024];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void init_paging() {
|
void init_paging() {
|
||||||
|
// The size of physical memory. For the moment we
|
||||||
|
// assume it is 16MB big.
|
||||||
|
uint32_t mem_end_page = 0x1000000;
|
||||||
|
|
||||||
|
nframes = mem_end_page / 0x1000;
|
||||||
|
frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes));
|
||||||
|
memset(frames, 0, INDEX_FROM_BIT(nframes));
|
||||||
//set each entry to not present
|
//set each entry to not present
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 1024; i++)
|
for(i = 0; i < 1024; i++)
|
||||||
|
@ -60,4 +236,7 @@ void init_paging() {
|
||||||
|
|
||||||
loadPageDirectory(page_directory);
|
loadPageDirectory(page_directory);
|
||||||
enable_paging();
|
enable_paging();
|
||||||
|
|
||||||
|
// Initialise the kernel heap.
|
||||||
|
//kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef _ASSERT_H
|
||||||
|
#define _ASSERT_H 1
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define assert(condition) ((void)0)
|
||||||
|
#else
|
||||||
|
#define assert(condition) /*implementation defined*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -61,6 +61,18 @@ int printf(const char* restrict format, ...) {
|
||||||
if (!print(str, len))
|
if (!print(str, len))
|
||||||
return -1;
|
return -1;
|
||||||
written += len;
|
written += len;
|
||||||
|
} else if (*format == 'x') {
|
||||||
|
format++;
|
||||||
|
int c = va_arg(parameters, int);
|
||||||
|
c = c == 10 ? 17 : c;
|
||||||
|
if (!maxrem) {
|
||||||
|
// TODO: Set errno to EOVERFLOW.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!print("0x", &c))
|
||||||
|
return -1;
|
||||||
|
written++;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
format = format_begun_at;
|
format = format_begun_at;
|
||||||
size_t len = strlen(format);
|
size_t len = strlen(format);
|
||||||
|
|
Loading…
Reference in New Issue