Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
I tested my OS on real hardware by flashing it to a flash drive and it works great (PIC/GDT/IDT sets up correctly); however one problem is that the PIT timer does not acknowledge my set channel 0 frequency request:
YDeeps1 wrote:I tested my OS on real hardware by flashing it to a flash drive and it works great (PIC/GDT/IDT sets up correctly); however one problem is that the PIT timer does not acknowledge my set channel 0 frequency request:
as it runs at a much lower frequency when testing on real hardware. Perhaps I would have to use APIC? (testing on CPU Intel Q6600).
On VirtualBox the timer runs at the expected frequency and I do not have any leads to go on.
Would love some information on this! Thank you.
I don't know what your actual problem is but PIT runs quite well on real hardware, at least from my experience.
Perhaps try other emulators, like VMware or QEMU and see if it works there.
As for LAPIC, you could use it but you would need some other timer to calibrate it.
YDeeps1 wrote:it runs at a much lower frequency when testing on real hardware.
How are you measuring the frequency?
If you're referring to how I came to the conclusion, I setup a small text update every time an IRQ0 interrupt came and added them to the total. The frequency was roughly 16-18 which lines up with the default PIT frequency as opposed to the 100x/s set (which works correctly on VirtualBox).
Other than that everything else works fine such as the EOI and everything data line wise.
Last edited by YDeeps1 on Tue Sep 21, 2021 4:31 pm, edited 1 time in total.
YDeeps1 wrote:I tested my OS on real hardware by flashing it to a flash drive and it works great (PIC/GDT/IDT sets up correctly); however one problem is that the PIT timer does not acknowledge my set channel 0 frequency request:
as it runs at a much lower frequency when testing on real hardware. Perhaps I would have to use APIC? (testing on CPU Intel Q6600).
On VirtualBox the timer runs at the expected frequency and I do not have any leads to go on.
Would love some information on this! Thank you.
I don't know what your actual problem is but PIT runs quite well on real hardware, at least from my experience.
Perhaps try other emulators, like VMware or QEMU and see if it works there.
As for LAPIC, you could use it but you would need some other timer to calibrate it.
Emulators work fine. It's just that the PIT will not change the frequency to my requested value on real hardware.
YDeeps1 wrote:If you're referring to how I came to the conclusion, I setup a small text update every time an IRQ0 interrupt came and added them to the total.
Are you sure you're not missing any ticks? Updating the screen on every tick might take long enough that you miss some.
What motherboard are you using? Maybe the chipset doesn't contain a complete i8254, or maybe the BIOS configures a different timer as the IRQ0 source by default.
YDeeps1 wrote:On VirtualBox the timer runs at the expected frequency and I do not have any leads to go on.
How did you manage to get VirtualBox to run at "expected" speeds? In my experience VirtualBox is horrible with the PIT, often running at 10% speed. VMware is fine, QEMU is fine, Bochs is fine, but not VirtualBox.
Here's how I init the PIT. It runs fine on all the hardware I've tested.
YDeeps1 wrote:If you're referring to how I came to the conclusion, I setup a small text update every time an IRQ0 interrupt came and added them to the total.
Are you sure you're not missing any ticks? Updating the screen on every tick might take long enough that you miss some.
What motherboard are you using? Maybe the chipset doesn't contain a complete i8254, or maybe the BIOS configures a different timer as the IRQ0 source by default.
I am certain. In fact I tested it on a semi-ancient machine I have from the 2000s and it worked just fine. The ticks go up about every hundred per second and on the machine I tested on previously, it only went up by about 20 ticks per second (it's very difficult to confuse these).
The machine I tested on is a cheap MSI motherboard (G41M-S03). I did also initially think there is something funky going on with the implementations. If all else fails I may give the APIC a go and go through with the configurations.
YDeeps1 wrote:On VirtualBox the timer runs at the expected frequency and I do not have any leads to go on.
How did you manage to get VirtualBox to run at "expected" speeds? In my experience VirtualBox is horrible with the PIT, often running at 10% speed. VMware is fine, QEMU is fine, Bochs is fine, but not VirtualBox.
Here's how I init the PIT. It runs fine on all the hardware I've tested.
void init_pit(uint32_t freq) {
frequency = freq; // frequency is a global variable
uint32_t pitfreq = 1193181 / freq;
outb(0x43, 0x34);
outb(0x40, (uint8_t)(pitfreq));
outb(0x40, (uint8_t)(pitfreq >> 8));
}
Also, is there a reason you are using Mode 3 (square wave generator) rather than Mode 2 (rate generator)?
No reason really other than I must've misread/misset the bits. I changed it to rate generators now though (not that it matters in this issue though).
(I did test it to make sure before I sounded stupid )
YDeeps1 wrote:In fact I tested it on a semi-ancient machine I have from the 2000s and it worked just fine.
That doesn't mean the newer machine is fast enough to update the display 100 times per second. (I don't think this is actually the issue, but you should still try to rule it out - for example, wait for five ticks before updating the display.)
YDeeps1 wrote:The machine I tested on is a cheap MSI motherboard (G41M-S03).
This board has an ICH7 southbridge, so any issues with the PIT should be fairly well-known (to OS developers at least), but I can't find any. Maybe there's a problem with io_port::bit_8::out()? I don't know what could be wrong with it, though.
Incidentally, the ICH7 datasheet mentions that timer 0 is typically programmed for mode 3, so it should still work even if mode 2 makes more sense.
YDeeps1 wrote:In fact I tested it on a semi-ancient machine I have from the 2000s and it worked just fine.
That doesn't mean the newer machine is fast enough to update the display 100 times per second. (I don't think this is actually the issue, but you should still try to rule it out - for example, wait for five ticks before updating the display.)
YDeeps1 wrote:The machine I tested on is a cheap MSI motherboard (G41M-S03).
This board has an ICH7 southbridge, so any issues with the PIT should be fairly well-known (to OS developers at least), but I can't find any. Maybe there's a problem with io_port::bit_8::out()? I don't know what could be wrong with it, though.
Incidentally, the ICH7 datasheet mentions that timer 0 is typically programmed for mode 3, so it should still work even if mode 2 makes more sense.
Oh I did actually initially try updating it every 50 ticks but it was still very slow so that's ruled out.
I'll also try playing around with the modes and different settings in case this makes a difference and to check if the PIT is actually acknowledging anything I'm sending it.
So strange. I performed a read-back on both before setting and after setting and the results come back as expected (bits change + matches with VM) so there should be no reason for it not to change the ticking frequency. It may indeed be faulty but I just haven't noticed since all operating systems I've ever used on it used APIC instead?
Turns out I was looking in the wrong place all along. There's nothing wrong with the PIT, but with doing math operations on floating point numbers. For some reason dividing the base frequency to get the desired frequency and casting it to an unsigned number, it just returns 0 on the real machine while the VM does the calculation without a problem? Is there something I missed which results in me not being able to do float operations correctly?
On another test when simply declaring a floating point number and casting it to an integer, it goes to far side of a negative 32 bit number.
YDeeps1 wrote:Is there something I missed which results in me not being able to do float operations correctly?
Sounds like you missed initializing the CPU's float units. Without proper initialization, float operations may either cause exceptions or silently return the wrong values.
Kernels are usually written and compiled to avoid operations that require extended registers the way floating-point operations do. Using extended registers in your kernel means your kernel has to save and restore those registers on every entry and exit, which can be a lot of overhead (especially since some x86 CPUs have over 2kiB of extended registers).
The code you provided to demonstrate the problem doesn't have any float operations.
I had this issue before, the floating point working in virtual box, but not other vm or hardware.
You need to initialize fpu first there are codes for this on the wiki, essentially enabling it, setting control Word flags etc
For some reason it worked fine in virtual box without this.
Maybe you can use sse instead.
Its true its probably not very good to use floats in kernel, but from what i could see the timer is the only place float is really going to be useful to compute precise timer , there are not much other place where you deal with fractional numbers, and timer is only initialized at first most likely before the task manager or userland kicks in so it should be harmless on the task switching side.