mirror of
https://github.com/daeken/Zookeeper.git
synced 2024-05-14 19:09:33 -04:00
Added initial PCI and Port IO support. Refactored device management.
This commit is contained in:
parent
6dac6e26e4
commit
8d56300d73
21
Box.cpp
21
Box.cpp
|
@ -21,3 +21,24 @@ Box::Box() {
|
|||
|
||||
gpu = new Gpu();
|
||||
}
|
||||
|
||||
void Box::add_mmio(uint32_t base, uint32_t pages, Device *dev) {
|
||||
auto memblock = new uint8_t[pages * PAGE_SIZE];
|
||||
cpu->hv->map_phys(memblock, base, pages * PAGE_SIZE);
|
||||
for(auto i = 0; i < pages; ++i) {
|
||||
mmio[base] = dev;
|
||||
dev->mmioBuffers[base] = memblock;
|
||||
cpu->map_pages(base, base, 1, false); // Pages are not marked present
|
||||
base += PAGE_SIZE;
|
||||
memblock += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void Box::add_port(uint32_t port, Device *dev) {
|
||||
ports[port] = dev;
|
||||
}
|
||||
|
||||
void Box::add_pci(uint16_t bus, uint16_t slot, Device *dev) {
|
||||
auto addr = (((uint32_t) bus) << 16) | slot;
|
||||
pci[addr] = dev;
|
||||
}
|
||||
|
|
7
Box.hpp
7
Box.hpp
|
@ -5,6 +5,9 @@
|
|||
class Box {
|
||||
public:
|
||||
Box();
|
||||
void add_mmio(uint32_t base, uint32_t pages, Device *dev);
|
||||
void add_port(uint32_t port, Device *dev);
|
||||
void add_pci(uint16_t bus, uint16_t slot, Device *dev);
|
||||
|
||||
Cpu *cpu;
|
||||
Gpu *gpu;
|
||||
|
@ -15,6 +18,10 @@ public:
|
|||
IOManager *io;
|
||||
Debugger *debugger;
|
||||
|
||||
map<uint32_t, Device *> mmio;
|
||||
map<uint32_t, Device *> ports;
|
||||
map<uint32_t, Device *> pci;
|
||||
|
||||
uint32_t xbebase;
|
||||
};
|
||||
|
||||
|
|
56
Cpu.cpp
56
Cpu.cpp
|
@ -64,18 +64,6 @@ void Cpu::map_pages(uint32_t virt, uint32_t phys, uint32_t count, bool present)
|
|||
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 * PAGE_SIZE];
|
||||
hv->map_phys(memblock, base, pages * PAGE_SIZE);
|
||||
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 += PAGE_SIZE;
|
||||
memblock += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void Cpu::flip_page(uint32_t base, bool val) {
|
||||
auto dir = (uint32_t *) (mem + 64*ONE_MB);
|
||||
auto table = (uint32_t *) (mem + (dir[base >> 22] & ~PAGE_MASK));
|
||||
|
@ -171,9 +159,9 @@ void Cpu::run(uint32_t eip) {
|
|||
auto swap = true;
|
||||
uint32_t in_mmio;
|
||||
do {
|
||||
if(break_in) {
|
||||
if(do_break_in) {
|
||||
box->debugger->enter();
|
||||
break_in = false;
|
||||
do_break_in = false;
|
||||
}
|
||||
auto exit = hv->enter();
|
||||
|
||||
|
@ -213,11 +201,11 @@ void Cpu::run(uint32_t eip) {
|
|||
case 4: { // MMIO Write
|
||||
auto page = in_mmio & ~PAGE_MASK;
|
||||
flip_page(page, false);
|
||||
auto dev = mmio[page];
|
||||
auto buf = dev->buffers[page];
|
||||
auto dev = box->mmio[page];
|
||||
auto buf = dev->mmioBuffers[page];
|
||||
auto off = in_mmio & PAGE_MASK;
|
||||
volatile auto val = (uint32_t *) ((uint8_t *) buf + off);
|
||||
dev->write(in_mmio, *val);
|
||||
dev->writeMmio(in_mmio, *val);
|
||||
single_step = 0;
|
||||
in_mmio = 0;
|
||||
break;
|
||||
|
@ -233,10 +221,10 @@ void Cpu::run(uint32_t eip) {
|
|||
}
|
||||
case 14: {
|
||||
auto page = exit.address & ~PAGE_MASK;
|
||||
if(IN(page, mmio)) {
|
||||
if(IN(page, box->mmio)) {
|
||||
auto off = exit.address & PAGE_MASK;
|
||||
auto dev = mmio[page];
|
||||
auto buf = dev->buffers[page];
|
||||
auto dev = box->mmio[page];
|
||||
auto buf = dev->mmioBuffers[page];
|
||||
auto write = FLAG(exit.error_code, 2);
|
||||
in_mmio = exit.address;
|
||||
flip_page(page, true);
|
||||
|
@ -244,7 +232,7 @@ void Cpu::run(uint32_t eip) {
|
|||
single_step = 4;
|
||||
} else {
|
||||
volatile auto val = (uint32_t *) ((uint8_t *) buf + off);
|
||||
*val = dev->read(exit.address);
|
||||
*val = dev->readMmio(exit.address);
|
||||
single_step = 3;
|
||||
}
|
||||
} else {
|
||||
|
@ -274,8 +262,30 @@ void Cpu::run(uint32_t eip) {
|
|||
stop = true;
|
||||
break;
|
||||
case PortIO: {
|
||||
hv->reg(EIP, hv->reg(EIP) + exit.instruction_length);
|
||||
cout << "Port IO: " << hex << exit.port << endl;
|
||||
if(IN(exit.port, box->ports)) {
|
||||
auto dev = box->ports[exit.port];
|
||||
if(exit.port_direction) {
|
||||
auto val = hv->reg(EAX);
|
||||
if(exit.port_size == 8)
|
||||
val &= 0xFF;
|
||||
else if(exit.port_size == 16)
|
||||
val &= 0xFFFF;
|
||||
dev->writePort(exit.port, exit.port_size, val);
|
||||
}
|
||||
else {
|
||||
auto val = dev->readPort(exit.port, exit.port_size);
|
||||
if(exit.port_size == 8)
|
||||
hv->reg(EAX, (hv->reg(EAX) & 0xFFFFFF00) | (val & 0xFF));
|
||||
else if(exit.port_size == 16)
|
||||
hv->reg(EAX, (hv->reg(EAX) & 0xFFFF0000) | (val & 0xFFFF));
|
||||
else
|
||||
hv->reg(EAX, val);
|
||||
}
|
||||
hv->reg(EIP, hv->reg(EIP) + exit.instruction_length);
|
||||
} else {
|
||||
cout << "Unknown port: " << hex << exit.port << endl;
|
||||
stop = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Ignore:
|
||||
|
|
13
Cpu.hpp
13
Cpu.hpp
|
@ -2,21 +2,12 @@
|
|||
|
||||
#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, 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);
|
||||
|
@ -41,7 +32,5 @@ public:
|
|||
uint8_t *mem, *kmem;
|
||||
int single_step = 0;
|
||||
bool stop = false;
|
||||
bool break_in = false;
|
||||
|
||||
map<uint32_t, MMIOReceiver *> mmio;
|
||||
bool do_break_in = false;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#include "Zookeeper.hpp"
|
||||
|
||||
void break_in(bool fatal) {
|
||||
if(fatal)
|
||||
box->cpu->stop = true;
|
||||
else
|
||||
box->cpu->do_break_in = true;
|
||||
}
|
||||
|
||||
Breakpoint::Breakpoint(uint32_t _addr) : addr(_addr) {
|
||||
enable();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
#include "Zookeeper.hpp"
|
||||
|
||||
void break_in(bool fatal=false);
|
||||
|
||||
class Breakpoint {
|
||||
public:
|
||||
Breakpoint(uint32_t _addr);
|
||||
|
|
17
Device.hpp
Normal file
17
Device.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "Zookeeper.hpp"
|
||||
|
||||
class Device {
|
||||
public:
|
||||
virtual uint32_t readMmio(uint32_t addr) = 0;
|
||||
virtual void writeMmio(uint32_t addr, uint32_t value) = 0;
|
||||
|
||||
virtual void readPci(uint32_t reg, void *buffer, uint32_t length) = 0;
|
||||
virtual void writePci(uint32_t reg, void *buffer, uint32_t length) = 0;
|
||||
|
||||
virtual uint32_t readPort(uint32_t port, uint32_t size) = 0;
|
||||
virtual void writePort(uint32_t port, uint32_t size, uint32_t value) = 0;
|
||||
|
||||
map<uint32_t, void *> mmioBuffers;
|
||||
};
|
37
Gpu.cpp
37
Gpu.cpp
|
@ -1,22 +1,47 @@
|
|||
#include "Zookeeper.hpp"
|
||||
|
||||
Gpu::Gpu() {
|
||||
box->cpu->map_io(0xFD000000, 4096, (MMIOReceiver *) this); // 4096 pages * 4KB == 16MB address space
|
||||
box->add_pci(1, 0, this);
|
||||
box->add_mmio(0xFD000000, 4096, this); // 4096 pages * 4KB == 16MB address space
|
||||
box->add_port(0x80c0, this);
|
||||
}
|
||||
|
||||
uint32_t Gpu::read(uint32_t addr) {
|
||||
cout << format("Gpu::read(0x%08x)") % addr << endl;
|
||||
uint32_t Gpu::readMmio(uint32_t addr) {
|
||||
cout << format("Gpu::readMmio(0x%08x)") % addr << endl;
|
||||
|
||||
switch(addr) {
|
||||
case 0xfd100200:
|
||||
return 3;
|
||||
default:
|
||||
return addr;
|
||||
break_in(true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Gpu::write(uint32_t addr, uint32_t value) {
|
||||
void Gpu::writeMmio(uint32_t addr, uint32_t value) {
|
||||
if(addr > 0xfd700000 && addr <= 0xfd705000)
|
||||
return;
|
||||
cout << format("Gpu::write(0x%08x, 0x%08x)") % addr % value << endl;
|
||||
cout << format("Gpu::writeMmio(0x%08x, 0x%08x)") % addr % value << endl;
|
||||
break_in(true);
|
||||
}
|
||||
|
||||
void Gpu::readPci(uint32_t reg, void *buffer, uint32_t length) {
|
||||
cout << format("Gpu::readPci(0x%08x, %i)") % reg % length << endl;
|
||||
break_in(true);
|
||||
}
|
||||
|
||||
void Gpu::writePci(uint32_t reg, void *buffer, uint32_t length) {
|
||||
cout << format("Gpu::writePci(0x%08x, %i)") % reg % length << endl;
|
||||
break_in(true);
|
||||
}
|
||||
|
||||
uint32_t Gpu::readPort(uint32_t port, uint32_t size) {
|
||||
cout << format("Gpu::readPort(0x%04x, %i)") % port % size << endl;
|
||||
break_in(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Gpu::writePort(uint32_t port, uint32_t size, uint32_t value) {
|
||||
cout << format("Gpu::writePort(0x%04x, %i, 0x%x)") % port % size % value << endl;
|
||||
break_in(true);
|
||||
}
|
||||
|
|
14
Gpu.hpp
14
Gpu.hpp
|
@ -1,10 +1,16 @@
|
|||
#pragma once
|
||||
#include "Zookeeper.hpp"
|
||||
|
||||
class Gpu : public MMIOReceiver {
|
||||
class Gpu : public Device {
|
||||
public:
|
||||
Gpu();
|
||||
|
||||
uint32_t read(uint32_t addr);
|
||||
void write(uint32_t addr, uint32_t value);
|
||||
|
||||
uint32_t readMmio(uint32_t addr);
|
||||
void writeMmio(uint32_t addr, uint32_t value);
|
||||
|
||||
void readPci(uint32_t reg, void *buffer, uint32_t length);
|
||||
void writePci(uint32_t reg, void *buffer, uint32_t length);
|
||||
|
||||
uint32_t readPort(uint32_t port, uint32_t size);
|
||||
void writePort(uint32_t port, uint32_t size, uint32_t value);
|
||||
};
|
||||
|
|
2
HV.hpp
2
HV.hpp
|
@ -39,7 +39,7 @@ typedef struct exit {
|
|||
|
||||
// Used for port IO
|
||||
uint32_t port;
|
||||
uint32_t access_size; // 8, 16, or 32 bits
|
||||
uint32_t port_size; // 8, 16, or 32 bits
|
||||
bool port_direction; // true is OUT, false is IN
|
||||
} exit_t;
|
||||
|
||||
|
|
|
@ -107,3 +107,29 @@ void Hypercall::get_system_time(uint32_t addr) {
|
|||
auto time = ((uint64_t) stime.tv_sec) * 10000000 + ((uint64_t) stime.tv_usec) * 10;
|
||||
box->cpu->write_memory<uint64_t>(addr, time);
|
||||
}
|
||||
|
||||
void Hypercall::pci_read(uint32_t bus, uint32_t slot, uint32_t reg, uint32_t buffer, uint32_t length) {
|
||||
auto addr = (bus << 16) | slot;
|
||||
auto buf = new uint8_t[length];
|
||||
if(IN(addr, box->pci)) {
|
||||
auto dev = box->pci[addr];
|
||||
dev->readPci(reg, buf, length);
|
||||
box->cpu->write_memory(buffer, length, buf);
|
||||
} else {
|
||||
cout << format("Read from PCI device at %04x:%04x") % bus % slot << endl;
|
||||
break_in(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Hypercall::pci_write(uint32_t bus, uint32_t slot, uint32_t reg, uint32_t buffer, uint32_t length) {
|
||||
auto addr = (bus << 16) | slot;
|
||||
auto buf = new uint8_t[length];
|
||||
box->cpu->read_memory(buffer, length, buf);
|
||||
if(IN(addr, box->pci)) {
|
||||
auto dev = box->pci[addr];
|
||||
dev->writePci(reg, buf, length);
|
||||
} else {
|
||||
cout << format("Write to unknown PCI device at %04x:%04x") % bus % slot << endl;
|
||||
break_in(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,10 +198,12 @@ exit_t HVMac::enter() {
|
|||
break;
|
||||
}
|
||||
case VMX_REASON_IO: {
|
||||
// "Table 24-5. Exit Qualification for I/O Instructions"
|
||||
_exit.reason = PortIO;
|
||||
_exit.access_size = ((qual & 3) + 1) << 3;
|
||||
_exit.port = qual >> 16;
|
||||
_exit.port_direction = ((qual >> 3) & 1) == 0;
|
||||
_exit.port_size = ((qual & 3) + 1) << 3;
|
||||
_exit.port_direction = !FLAG(qual >> 3, 1);
|
||||
bailout(FLAG(qual >> 5, 1)); // No rep support
|
||||
break;
|
||||
}
|
||||
case VMX_REASON_IRQ:
|
||||
|
|
|
@ -17,5 +17,3 @@
|
|||
#include "liballoc.hpp"
|
||||
#include "XboxKernel/KernelThunk.hpp"
|
||||
#include "XboxKernel/Kernel.hpp"
|
||||
|
||||
#define pagepad(expr) (((expr) & 0xFFF) ? ((expr) & ~0xFFF) + 4096 : (expr))
|
||||
|
|
16
NightBeliever/XboxKernel/HW.cpp
Normal file
16
NightBeliever/XboxKernel/HW.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "Kernel.hpp"
|
||||
|
||||
void NTAPI kernel_HalReadWritePCISpace(
|
||||
uint32_t BusNumber,
|
||||
uint32_t SlotNumber,
|
||||
uint32_t RegisterNumber,
|
||||
void *Buffer,
|
||||
uint32_t Length,
|
||||
BOOLEAN WritePCISpace
|
||||
) {
|
||||
log("HalReadWritePCISpace(%i, %i, %i, 0x%08x, %i, %i)", BusNumber, SlotNumber, RegisterNumber, Buffer, Length, WritePCISpace);
|
||||
if(WritePCISpace)
|
||||
pci_write(BusNumber, SlotNumber, RegisterNumber, Buffer, Length);
|
||||
else
|
||||
pci_read(BusNumber, SlotNumber, RegisterNumber, Buffer, Length);
|
||||
}
|
12
NightBeliever/XboxKernel/HW.hpp
Normal file
12
NightBeliever/XboxKernel/HW.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "Kernel.hpp"
|
||||
|
||||
void NTAPI kernel_HalReadWritePCISpace(
|
||||
uint32_t BusNumber,
|
||||
uint32_t SlotNumber,
|
||||
uint32_t RegisterNumber,
|
||||
void *Buffer,
|
||||
uint32_t Length,
|
||||
BOOLEAN WritePCISpace
|
||||
);
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
#include "Dpc.hpp"
|
||||
#include "FS.hpp"
|
||||
#include "HW.hpp"
|
||||
#include "Interrupt.hpp"
|
||||
#include "Memory.hpp"
|
||||
#include "Misc.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Thread.hpp"
|
||||
#include "Timer.hpp"
|
||||
#include "Interrupt.hpp"
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#define ONE_KB 1024
|
||||
#define ONE_MB (1024 * ONE_KB)
|
||||
#define ONE_GB (1024 * ONE_MB)
|
||||
|
||||
#define PAGE_SIZE (4 * ONE_KB)
|
||||
#define PAGE_MASK (PAGE_SIZE - 1)
|
||||
|
||||
#define pagepad(expr) (((expr) & PAGE_MASK) ? ((expr) & ~PAGE_MASK) + PAGE_SIZE : (expr))
|
||||
|
||||
enum class FSFlags : int {
|
||||
READ = 0,
|
||||
WRITE = 1,
|
||||
|
|
|
@ -17,15 +17,6 @@ using namespace boost::algorithm;
|
|||
|
||||
#define bailout(expr) do { if(expr) { cout << "Bailout: " << #expr << " @ " << __FILE__ << " (" << dec << __LINE__ << ")" << endl; exit(1); } } while(0)
|
||||
|
||||
#define ONE_KB 1024
|
||||
#define ONE_MB (1024 * ONE_KB)
|
||||
#define ONE_GB (1024 * ONE_MB)
|
||||
|
||||
#define PAGE_SIZE (4 * ONE_KB)
|
||||
#define PAGE_MASK (PAGE_SIZE - 1)
|
||||
|
||||
#define pagepad(expr) (((expr) & PAGE_MASK) ? ((expr) & ~PAGE_MASK) + PAGE_SIZE : (expr))
|
||||
|
||||
#define IN(a, b) (((b).find(a)) != (b).end())
|
||||
|
||||
// Xbox has 64MB RAM, Chihiro has 128 MB RAM
|
||||
|
@ -43,6 +34,7 @@ using namespace boost::algorithm;
|
|||
#include "Hypercall.hpp"
|
||||
#include "xbetypes.hpp"
|
||||
#include "Xbe.hpp"
|
||||
#include "Device.hpp"
|
||||
#include "Cpu.hpp"
|
||||
#include "Gpu.hpp"
|
||||
#include "HandleManager.hpp"
|
||||
|
|
|
@ -55,4 +55,16 @@ io_ioctl:
|
|||
close:
|
||||
- handle: uint32_t
|
||||
get_system_time:
|
||||
- time: uint64_t *
|
||||
- time: uint64_t *
|
||||
pci_read:
|
||||
- bus: uint32_t
|
||||
- slot: uint32_t
|
||||
- reg: uint32_t
|
||||
- buffer: void *
|
||||
- length: uint32_t
|
||||
pci_write:
|
||||
- bus: uint32_t
|
||||
- slot: uint32_t
|
||||
- reg: uint32_t
|
||||
- buffer: void *
|
||||
- length: uint32_t
|
||||
|
|
Loading…
Reference in a new issue