Added initial PCI and Port IO support. Refactored device management.

This commit is contained in:
Cody Brocious 2016-05-20 12:05:33 -06:00
parent 6dac6e26e4
commit 8d56300d73
19 changed files with 213 additions and 61 deletions

21
Box.cpp
View file

@ -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;
}

View file

@ -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
View file

@ -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
View file

@ -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;
};

View file

@ -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();
}

View file

@ -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
View 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
View file

@ -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
View file

@ -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
View file

@ -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;

View file

@ -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);
}
}

View file

@ -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:

View file

@ -17,5 +17,3 @@
#include "liballoc.hpp"
#include "XboxKernel/KernelThunk.hpp"
#include "XboxKernel/Kernel.hpp"
#define pagepad(expr) (((expr) & 0xFFF) ? ((expr) & ~0xFFF) + 4096 : (expr))

View 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);
}

View 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
);

View file

@ -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"

View file

@ -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,

View file

@ -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"

View file

@ -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