So in my previous blogpost I briefly spoke about switching to C++ from pure C. I really like it so far. Since the majority of code I write at work is C#, I've become very accustomed to object oriented thinking.
Currently, the driver model, device model, interrupt handling, terminal, and more have been migrated to C++. Also, I implemented a LinkedList<T> class.
As you can see, there is one "root" base class that is the base to all driver implementations. One layer below that are type classes, which allow for a layer of abstraction based on the kind of device. On the bottom layer are the concrete implementations.
Usually, a driver has a relation to a "device". For instance, the PITDriver has 3 PITDevice instances, one for each channel of the PIT. The AtaDriver is able to detect the devices that are connected to the computer, and will create an AtaDevice instance for each of them:
This way, I can tell my DeviceManager instance to give me a Keyboard driver, like this:
Note that the KERNEL macro is just a shortcut to access the kernel singleton.
Before the switch to C++, the only way to register Interrupt Service Routines was to use a this arbitrarily named function "idt_register" that would add it to a table. Now, there is one manager class, which contains a linked list of instances of type InterruptHandler. These classes contain a Handle() function to execute whatever code needs to be executed on interrupt.
There is also one single generic ISR which will simply ask the manager to return the InterruptHandler for a given IRQ. The ISR will then, in turn, call the (virtual) Handle method.
One base class FileSystem is defined, which contains all virtual methods a file system should contain. The class VirtualFileSystem inherits from FileSystem, and acts as a Proxy because it propagates all calls to the concrete FileSystem implementation. Currently only FAT16 is supported, but this can easily be extended by simply registering a new class.
So, implementing a terminal command to print a directory listing is as simple as:
Pay attention to the GetVfs() call to the kernel instance. This will return the VFS, and allows us to create new files, open files, list files, delete files, etc.
The terminal has been extended with a "status bar" at the top. The idea is that this status bar does not scroll along with the rest of the terminal, so it can contain some information which is always interesting to show. Currently it shows the current date/time, and the current RAM usage. See below for a screenshot.
The date and time is retrieved from the CMOS chip.
If you have been paying close attention, you might have noticed in the screenshot above that I added PCI support. Kind of. It's very basic at the moment, but the PCI manager actually retrieves the CPU I/O ports from the PCI configuration address space for the IDE controller. The ATA driver is then registered by the PCI manager with the correct data.
Also, C++ RTTI sucks. It is one of few evidences that C++ is just built on top of C, instead of being designed from scratch. I have implemented support for the Visual C++ RTTI ABI, and it really felt like a necessary evil.
The terminal has received a new feature: press TAB to cycle through previous commands. I was growing tired of having to re-enter all commands every time, so I implemented this feature.
I should rewrite my keyboard driver. I thought I had scan codes/keycodes covered pretty well, but I made a few design errors here and there. As a result, the current keyboard driver can not support more than 0xFF keycodes. "Exotic" keys like the function keys, directional keys are not working because of that.
I have been tinkering with higher resolutions for the terminal. Not possible with GRUB as the bootloader, because it's set to default 80x25. The easiest way is to use VBE but this requires my own bootloader. There are more reasons to write my own bootloader ,such as ACPI, and some more I forgot ;-). So that might happen as well.