Initializing the PIT in C++

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.
Post Reply
User avatar
austanss
Member
Member
Posts: 377
Joined: Sun Oct 11, 2020 9:46 pm
Location: United States

Initializing the PIT in C++

Post by austanss »

Hi,
I read the wiki article on the PIT here: https://wiki.osdev.org/PIT#PIT_Channel_0_Example_Code

I read the example code, but I had an issue. The code is written in assembly for x86-32, and my kernel is in x86-64. I could try my hardest to translate the code, but with the sheer volume of code there, I don't think I would be able to pull it off.

Does anyone know any links/resources to PIT initialization example code (preferably in C++) for x86-64?
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Initializing the PIT in C++

Post by vvaltchev »

On: http://www.osdever.net/bkerndev/Docs/pit.htm
There's a simple example in C. In C++, it will be exactly the same.

Code: Select all

void timer_phase(int hz)
{
    int divisor = 1193180 / hz;       /* Calculate our divisor */
    outportb(0x43, 0x36);             /* Set our command byte 0x36 */
    outportb(0x40, divisor & 0xFF);   /* Set low byte of divisor */
    outportb(0x40, divisor >> 8);     /* Set high byte of divisor */
}
It's not extremely precise, but it's a start point. With this logic, at 100 Hz, I believe you'll have a clock skew of a few seconds per day. Just replace 1193180 with 1193182.

Note: you'll also need to implement the outportb() function. A possible implementation in GNU C is:

Code: Select all

static inline void outb(unsigned short port, unsigned char val)
{
   asm volatile(
      "outb %[value], %[port]"
      : /* no output */
      : [value] "a"(val), [port] "Nd"(port)
   );
}
Note[2]: it's not possible to have an implementation in ISO C, simply because there's no such feature as the "inline assembly" in the ISO C.
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Initializing the PIT in C++

Post by vvaltchev »

P.S. the link I sent you is part of the "Bran's Kernel Development Tutorial":
http://www.osdever.net/tutorials/view/b ... t-tutorial

The tutorial is a nice starting point BUT, it has several bugs in it. See our wiki page about that:
https://wiki.osdev.org/Bran%27s_Kernel_ ... Known_Bugs

Still, despite the bugs, you might learn more than a few things there, start experimenting on your own, insult tutorial's author while fixing some of his bugs, and have a lot of fun in the meanwhile :-)
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
gonzo
Posts: 12
Joined: Mon Dec 03, 2018 4:10 pm

Re: Initializing the PIT in C++

Post by gonzo »

Have a look at IncludeOS! It implements all these devices, including PIT. Note that it doesn't really use the PIT directly as a timing system, only as a backend for timers when there is nothing better. So, the PIT is mostly just a measurement device to calibrate the LAPIC timer.
Post Reply