Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/config/config.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "config.h"

#include "internal/assembly.h"
#include "internal/heap.h"
#include "internal/mem.h"
#include "internal/log.h"
#include "internal/tickable.h"
#include "patches/custom/party_game_toggle.h"
Expand Down Expand Up @@ -159,7 +159,7 @@ void parse_config() {
if (open_success) {
// heap::alloc rounds to a multiple of 32, necessary for DVDReadAsyncPrio
config_file_length = (config_file_info.length + 0x1f) & 0xffffffe0;
config_file_buf = static_cast<char*>(heap::alloc(config_file_length));
config_file_buf = static_cast<char*>(mem::wsmod_heap.alloc(config_file_length));
u32 read_length = mkb::read_entire_file_using_dvdread_prio_async(&config_file_info, config_file_buf, config_file_length, 0);
char* eof = config_file_buf + config_file_info.length;

Expand Down Expand Up @@ -219,7 +219,7 @@ void parse_config() {
} while (file <= eof);
}
mkb::DVDClose(&config_file_info);
heap::free(config_file_buf);
mem::wsmod_heap.free(config_file_buf);
}
}

Expand Down
34 changes: 34 additions & 0 deletions src/internal/arena.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "arena.h"

#include "log.h"

// TODO default to 4-byte alignment

namespace arena {

void Arena::init(const char* name, void* start, u32 size) {
m_name = name;
m_start = start;
m_capacity = size;
reset();
}

void Arena::reset() {
m_occupied = 0;
mkb::memset(m_start, 0, m_capacity);
}

void* Arena::alloc(u32 size) {
u32 new_occupied = m_occupied + size;
if (new_occupied > m_capacity) {
// Not ideal way to log this
LOG("%s arena out of memory", m_name);
MOD_ASSERT(new_occupied <= m_capacity);
}
void* ret = reinterpret_cast<void*>(reinterpret_cast<u32>(m_start) + m_occupied);
m_occupied = new_occupied;
return ret;
}

} // namespace arena

36 changes: 36 additions & 0 deletions src/internal/arena.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include "mkb.h"

namespace arena {

class Arena {
public:
void init(const char* name, void* start, u32 size);
void reset();
void* alloc(u32 size);

template <typename T>
T* alloc() {
return static_cast<T*>(alloc(sizeof(T)));
}

template <typename T>
T* alloc(u32 elem_count) {
return static_cast<T*>(alloc(sizeof(T) * elem_count));
}

void* get_start() { return m_start; }
void* get_pos() { return reinterpret_cast<void*>(reinterpret_cast<u32>(m_start) + m_occupied); }
u32 get_occupied() { return m_occupied; }
u32 get_free() { return m_capacity - m_occupied; }

private:
const char* m_name;
void* m_start = nullptr;
u32 m_capacity = 0;
u32 m_occupied = 0;
};

} // namespace arena

17 changes: 4 additions & 13 deletions src/internal/cardio.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "cardio.h"
#include "heap.h"
#include "mem.h"
#include "mkb.h"
#include "modlink.h"
#include <optional>
Expand Down Expand Up @@ -28,7 +28,7 @@ static Slot s_current_slot = Slot::None;
// We need a 40KB(!) buffer just for the privilege of accessing memory cards,
// this sucks! Reminder we only have ~550KB to work with for the entire mod,
// including savestates
static void* s_card_work_area;
static u8 s_card_work_area[mkb::CARD_WORKAREA_SIZE] __attribute__((__aligned__(32)));
static mkb::CARDFileInfo s_card_file_info;

