Sorry I haven't been updating this blog as frequently as I should be. Have lots on my plate besides this emulator atm. No worries though, I'm still eager to continue updating this emulator as often as possible.
About the SVN, this is where I'll be uploading my source code updates when I see fit. Right now, the code isn't too great, and it's kinda sloppy in some areas. In fact, it's downright embarrassing in some places! Some of this stuff was just done in a rather reckless way to get stuff to work immediately. There's lots of stuff I've been meaning to add, but just haven't gotten around to doing it yet. Maybe I should focus on getting the more annoying things emulated, such as the SMBus, PIC, EEPROM, temperature monitor, PCI, X-Codes, VGA, etc. Well, the EEPROM part is easy, I mean, you don't even need to dump your own EEPROM for this emulator to work. Creating a dummy EEPROM is pretty easy anyway. All of that stuff has to be done before I can think of attempting full blown BIOS emulation (which is going to be hard).
Oh, wait. I forgot, I was supposed to explain the threading model of this emulator! *palm hitting forehead* Ugh, sorry guys. Let me explain that now. Then you'll understand why the code is structured the way it is.
In order to understand how this threading model works, we have to understand how the emulator actually works (and why it works). I'm assuming I explained this before, but here's a diagram I drew in mspaint. Hopefully it's readable/understandable enough.
Now, remember the sole purpose of Xenoborg.exe is to reserve a specific memory address that the .xbe normally has to access to do it's dirty work. The .xbe's base address is (almost) always 0x10000, and if you EVER find an .xbe file with a different base address than that, let me know right away! Pretty much all of the code executed by Xbox is located in Ram (which is located at 0x00000000 - 0x03FFFFFF (64Mb), 0x07FFFFFF for debug Xboxes (128Mb), and Chihiro Ram range can be as great as 0x40000000 (1GB)) and since .xbe files are very specific as to what memory locations to read/write, we have to give it access to it's desired base address in order for it to work (meaning we can't just allocate some buffer and throw the .xbe contents in there and expect it to work). So we give the launcher .exe file the power to reserve that address, then transfer control over to the .dll file. This means that we never return to the .exe until it's time to exit because the .exe contents will be overwritten completely and restored at exit time.
Now we need 3 threads. One thread handles the message pump for the window being rendered to because DllMain is not suited to handle a message pump like WinMain is, so I created a thread to contain that loop. The second handles actual emulation loop, and the third just updates interrrupts and other time related things. These threads are created/organized as they are in this diagram.
Make sense? So far, it appears to work fine, but the CPU usage is really high because I suck at writing threaded code. Maybe it's the thread priorities causing problems, I dunno. If you can think of a better way to thread this, let me know because my knowledge of threading is limited.
Any suggestions? Speak up, I'd like to hear 'em!
Shogun.
Great work right there!
ReplyDeleteHey man, its great to see a new xbox emulator on the works!
ReplyDeleteThis is waaayyy above my knowledge of reverse engineering, can't help you there :/
But keep it up, it looks like you're building on solid foundations, I know its a long process, I am sure it'll be the best emulator =)
Your choice seems logical.
ReplyDeleteYou should check out which thread sucks out the CPU resources, and then which section. Ideally you want to have as much idle time as possible, so there might be a lot of unwanted activity.
Not sure if it is too late or not, but I would highly recommend the use the the C++ POCO framework (http://pocoproject.org/). It is multi-platform and it brings many amazing tools like threading, memory management, message passing between threads, cache management.
this is awesome!! Best wishes on your work and I wish you well! The end result, xbox1 and Chihiro games emulation, fantastic!! = )
ReplyDelete"Makes sense?" - No, it doesn't.
ReplyDeleteHere is why:
If you are going for bios emulation you need a binary loader, not an xbe loader [that's done in the kernel, which is one levels higher than the bios (roughly: hardware -> bios -> kernel -> xtl -> application -> drivers -> frontends for xtl)].
(Also the 0x10000 is hardcoded as baseimage address. The xbox will refuse to load anything else unless you use a debug bios [but that would require dynamic linking etc. which is something which you wouldn't want to HLE anyway])
Also, you don't need these specific addresses because the xbox ABI seems to assume flat memory. That means you can abuse the registers to move the code to any region. This, however, is way more tricky when you plan to do bios emulation because the xbox will reserve the virtual memory itself and it will also fill the GDT and LDT.
DllMain CAN process window messages - You can even handle window messages in a remote process.
The threading model makes no sense either to me. Maybe I missunderstand something, but there are some obvious flaws in its design:
- If it handles code execution AND hardware in one thread, that would mean that the hardware can't work in the background. This however is necessary for the GPU, the OHCI controller and other hardware which might wants to callback or has the ability to timeout.
Also on windows exception handling is always done in interrupts or DPCs which means you don't have to have a thread for it - the calling thread will always be the one which caused the exception afaik. Forwarding the error to another thread is almost impossible and not recommended because the thread which you are trying to forward the exception to, could possibly also throw an exception during that time. (exception = Actual exception, not some virtual SEH crap).
Also, the interrupts must be generated by the hardware. If you have to use shared regions for the IPC you will have way too many cache invalidations to get good performance. So the only logical choice is to generate them in hardware emulation - in fact, not doing so is almost impossible.
Furthermore, again, when going with bios emulation, you are VERY restricted about most of this because the interrupts might have to be timed very carefully so they aren't lost or issued twice.
Also, you have to keep in mind that your renderer (let's say OGL via an NV2A emulator) probably wants to stick to it's initial thread context. So you are very restriced too about where and how hardware emulation happens [unless you want to mess with the windows TLS].