mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-29 14:04:19 +01:00
An actual memory implementation
This commit is contained in:
parent
64f2f90087
commit
2f24f28084
@ -9,6 +9,7 @@ include_directories(${source_DIR}/include)
|
|||||||
add_library(lightswitch SHARED
|
add_library(lightswitch SHARED
|
||||||
${source_DIR}/lightswitch.cpp
|
${source_DIR}/lightswitch.cpp
|
||||||
${source_DIR}/core/arm/cpu.cpp
|
${source_DIR}/core/arm/cpu.cpp
|
||||||
|
${source_DIR}/core/arm/memory.cpp
|
||||||
|
|
||||||
${source_DIR}/core/hos/loaders/nro.cpp
|
${source_DIR}/core/hos/loaders/nro.cpp
|
||||||
)
|
)
|
||||||
|
43
app/src/main/cpp/core/arm/memory.cpp
Normal file
43
app/src/main/cpp/core/arm/memory.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include <sys/mman.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <vector>
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
std::vector<mem::MemoryRegion> memRegions;
|
||||||
|
|
||||||
|
namespace mem {
|
||||||
|
bool Map(uc_engine* uc, uint64_t address, size_t size, std::string label) {
|
||||||
|
void* ptr = mmap((void*)(address), size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0);
|
||||||
|
if(!ptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Skipping this until the CPU implementation is working
|
||||||
|
if(uc) {
|
||||||
|
uc_err err = uc_mem_map_ptr(uc, address, size, UC_PROT_ALL, ptr);
|
||||||
|
if(err)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "Memory map failed: %s", uc_strerror(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "Successfully mapped region '%s' to 0x%x", label.c_str(), address);
|
||||||
|
|
||||||
|
memRegions.push_back({label, address, size, ptr});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Boundary checks
|
||||||
|
void Write(void* data, uint64_t offset, size_t size) { std::memcpy((void*)(offset), data, size); }
|
||||||
|
void WriteU8(uint8_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 1); }
|
||||||
|
void WriteU16(uint16_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 2); }
|
||||||
|
void WriteU32(uint32_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 4); }
|
||||||
|
void WriteU64(uint64_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 8); }
|
||||||
|
|
||||||
|
void Read(void* destination, uint64_t offset, size_t size) { std::memcpy(destination, (void*)(offset), size); }
|
||||||
|
uint8_t ReadU8(uint64_t offset) { uint8_t value; Read(reinterpret_cast<void*>(&value), offset, 1); return value; }
|
||||||
|
uint16_t ReadU16(uint64_t offset) { uint16_t value; Read(reinterpret_cast<void*>(&value), offset, 2); return value; }
|
||||||
|
uint32_t ReadU32(uint64_t offset) { uint32_t value; Read(reinterpret_cast<void*>(&value), offset, 4); return value; }
|
||||||
|
uint64_t ReadU64(uint64_t offset) { uint64_t value; Read(reinterpret_cast<void*>(&value), offset, 8); return value; }
|
||||||
|
}
|
28
app/src/main/cpp/core/arm/memory.h
Normal file
28
app/src/main/cpp/core/arm/memory.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <unicorn/unicorn.h>
|
||||||
|
|
||||||
|
#define MEM_BASE 0x80000000
|
||||||
|
|
||||||
|
namespace mem {
|
||||||
|
struct MemoryRegion {
|
||||||
|
std::string label;
|
||||||
|
uint64_t address;
|
||||||
|
size_t size;
|
||||||
|
void* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Map(uc_engine* uc, uint64_t address, size_t size, std::string label="");
|
||||||
|
|
||||||
|
void Write(void* data, uint64_t offset, size_t size);
|
||||||
|
void WriteU8(uint8_t value, uint64_t offset);
|
||||||
|
void WriteU16(uint16_t value, uint64_t offset);
|
||||||
|
void WriteU32(uint32_t value, uint64_t offset);
|
||||||
|
void WriteU64(uint64_t value, uint64_t offset);
|
||||||
|
|
||||||
|
void Read(void* destination, uint64_t offset, size_t size);
|
||||||
|
uint8_t ReadU8(uint64_t offset);
|
||||||
|
uint16_t ReadU16(uint64_t offset);
|
||||||
|
uint32_t ReadU32(uint64_t offset);
|
||||||
|
uint64_t ReadU64(uint64_t offset);
|
||||||
|
}
|
@ -1,13 +1,10 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "../../arm/memory.h"
|
||||||
#include "nro.h"
|
#include "nro.h"
|
||||||
|
|
||||||
// TODO: Move memory to it's own file
|
|
||||||
#define MEM_BASE 0x80000000
|
|
||||||
|
|
||||||
void ReadDataFromFile(std::string file, char* output, uint32_t offset, size_t size)
|
void ReadDataFromFile(std::string file, char* output, uint32_t offset, size_t size)
|
||||||
{
|
{
|
||||||
std::ifstream f(file, std::ios::binary | std::ios::beg);
|
std::ifstream f(file, std::ios::binary | std::ios::beg);
|
||||||
@ -34,30 +31,22 @@ namespace loader {
|
|||||||
ro.resize(h.segments[1].size);
|
ro.resize(h.segments[1].size);
|
||||||
data.resize(h.segments[2].size);
|
data.resize(h.segments[2].size);
|
||||||
|
|
||||||
ReadDataFromFile(file, reinterpret_cast<char *>(text.data()),
|
ReadDataFromFile(file, reinterpret_cast<char *>(text.data()), h.segments[0].fileOffset, h.segments[0].size);
|
||||||
h.segments[0].fileOffset, h.segments[0].size);
|
ReadDataFromFile(file, reinterpret_cast<char *>(ro.data()), h.segments[1].fileOffset, h.segments[1].size);
|
||||||
ReadDataFromFile(file, reinterpret_cast<char *>(ro.data()),
|
ReadDataFromFile(file, reinterpret_cast<char *>(data.data()), h.segments[2].fileOffset, h.segments[2].size);
|
||||||
h.segments[1].fileOffset, h.segments[1].size);
|
|
||||||
ReadDataFromFile(file, reinterpret_cast<char *>(data.data()),
|
|
||||||
h.segments[2].fileOffset, h.segments[2].size);
|
|
||||||
|
|
||||||
|
if( !mem::Map(nullptr, MEM_BASE, h.segments[0].size, ".text") ||
|
||||||
if(!mmap((void*)(MEM_BASE),
|
!mem::Map(nullptr, MEM_BASE + h.segments[0].size, h.segments[1].size, ".ro") ||
|
||||||
h.segments[0].size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) ||
|
!mem::Map(nullptr, MEM_BASE + h.segments[0].size + h.segments[1].size, h.segments[2].size, ".data") ||
|
||||||
!mmap((void*)(MEM_BASE + h.segments[0].size),
|
!mem::Map(nullptr, MEM_BASE + h.segments[0].size + h.segments[1].size + h.segments[2].size, h.bssSize, ".bss")) {
|
||||||
h.segments[1].size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) ||
|
|
||||||
!mmap((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size),
|
|
||||||
h.segments[2].size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) ||
|
|
||||||
!mmap((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size + h.segments[2].size),
|
|
||||||
h.bssSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0)) {
|
|
||||||
|
|
||||||
syslog(LOG_ERR, "Failed mapping regions for executable");
|
syslog(LOG_ERR, "Failed mapping regions for executable");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy((void*)(MEM_BASE), text.data(), text.size());
|
mem::Write(text.data(), MEM_BASE, text.size());
|
||||||
std::memcpy((void*)(MEM_BASE + h.segments[0].size), ro.data(), ro.size());
|
mem::Write(ro.data(), MEM_BASE + h.segments[0].size, ro.size());
|
||||||
std::memcpy((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size), data.data(), data.size());
|
mem::Write(data.data(), MEM_BASE + h.segments[0].size + h.segments[1].size, data.size());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user