Hi,
DavidCooper wrote:Brendan wrote:I'd estimate roughly one week for instruction decoding and framework (e.g. functions to simplify addressing modes, so that something like "[eax*8+ebx+1234]" gets simplified into an actual address).
The addressing in real mode is a bit simpler than that, but it's still the most complex part of the emulator to do.
The addressing in real mode is almost exactly the same as it is in 32-bit protected mode. The only difference is the default code size (e.g. if the operand size override prefixes and address size override prefixes mean "use 32-bit and not 16-bit" or "use 16-bit and not 32-bit").
DavidCooper wrote:Then I'd allow one hour per instruction, ignoring FPU, MMX, SSE and AVX. There's about 70 general purpose instructions, so that adds up to another few weeks.
Most of them are dead easy and should only take minutes.
Something that looks simple like "add reg32,immediate" wouldn't be too hard and should only take a few minutes if your framework (above) is good, and if you've already got code to handle setting the condition flags in EFLAGS correctly. Supporting all of the different variations of "add" and handling all the corner cases correctly is going to take longer. Consider something like "lock add [gs:esp],bx" where GS:ESP = 0x000FFFFE and A20 happens to be disabled. Now consider writing some real mode code to test each variation of "ADD", including all the "should work" cases and all the "should generate an exception" cases (and running this test code inside your emulator and on real hardware and comparing the differences).
DavidCooper wrote:On top of that, you'd need code to setup the virtual address space,
Nothing to set up in my case as I don't use paging yet, but even when I do it will run in an area where the virtual addresses are the same as the physical ones.
If you're not doing it properly and just recycling the original BIOS and the original video ROM, then you won't need to setup much.
If you are doing it properly and using your own dummy BIOS, and using the video card's BARs in PCI configuration space to get a fresh/clean copy of the video ROM; then "virtual addresses are the same as the physical addresses" is an annoying pain in the neck. If you're not using paging, then the emulator can do "guest physical address to host physical address" conversion in software (which is probably harder and slower than using paging).
DavidCooper wrote:code to find the correct version of the video card's ROM (e.g. video card's ROM may contain several images, where only one of them is for "PC BIOS" and is copied to 0x000C0000),
I would have thought this would be set up by the BIOS on booting, but if it's something that changes every time you change screen mode, maybe I'll have to use real mode when changing screen mode and only emulate the code for changing the start-of-display position and for the windor function.
If the firmware is "PC BIOS" and if the video card is the first video card and if the boot code can't do anything to screw things up (including trashing the original BIOS's IVT or data areas, putting the video card into a state the video ROM isn't expecting, messing with PCI bridges, etc); then you could assume it's safe to recycle the original BIOS and video ROM. I don't like silly restrictions or potentially wrong assumptions; and therefore I'd do it properly and not use the original BIOS or the original video ROM. For example, if it's done properly then (with enough extra work) it might be possible to use VBE when the firmware is EFI; and (with enough extra work) might be possible to have 3 instances of the emulator for 3 different video cards (and mess with "legacy IO port and memory mapped IO" routing in the PCI host and bridges to make it look like all video cards share the same IO ports and memory ranges). It might also be possible to re-use the same real mode emulator for things like network card and SCSI controller ROMs (if it's done right).
DavidCooper wrote:code to handle PCI configuration space access and IO port access (to ensure the video card's ROM doesn't mess with anything it shouldn't and possible emulate parts of it),
If it was going to mess things up, wouldn't it already be doing that when using the BIOS directly?
Code in the video ROM may assume certain pieces of hardware are in a certain state, and these assumptions may be perfectly correct when the video ROM's code is running in real mode on the real BIOS; but after your OS has initialised (reconfigured) most of the hardware all the assumptions that were correct are now problems that your emulator has to handle.
On top of that I'd want to use some
defensive programming and make sure that (for e.g.) badly written and/or buggy video ROMs can't completely screw my OS. For a simple example, if the video ROM happens to accidentally write to 0x12345678 then it may never cause a problem on real hardware in real mode; but the same bug can trash your kernel's data or something and it'd be nice to use the emulator as a type of "sandbox" to prevent that. An "extreme" OS developer might even use the "sandbox" nature of the emulator to protect against malicious code injection (e.g. where the video ROM's code has been tampered with deliberately in an attempt to bypass the OS's security), just because it's so easy for an emulator to protect against these sorts of things when it is done right.
DavidCooper wrote:code to initialise the video card's ROM that mimics the BIOS POST (there's specifications for that somewhere but I can't remember where - be warned it includes "pre-boot environment memory management").
Again this isn't something that's going to happen when changing the window position or the display start position. I don't know if it's an issue when changing screen mode.
It's an issue for "initialising that specific video card's ROM properly before using it"; and only applies when you're not recycling the original BIOS and original video ROM.
DavidCooper wrote:Finally you'd want to create an IVT and dummy BIOS,
There's shouldn't be a need to emulate everything that can be done in real mode - I was assuming that the code I need to emulate would never want to run an int instruction, but maybe that's wrong.
Nothing prevents the video ROMs code from calling any of the BIOS functions for any reason. Most video cards probably don't have a good reason to do this, but at a minimum you'd want to be able to detect when the video card is attempting to call BIOS functions that your emulator doesn't emulate.
DavidCooper wrote:One important question though: does the video rom ever generate interrupts? I had gained the impression that it doesn't, and I've certainly found that if I call screen-related functions with the interrupts disabled they seem to work fine, but maybe the BIOS enables them at the start of a function and puts them back as they were afterwards.
Nothing prevents the video card from generating an IRQ. For example, before switching video modes it might do "HLT" in a loop until a vertical retrace IRQ occurs or something. I'd assume that most video cards don't generate IRQs and most video card ROMs don't use them, and therefore it's important to cover cases where these assumptions happen to be wrong. At a minimum you'd want to be able to detect when the video card is attempting to use IRQs (e.g. trap writes to the IVT and the PIC chips during the "emulated POST" that you weren't planning to have) so that you know if any video card ever tries it.
Also don't forget that a video card might do other annoying things, like polling the BIOS's "ticks since midnight" variable, or relying on FPU instructions (and maybe even using IRQ13 for floating point errors).
Basically you're right, in that 1 week might be enough time to write a half-assed emulator that "works" for the limited number of computers and video cards you've got access to. Of course "works for me" may be the worst thing that can happen - I wouldn't want to receive hundreds of "It crashed for some reason and I can't give you any hints why, and I'm going to tell everyone that will listen that your OS is unstable crap" emails from unfortunate end-users after the OS is released.
Cheers,
Brendan