static WriteState s_state = WriteState::Idle;
Expand Down Expand Up @@ -81,7 +81,7 @@ static mkb::CARDResult read_file_internal(const Slot slot, const char* file_name

u32 buf_size =
(stat.length + mkb::CARD_READ_SIZE - 1) & ~(mkb::CARD_READ_SIZE - 1);
void* buf = heap::alloc(buf_size);
void* buf = mem::wsmod_heap.alloc(buf_size);
if (buf == nullptr) {
// Not quite the right error (we're out of memory, not out of card space)
mkb::CARDUnmount(static_cast<s32>(slot));
Expand All @@ -93,7 +93,7 @@ static mkb::CARDResult read_file_internal(const Slot slot, const char* file_name
res = mkb::CARDGetResultCode(static_cast<s32>(slot));
} while (res == mkb::CARD_RESULT_BUSY);
if (res != mkb::CARD_RESULT_READY) {
heap::free(buf);
mem::wsmod_heap.free(buf);
mkb::CARDUnmount(static_cast<s32>(slot));
return res;
}
Expand All @@ -120,15 +120,6 @@ static void finish_write(mkb::CARDResult res) {
}

void init() {
// Artificial delay so that the memcard has time to initialize
// Probably not an issue on console, but if read speed emulation is disabled in Dolphin, this can cause issues
// auto current_tick = mkb::OSGetTick();
// auto end_tick = current_tick + mkb::BUS_CLOCK_SPEED/32; // 0.125s delay
// while (current_tick < end_tick) {
// current_tick = mkb::OSGetTick();
// }

s_card_work_area = heap::alloc(mkb::CARD_WORKAREA_SIZE);
modlink::set_card_work_area(s_card_work_area);
}

Expand Down
14 changes: 7 additions & 7 deletions src/internal/cxx.cpp
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
#include "heap.h"
#include "mem.h"

void* operator new(u32 size) {
return heap::alloc(size);
return mem::wsmod_heap.alloc(size);
}

void* operator new[](u32 size) {
return heap::alloc(size);
return mem::wsmod_heap.alloc(size);
}

void operator delete(void* ptr) {
heap::free(ptr);
mem::wsmod_heap.free(ptr);
}

void operator delete[](void* ptr) {
heap::free(ptr);
mem::wsmod_heap.free(ptr);
}

void operator delete(void* ptr, u32 size) {
heap::free(ptr);
mem::wsmod_heap.free(ptr);
}

void operator delete[](void* ptr, u32 size) {
heap::free(ptr);
mem::wsmod_heap.free(ptr);
}
86 changes: 35 additions & 51 deletions src/internal/heap.cpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
#include "heap.h"

#include "mkb/mkb.h"
#include "relutil.h"
#include <mkb.h>
#include <cinttypes>
#include "log.h"

namespace heap {

static mkb::HeapInfo s_heap_info;

mkb::ChunkInfo* extract_chunk(mkb::ChunkInfo* list, mkb::ChunkInfo* chunk) {
static mkb::ChunkInfo* extract_chunk(mkb::ChunkInfo* list, mkb::ChunkInfo* chunk) {
if (chunk->next) {
chunk->next->prev = chunk->prev;
}

if (!chunk->prev) {
return chunk->next;
}
else {
} else {
chunk->prev->next = chunk->next;
return list;
}
}

mkb::ChunkInfo* add_chunk_to_front(mkb::ChunkInfo* list, mkb::ChunkInfo* chunk) {
static mkb::ChunkInfo* add_chunk_to_front(mkb::ChunkInfo* list, mkb::ChunkInfo* chunk) {
chunk->next = list;
chunk->prev = nullptr;

Expand All @@ -33,7 +30,7 @@ mkb::ChunkInfo* add_chunk_to_front(mkb::ChunkInfo* list, mkb::ChunkInfo* chunk)
return chunk;
}

mkb::ChunkInfo* find_chunk_in_list(mkb::ChunkInfo* list, mkb::ChunkInfo* chunk) {
static mkb::ChunkInfo* find_chunk_in_list(mkb::ChunkInfo* list, mkb::ChunkInfo* chunk) {
for (; list; list = list->next) {
if (list == chunk) {
return list;
Expand All @@ -42,31 +39,25 @@ mkb::ChunkInfo* find_chunk_in_list(mkb::ChunkInfo* list, mkb::ChunkInfo* chunk)
return nullptr;
}

static void make_heap() {
u32 start = mkb::OSRoundUp32B(*reinterpret_cast<u32*>(0x8000452C));
void* end_ptr = relutil::compute_mainloop_reldata_boundary(reinterpret_cast<void*>(start));
u32 end = mkb::OSRoundDown32B(reinterpret_cast<u32>(end_ptr));
u32 size = end - start;

void Heap::init(void* start, u32 size) {
mkb::memset(reinterpret_cast<void*>(start), 0, size);

s_heap_info.capacity = size;
s_heap_info.first_free = reinterpret_cast<mkb::ChunkInfo*>(start);
s_heap_info.first_free->next = nullptr;
s_heap_info.first_free->prev = nullptr;
s_heap_info.first_free->size = size;
s_heap_info.first_used = nullptr;
m_heap_info.capacity = size;
m_heap_info.first_free = reinterpret_cast<mkb::ChunkInfo*>(start);
m_heap_info.first_free->next = nullptr;
m_heap_info.first_free->prev = nullptr;
m_heap_info.first_free->size = size;
m_heap_info.first_used = nullptr;
}

void* alloc(u32 size) {
void* Heap::alloc(u32 size) {
// Enlarge size to the smallest possible chunk size
u32 new_size = size + mkb::OSRoundUp32B(sizeof(mkb::ChunkInfo));
new_size = mkb::OSRoundUp32B(new_size);

mkb::ChunkInfo* temp_chunk = nullptr;

// Find a memory area large enough
for (temp_chunk = s_heap_info.first_free; temp_chunk; temp_chunk = temp_chunk->next) {
for (temp_chunk = m_heap_info.first_free; temp_chunk; temp_chunk = temp_chunk->next) {
if (new_size <= temp_chunk->size) {
break;
}
Expand All @@ -84,9 +75,8 @@ void* alloc(u32 size) {
// Check if the current chunk can be split into two pieces
if (leftover_size < min_size) {
// Too small to split, so just extract it
s_heap_info.first_free = extract_chunk(s_heap_info.first_free, temp_chunk);
}
else {
m_heap_info.first_free = extract_chunk(m_heap_info.first_free, temp_chunk);
} else {
// Large enough to split
temp_chunk->size = static_cast<s32>(new_size);

Expand All @@ -105,14 +95,13 @@ void* alloc(u32 size) {

if (new_chunk->prev) {
new_chunk->prev->next = new_chunk;
}
else {
s_heap_info.first_free = new_chunk;
} else {
m_heap_info.first_free = new_chunk;
}
}

// Add the chunk to the allocated list
s_heap_info.first_used = add_chunk_to_front(s_heap_info.first_used, temp_chunk);
m_heap_info.first_used = add_chunk_to_front(m_heap_info.first_used, temp_chunk);

// Add the header size to the chunk
void* allocated_memory = reinterpret_cast<void*>(reinterpret_cast<u32>(temp_chunk) +
Expand All @@ -122,7 +111,7 @@ void* alloc(u32 size) {
return allocated_memory;
}

bool free(void* ptr) {
bool Heap::free(void* ptr) {
u32 ptr_raw = reinterpret_cast<u32>(ptr);

u32 header_size = mkb::OSRoundUp32B(sizeof(mkb::ChunkInfo));
Expand All @@ -131,34 +120,34 @@ bool free(void* ptr) {
mkb::ChunkInfo* temp_chunk = reinterpret_cast<mkb::ChunkInfo*>(ptr_raw - header_size);

// Make sure ptr is actually allocated
if (!find_chunk_in_list(s_heap_info.first_used, temp_chunk)) {
if (!find_chunk_in_list(m_heap_info.first_used, temp_chunk)) {
return false;
}

// Extract the chunk from the allocated list
s_heap_info.first_used = extract_chunk(s_heap_info.first_used, temp_chunk);
m_heap_info.first_used = extract_chunk(m_heap_info.first_used, temp_chunk);

// Add in sorted order to the free list
s_heap_info.first_free = mkb::DLInsert(s_heap_info.first_free, temp_chunk);
m_heap_info.first_free = mkb::DLInsert(m_heap_info.first_free, temp_chunk);
return true;
}

u32 get_free_space() {
u32 Heap::get_free_space() {
u32 space = 0;
for (mkb::ChunkInfo* chunk = s_heap_info.first_free; chunk; chunk = chunk->next) {
space += chunk->size - 32;// Don't count the ChunkInfo
for (mkb::ChunkInfo* chunk = m_heap_info.first_free; chunk; chunk = chunk->next) {
space += chunk->size - 32; // Don't count the ChunkInfo
}
return space;
}

u32 get_total_space() { return s_heap_info.capacity; }
u32 Heap::get_total_space() { return m_heap_info.capacity; }

void check_integrity() {
void Heap::check_integrity() {
bool valid = true;

mkb::ChunkInfo* current_chunk = nullptr;
mkb::ChunkInfo* prev_chunk = nullptr;
for (current_chunk = s_heap_info.first_used; current_chunk;
for (current_chunk = m_heap_info.first_used; current_chunk;
current_chunk = current_chunk->next) {
// Check pointer sanity
auto check_if_pointer_is_valid = [](void* ptr) {
Expand Down Expand Up @@ -187,17 +176,12 @@ void check_integrity() {
}

if (!valid) {
// Print the error message to the console
mkb::OSReport("Heap corrupt at 0x%08" PRIx32 "\n", reinterpret_cast<u32>(current_chunk));
// Not ideal way to log this
LOG("Heap corrupt at 0x%08" PRIx32 "\n", reinterpret_cast<u32>(current_chunk));
MOD_ASSERT(valid);
}
}

void init() {
make_heap();
}

mkb::HeapInfo& get_heap_info() {
return s_heap_info;
}
mkb::HeapInfo& Heap::get_heap_info() { return m_heap_info; }

}// namespace heap
} // namespace heap
Loading