mirror of
https://github.com/daeken/Zookeeper.git
synced 2024-05-14 19:09:33 -04:00
Removed silly aligned page allocation calls. Fixed contiguous memory. Added basic MMIO. Added initial GPU class.
This commit is contained in:
parent
2aeb66c4ab
commit
21f002ac5e
5
Box.cpp
5
Box.cpp
|
@ -12,13 +12,12 @@ Box::Box() {
|
|||
hypercall = new Hypercall();
|
||||
|
||||
hm = new HandleManager();
|
||||
|
||||
pm = new PageManager();
|
||||
pm->add_region(0, 64 * 1024 * 1024);
|
||||
|
||||
tm = new ThreadManager();
|
||||
|
||||
io = new IOManager();
|
||||
|
||||
debugger = new Debugger();
|
||||
|
||||
gpu = new Gpu();
|
||||
}
|
||||
|
|
1
Box.hpp
1
Box.hpp
|
@ -7,6 +7,7 @@ public:
|
|||
Box();
|
||||
|
||||
Cpu *cpu;
|
||||
Gpu *gpu;
|
||||
Hypercall *hypercall;
|
||||
HandleManager *hm;
|
||||
PageManager *pm;
|
||||
|
|
77
Cpu.cpp
77
Cpu.cpp
|
@ -53,17 +53,35 @@ Cpu::Cpu(uint8_t *ram, uint8_t *kram) {
|
|||
hv->reg(CR4, 0x2000);
|
||||
}
|
||||
|
||||
void Cpu::map_pages(uint32_t virt, uint32_t phys, uint32_t count) {
|
||||
void Cpu::map_pages(uint32_t virt, uint32_t phys, uint32_t count, bool present) {
|
||||
auto dir = (uint32_t *) (mem + 64*1024*1024);
|
||||
for(auto i = 0; i < count; ++i) {
|
||||
auto table = (uint32_t *) (mem + (dir[virt >> 22] & ~0xFFF));
|
||||
table[(virt >> 12) & 0x3ff] = phys | 0x7;
|
||||
table[(virt >> 12) & 0x3ff] = phys | 0x6 | (present ? 1 : 0);
|
||||
virt += 4096;
|
||||
phys += 4096;
|
||||
}
|
||||
hv->invalidate_tlb(); // Do we really need to do this all the time?
|
||||
}
|
||||
|
||||
void Cpu::map_io(uint32_t base, uint32_t pages, MMIOReceiver *recv) {
|
||||
auto memblock = new uint8_t[pages * 4096];
|
||||
hv->map_phys(memblock, base, pages * 4096);
|
||||
for(auto i = 0; i < pages; ++i) {
|
||||
mmio[base] = recv;
|
||||
recv->buffers[base] = memblock;
|
||||
map_pages(base, base, 1, false); // Pages are not marked present
|
||||
base += 4096;
|
||||
memblock += 4096;
|
||||
}
|
||||
}
|
||||
|
||||
void Cpu::flip_page(uint32_t base, bool val) {
|
||||
auto dir = (uint32_t *) (mem + 64*1024*1024);
|
||||
auto table = (uint32_t *) (mem + (dir[base >> 22] & ~0xFFF));
|
||||
table[(base >> 12) & 0x3ff] = (table[(base >> 12) & 0x3ff] & ~1) | (val ? 1 : 0);
|
||||
}
|
||||
|
||||
uint32_t Cpu::virt2phys(uint32_t addr) {
|
||||
auto cr3 = hv->reg(CR3);
|
||||
if(cr3 == 0)
|
||||
|
@ -150,6 +168,7 @@ void Cpu::run(uint32_t eip) {
|
|||
auto last_time = systime();
|
||||
|
||||
auto swap = true;
|
||||
uint32_t in_mmio;
|
||||
do {
|
||||
if(break_in) {
|
||||
box->debugger->enter();
|
||||
|
@ -173,12 +192,36 @@ void Cpu::run(uint32_t eip) {
|
|||
case 1: { // Single step
|
||||
auto flags = hv->reg(EFLAGS);
|
||||
hv->reg(EFLAGS, flags & ~(1 << 8));
|
||||
if(single_step == 2) { // Requested
|
||||
single_step = 0;
|
||||
box->debugger->enter();
|
||||
switch(single_step) {
|
||||
case 1: { // Debugger requested
|
||||
box->debugger->reenable();
|
||||
break;
|
||||
}
|
||||
case 2: { // User requested
|
||||
single_step = 0;
|
||||
box->debugger->enter();
|
||||
break;
|
||||
}
|
||||
case 3: { // MMIO Read
|
||||
auto page = in_mmio & ~0xFFF;
|
||||
flip_page(page, false);
|
||||
single_step = 0;
|
||||
in_mmio = 0;
|
||||
break;
|
||||
}
|
||||
case 4: { // MMIO Write
|
||||
auto page = in_mmio & ~0xFFF;
|
||||
flip_page(page, false);
|
||||
auto dev = mmio[page];
|
||||
auto buf = dev->buffers[page];
|
||||
auto off = in_mmio & 0xFFF;
|
||||
volatile auto val = *((uint32_t *) ((uint8_t *) buf + off));
|
||||
dev->write(in_mmio, val);
|
||||
single_step = 0;
|
||||
in_mmio = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
box->debugger->reenable();
|
||||
swap = true;
|
||||
break;
|
||||
}
|
||||
|
@ -188,8 +231,24 @@ void Cpu::run(uint32_t eip) {
|
|||
break;
|
||||
}
|
||||
case 14: {
|
||||
cout << format("Page fault reading %08x") % exit.address << endl;
|
||||
stop = true;
|
||||
auto page = exit.address & ~0xFFF;
|
||||
if(IN(page, mmio)) {
|
||||
auto off = exit.address & 0xFFF;
|
||||
auto dev = mmio[page];
|
||||
auto buf = dev->buffers[page];
|
||||
auto write = FLAG(exit.error_code, 2);
|
||||
in_mmio = exit.address;
|
||||
flip_page(page, true);
|
||||
if(write) {
|
||||
single_step = 4;
|
||||
} else {
|
||||
*((uint32_t *) ((uint8_t *) buf + off)) = dev->read(exit.address);
|
||||
single_step = 3;
|
||||
}
|
||||
} else {
|
||||
cout << format("Page fault reading %08x") % exit.address << endl;
|
||||
stop = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
14
Cpu.hpp
14
Cpu.hpp
|
@ -2,12 +2,22 @@
|
|||
|
||||
#include "Zookeeper.hpp"
|
||||
|
||||
class MMIOReceiver {
|
||||
public:
|
||||
virtual uint32_t read(uint32_t addr) = 0;
|
||||
virtual void write(uint32_t addr, uint32_t value) = 0;
|
||||
|
||||
map<uint32_t, void *> buffers;
|
||||
};
|
||||
|
||||
class Cpu {
|
||||
public:
|
||||
Cpu(uint8_t *ram, uint8_t *kram);
|
||||
~Cpu();
|
||||
void run(uint32_t eip);
|
||||
void map_pages(uint32_t virt, uint32_t phys, uint32_t count);
|
||||
void map_pages(uint32_t virt, uint32_t phys, uint32_t count, bool present=true);
|
||||
void map_io(uint32_t base, uint32_t pages, MMIOReceiver *recv);
|
||||
void flip_page(uint32_t base, bool val);
|
||||
|
||||
uint32_t virt2phys(uint32_t addr);
|
||||
bool is_mapped(uint32_t addr);
|
||||
|
@ -32,4 +42,6 @@ public:
|
|||
int single_step = 0;
|
||||
bool stop = false;
|
||||
bool break_in = false;
|
||||
|
||||
map<uint32_t, MMIOReceiver *> mmio;
|
||||
};
|
||||
|
|
16
Gpu.cpp
Normal file
16
Gpu.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "Zookeeper.hpp"
|
||||
|
||||
Gpu::Gpu() {
|
||||
box->cpu->map_io(0xFD000000, 16, (MMIOReceiver *) this);
|
||||
box->cpu->map_io(0xFD100000, 1, (MMIOReceiver *) this);
|
||||
box->cpu->map_io(0xFD600000, 1, (MMIOReceiver *) this);
|
||||
}
|
||||
|
||||
uint32_t Gpu::read(uint32_t addr) {
|
||||
cout << format("Gpu::read(0x%08x)") % addr << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Gpu::write(uint32_t addr, uint32_t value) {
|
||||
cout << format("Gpu::write(0x%08x, 0x%08x)") % addr % value << endl;
|
||||
}
|
10
Gpu.hpp
Normal file
10
Gpu.hpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include "Zookeeper.hpp"
|
||||
|
||||
class Gpu : public MMIOReceiver {
|
||||
public:
|
||||
Gpu();
|
||||
|
||||
uint32_t read(uint32_t addr);
|
||||
void write(uint32_t addr, uint32_t value);
|
||||
};
|
1
HV.hpp
1
HV.hpp
|
@ -29,6 +29,7 @@ enum HVExitReason {
|
|||
|
||||
typedef struct exit {
|
||||
HVExitReason reason;
|
||||
uint32_t error_code;
|
||||
uint32_t instruction_length;
|
||||
uint32_t interrupt_no;
|
||||
uint32_t address; // Used for page faults
|
||||
|
|
|
@ -20,8 +20,14 @@ void Hypercall::log_(uint32_t message) {
|
|||
uint32_t Hypercall::map(uint32_t virt_base, uint32_t count) {
|
||||
return box->pm->map(virt_base, count);
|
||||
}
|
||||
uint32_t Hypercall::map_aligned(uint32_t virt_base, uint32_t count) {
|
||||
return box->pm->map(virt_base, count, true);
|
||||
uint32_t Hypercall::map_contiguous(uint32_t virt_base, uint32_t phys_low, uint32_t phys_high, uint32_t count) {
|
||||
return box->pm->map_contiguous(virt_base, phys_low, phys_high, count);
|
||||
}
|
||||
uint32_t Hypercall::query_map_size(uint32_t base) {
|
||||
auto count = 0;
|
||||
while(box->cpu->is_mapped(base + count * 4096))
|
||||
count++;
|
||||
return count * 4096;
|
||||
}
|
||||
void Hypercall::unmap(uint32_t virt_base, uint32_t count) {
|
||||
box->pm->unmap(virt_base, count);
|
||||
|
|
|
@ -165,6 +165,7 @@ exit_t HVMac::enter() {
|
|||
switch(exit_reason) {
|
||||
case VMX_REASON_EXC_NMI: {
|
||||
auto vec_val = rvmcs(VMCS_RO_VMEXIT_IRQ_INFO) & 0xFFFF;
|
||||
_exit.error_code = rvmcs(VMCS_RO_VMEXIT_IRQ_ERROR);
|
||||
switch((vec_val >> 8) & 7) {
|
||||
case 6: {
|
||||
_exit.reason = Interrupt;
|
||||
|
|
|
@ -8,8 +8,17 @@ void NTAPI kernel_MmPersistContiguousMemory(
|
|||
//log("Ignore MmPersistContiguousMemory");
|
||||
}
|
||||
|
||||
PVOID NTAPI kernel_MmAllocateContiguousMemory(IN ULONG NumberOfBytes) {
|
||||
return (PVOID) new uint8_t[NumberOfBytes];
|
||||
void * NTAPI kernel_MmAllocateContiguousMemory(uint32_t NumberOfBytes) {
|
||||
return kernel_MmAllocateContiguousMemoryEx(NumberOfBytes, 0, 0xFFFFFFFF, 0, 0);
|
||||
}
|
||||
|
||||
void * NTAPI kernel_MmAllocateContiguousMemoryEx(
|
||||
uint32_t NumberOfBytes,
|
||||
uint32_t low, uint32_t high,
|
||||
uint32_t unk, uint32_t flags
|
||||
) {
|
||||
NumberOfBytes = pagepad(NumberOfBytes);
|
||||
return map_contiguous(0, low, high, NumberOfBytes / 4096);
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI kernel_NtAllocateVirtualMemory(
|
||||
|
@ -22,12 +31,12 @@ NTSTATUS NTAPI kernel_NtAllocateVirtualMemory(
|
|||
*BaseAddress = (void *) (((uint32_t) *BaseAddress) & ~0xFFF);
|
||||
*RegionSize = pagepad(*RegionSize);
|
||||
if((AllocationType & MEM_COMMIT) == MEM_COMMIT) {
|
||||
*BaseAddress = map_aligned(*BaseAddress, *RegionSize / 4096);
|
||||
*BaseAddress = map(*BaseAddress, *RegionSize / 4096);
|
||||
} else if((AllocationType & MEM_RESERVE) == MEM_RESERVE) {
|
||||
// We should just be reserving memory, but it doesn't matter.
|
||||
// Commit will trash this region and we're probably leaking some.
|
||||
// Future coders will deal with this problem.
|
||||
*BaseAddress = map_aligned(*BaseAddress, *RegionSize / 4096);
|
||||
*BaseAddress = map(*BaseAddress, *RegionSize / 4096);
|
||||
} else {
|
||||
bailout("Unsupported allocation type %x", AllocationType);
|
||||
}
|
||||
|
@ -47,3 +56,15 @@ NTSTATUS NTAPI kernel_NtFreeVirtualMemory(
|
|||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t NTAPI kernel_MmQueryAllocationSize(void *base) {
|
||||
// XXX: This won't return the size of a given allocation,
|
||||
// but how many pages are mapped after that point.
|
||||
// This might blow up sometime.
|
||||
return query_map_size(base);
|
||||
}
|
||||
|
||||
uint32_t NTAPI kernel_MmQueryAddressProtect(void *base) {
|
||||
// XXX: Implement
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,12 @@ void NTAPI kernel_MmPersistContiguousMemory(
|
|||
IN ULONG NumberOfBytes,
|
||||
IN BOOLEAN Persist
|
||||
);
|
||||
PVOID NTAPI kernel_MmAllocateContiguousMemory(IN ULONG NumberOfBytes);
|
||||
void * NTAPI kernel_MmAllocateContiguousMemory(uint32_t NumberOfBytes);
|
||||
void * NTAPI kernel_MmAllocateContiguousMemoryEx(
|
||||
uint32_t NumberOfBytes,
|
||||
uint32_t low, uint32_t high,
|
||||
uint32_t unk, uint32_t flags
|
||||
);
|
||||
|
||||
NTSTATUS NTAPI kernel_NtAllocateVirtualMemory(
|
||||
void **BaseAddress,
|
||||
|
@ -21,3 +26,6 @@ NTSTATUS NTAPI kernel_NtFreeVirtualMemory(
|
|||
uint32_t *FreeSize,
|
||||
uint32_t FreeType
|
||||
);
|
||||
|
||||
uint32_t NTAPI kernel_MmQueryAllocationSize(void *base);
|
||||
uint32_t NTAPI kernel_MmQueryAddressProtect(void *base);
|
||||
|
|
|
@ -16,9 +16,9 @@ void PageManager::add_region(uint32_t base, uint32_t size) {
|
|||
freePhysPages.push_back(addr);
|
||||
}
|
||||
|
||||
uint32_t PageManager::map(uint32_t base, uint32_t count, bool aligned) {
|
||||
uint32_t PageManager::map(uint32_t base, uint32_t count) {
|
||||
if(base == 0)
|
||||
base = box->pm->alloc_virt(count, aligned);
|
||||
base = box->pm->alloc_virt(count);
|
||||
|
||||
for(auto i = 0; i < count; ++i) {
|
||||
auto virt = base + i * 4096;
|
||||
|
@ -29,6 +29,16 @@ uint32_t PageManager::map(uint32_t base, uint32_t count, bool aligned) {
|
|||
return base;
|
||||
}
|
||||
|
||||
uint32_t PageManager::map_contiguous(uint32_t base, uint32_t phys_low, uint32_t phys_high, uint32_t count) {
|
||||
if(base == 0)
|
||||
base = box->pm->alloc_virt(count, 0x80000000); // D3D wants a higher half address
|
||||
|
||||
auto phys_base = box->pm->alloc_phys(count, phys_low, phys_high);
|
||||
box->cpu->map_pages(base, phys_base, count);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
void PageManager::unmap(uint32_t base, uint32_t count) {
|
||||
auto addr = base;
|
||||
for(auto i = 0; i < count; ++i) {
|
||||
|
@ -38,49 +48,78 @@ void PageManager::unmap(uint32_t base, uint32_t count) {
|
|||
box->pm->free_virt(base, count);
|
||||
}
|
||||
|
||||
uint32_t PageManager::alloc_phys() {
|
||||
bailout(freePhysPages.size() == 0);
|
||||
uint32_t PageManager::alloc_phys(uint32_t count, uint32_t phys_low, uint32_t phys_high) {
|
||||
bailout(freePhysPages.size() < count);
|
||||
|
||||
auto page = freePhysPages.front();
|
||||
freePhysPages.pop_front();
|
||||
return page;
|
||||
if(count == 1) {
|
||||
for(auto iter = freePhysPages.begin(); iter != freePhysPages.end(); ++iter) {
|
||||
if(phys_low < *iter && phys_high >= (*iter + 4096)) {
|
||||
auto page = *iter;
|
||||
freePhysPages.erase(iter);
|
||||
return page;
|
||||
}
|
||||
}
|
||||
bailout(true); // Could not find page in range
|
||||
} else {
|
||||
for(auto base : freePhysPages) {
|
||||
if(!(phys_low < base && (base + count * 4096) <= phys_high))
|
||||
continue;
|
||||
// This is the least efficient search ever.
|
||||
auto found = true;
|
||||
for(auto i = 1; i < count; ++i) {
|
||||
if(find(freePhysPages.begin(), freePhysPages.end(), base + i * 4096) == freePhysPages.end()) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(found) {
|
||||
for(auto i = 0; i < count; ++i) {
|
||||
auto iter = find(freePhysPages.begin(), freePhysPages.end(), base + i * 4096);
|
||||
freePhysPages.erase(iter);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
||||
bailout(true); // Could not find enough contiguous pages in range
|
||||
}
|
||||
}
|
||||
|
||||
void PageManager::free_phys(uint32_t page) {
|
||||
freePhysPages.push_back(page);
|
||||
}
|
||||
|
||||
uint32_t PageManager::alloc_virt(uint32_t count, bool aligned) {
|
||||
uint32_t PageManager::alloc_virt(uint32_t count, uint32_t low) {
|
||||
for(auto iter = virtGroups.begin(); iter != virtGroups.end(); ++iter) {
|
||||
if(iter->count >= count) {
|
||||
auto start = iter->start;
|
||||
if(aligned && (start & 0xFFF) != 0) {
|
||||
auto pad = start & 0xFFF;
|
||||
if(iter->count == count + pad) {
|
||||
iter->count = pad;
|
||||
iter->end = iter->start + pad;
|
||||
start += pad;
|
||||
} else if(iter->count > count + pad) {
|
||||
auto next = iter->count - (count + pad);
|
||||
start += pad;
|
||||
iter->count = pad;
|
||||
iter->end = iter->start + pad;
|
||||
virtgroup_t group;
|
||||
group.count = next;
|
||||
group.start = start + count;
|
||||
group.end = start + count + next;
|
||||
virtGroups.insert(++iter, group); // Add this group after the current one
|
||||
} else
|
||||
continue; // Too small to fix the padding.
|
||||
} else {
|
||||
if(iter->count >= count && iter->end > low + count) {
|
||||
if(iter->start >= low) {
|
||||
auto start = iter->start;
|
||||
if(iter->count == count)
|
||||
virtGroups.erase(iter);
|
||||
else {
|
||||
iter->count -= count;
|
||||
iter->start += count * 4096;
|
||||
}
|
||||
return start;
|
||||
} else {
|
||||
auto off = low - iter->start;
|
||||
auto coff = off / 4096;
|
||||
auto start = low;
|
||||
if(iter->count == coff + count) {
|
||||
iter->count -= count;
|
||||
iter->end -= count * 4096;
|
||||
} else {
|
||||
auto oend = iter->end;
|
||||
auto ocount = iter->count;
|
||||
iter->count = coff;
|
||||
iter->end = low;
|
||||
virtgroup_t group;
|
||||
group.count = ocount - count - coff;
|
||||
group.start = low + count * 4096;
|
||||
group.end = oend;
|
||||
virtGroups.insert(++iter, group);
|
||||
}
|
||||
return start;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,13 +11,14 @@ public:
|
|||
PageManager();
|
||||
void add_region(uint32_t base, uint32_t size);
|
||||
|
||||
uint32_t map(uint32_t base, uint32_t count, bool aligned=false);
|
||||
uint32_t map(uint32_t base, uint32_t count);
|
||||
uint32_t map_contiguous(uint32_t base, uint32_t phys_low, uint32_t phys_high, uint32_t count);
|
||||
void unmap(uint32_t base, uint32_t count);
|
||||
|
||||
uint32_t alloc_phys();
|
||||
uint32_t alloc_phys(uint32_t count=1, uint32_t phys_low=0, uint32_t phys_high=0xFFFFFFFF);
|
||||
void free_phys(uint32_t page);
|
||||
|
||||
uint32_t alloc_virt(uint32_t count, bool aligned=false);
|
||||
uint32_t alloc_virt(uint32_t count, uint32_t low=0);
|
||||
void free_virt(uint32_t start, uint32_t count);
|
||||
|
||||
void debug();
|
||||
|
|
|
@ -19,6 +19,8 @@ using namespace boost::algorithm;
|
|||
|
||||
#define pagepad(expr) (((expr) & 0xFFF) ? ((expr) & ~0xFFF) + 4096 : (expr))
|
||||
|
||||
#define IN(a, b) (((b).find(a)) != (b).end())
|
||||
|
||||
#define RAM_SIZE 128*1024*1024
|
||||
#define KRAM_SIZE 128*1024*1024
|
||||
|
||||
|
@ -32,6 +34,7 @@ using namespace boost::algorithm;
|
|||
#include "xbetypes.hpp"
|
||||
#include "Xbe.hpp"
|
||||
#include "Cpu.hpp"
|
||||
#include "Gpu.hpp"
|
||||
#include "HandleManager.hpp"
|
||||
#include "PageManager.hpp"
|
||||
#include "ThreadManager.hpp"
|
||||
|
|
|
@ -4,10 +4,15 @@ map:
|
|||
- return: void *
|
||||
- virt_base: void *
|
||||
- count: uint32_t
|
||||
map_aligned:
|
||||
map_contiguous:
|
||||
- return: void *
|
||||
- virt_base: void *
|
||||
- phys_low: uint32_t
|
||||
- phys_high: uint32_t
|
||||
- count: uint32_t
|
||||
query_map_size:
|
||||
- return: uint32_t
|
||||
- base: void *
|
||||
unmap:
|
||||
- virt_base: void *
|
||||
- count: uint32_t
|
||||
|
|
Loading…
Reference in a new issue