Skip to content

Commit

Permalink
Dummy memory allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
JayFoxRox committed Jun 12, 2019
1 parent aa0282b commit 3afc669
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 11 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ add_executable(openswe1r
emulation.c
export.c
shader.c
alloc.c

dll/kernel32.c

Expand Down
139 changes: 139 additions & 0 deletions alloc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright 2019 OpenSWE1R Maintainers
// Licensed under GPLv2 or any later version
// Refer to the included LICENSE.txt file.

// This is a temporary placeholder for a memory allocator.

#include "alloc.h"

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "common.h"


typedef struct _Allocator {
unsigned int block_count;
unsigned int block_size;
uint8_t block_usage[1];
} Allocator;


static void block_mark_used(Allocator* allocator, unsigned int block, bool used) {
uint8_t mask = 1 << (block % 8);
if (used) {
allocator->block_usage[block / 8] |= mask;
} else {
allocator->block_usage[block / 8] &= ~mask;
}
}

static bool block_is_used(Allocator* allocator, unsigned int block) {
uint8_t mask = 1 << (block % 8);
return allocator->block_usage[block / 8] & mask;
}

static unsigned int count_blocks(Allocator* allocator, unsigned int block, bool used) {
unsigned int count = 0;
while(block < allocator->block_count) {
if (block_is_used(allocator, block) != used) {
break;
}
block++;
count++;
}
return count;
}

static unsigned int find_free_blocks(Allocator* allocator, unsigned int needed_blocks) {

unsigned int best_count = 0;
unsigned int best_block = 0;

unsigned int block = 0;
while(block < allocator->block_count) {

bool block_used = block_is_used(allocator, block);
unsigned int available_blocks = count_blocks(allocator, block, block_used);

// Only look at unused blocks that are large enough
if (!block_used && (available_blocks >= needed_blocks)) {

// Check if we don't have a result yet, or if this is a better fit
if ((best_count == 0) || (available_blocks < best_count)) {

// Update result
best_block = block;
best_count = available_blocks;

// If we have an exact fit, use that
if (best_count == needed_blocks) {
break;
}

}
}

block += available_blocks;
}

// Assert that we have a result
assert(best_count != 0);

// Returns best block address
return best_block;
}

Allocator* alloc_create(unsigned int size, unsigned int block_size) {
assert(size % block_size == 0);
unsigned int block_count = size / block_size;

size_t usage_byte_count = (block_count + 7) / 8;
Allocator* allocator = malloc(sizeof(Allocator) + usage_byte_count - 1);
allocator->block_count = block_count;
allocator->block_size = block_size;
memset(allocator->block_usage, 0x00, usage_byte_count);
return allocator;
}

void alloc_destroy(Allocator* allocator) {
free(allocator);
}

unsigned int alloc_allocate(Allocator* allocator, unsigned int size) {

unsigned int aligned_size = AlignUp(size, allocator->block_size);
unsigned int count = aligned_size / allocator->block_size;

// Don't allow zero-size allocations (breaks algorithm)
assert(count > 0);

//FIXME: `+ 2` is a hack, so we can recognize block splits
unsigned int block = find_free_blocks(allocator, count + 2) + 1;

for(unsigned int i = 0; i < count; i++) {
block_mark_used(allocator, block + i, true);
}

return block * allocator->block_size;
}

void alloc_free(Allocator* allocator, unsigned int offset) {

assert(offset % allocator->block_size == 0);
unsigned int block = offset / allocator->block_size;

unsigned int used_blocks = count_blocks(allocator, block, true);

// Avoid double-free
assert(used_blocks > 0);

for(unsigned int i = 0; i < used_blocks; i++) {
block_mark_used(allocator, block + i, false);
}

}
18 changes: 18 additions & 0 deletions alloc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2019 OpenSWE1R Maintainers
// Licensed under GPLv2 or any later version
// Refer to the included LICENSE.txt file.

#ifndef __OPENSWE1R_ALLOC_H__
#define __OPENSWE1R_ALLOC_H__

#include <stdint.h>
#include <stdbool.h>

typedef struct _Allocator Allocator;

Allocator* alloc_create(unsigned int size, unsigned int block_size);
void alloc_destroy(Allocator* allocator);
unsigned int alloc_allocate(Allocator* allocator, unsigned int size);
void alloc_free(Allocator* allocator, unsigned int offset);

#endif
24 changes: 13 additions & 11 deletions emulation.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "emulation.h"
#include "exe.h"

#include "alloc.h"

//FIXME: These are hacks (register when mapping instead!)!
extern Exe* exe;
uint8_t* stack = NULL;
Expand Down Expand Up @@ -287,27 +289,27 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe
return memory;
}

static Allocator* memoryAllocator = NULL;
static unsigned int memoryBlockSize = 0x1000;

Address Allocate(Size size) {
static uint32_t address = HEAP_ADDRESS;
uint32_t ret = address;
address += size;
if (memoryAllocator == NULL) {
memoryAllocator = alloc_create(heapSize, memoryBlockSize);
}
unsigned int offset = alloc_allocate(memoryAllocator, size);
Address ret = heapAddress + offset;

#if 1
// Debug memset to detect memory errors
memset(Memory(ret), 0xDD, size);
#endif
//FIXME: Proper allocator

#if 1
//FIXME: This is a hack to fix alignment + to avoid too small allocations
address += 0x1000;
address &= 0xFFFFF000;
#endif

return ret;
}

void Free(Address address) {
//FIXME!
unsigned int offset = address - heapAddress;
alloc_free(memoryAllocator, offset);
}

void* Memory(uint32_t address) {
Expand Down

0 comments on commit 3afc669

Please sign in to comment.