HPET: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
(general capabilities and configuration registers)
Line 199: Line 199:
|Overall enable.
|Overall enable.
0 - main counter is halted, timer interrupts are disabled
0 - main counter is halted, timer interrupts are disabled

1 - main counter is running, timer interrupts are allowed if enabled
1 - main counter is running, timer interrupts are allowed if enabled
|}
|}

Revision as of 12:06, 24 November 2013

This page is a work in progress.
This page may thus be incomplete. Its content may be changed in the near future.
This page is not meant as a full description of HPET, only as a lightweight introduction. If you need any information not covered by this article, consult the HPET specification.

Preface

HPET, or High Precision Event Timer, is a piece of hardware designed by Intel and Microsoft to replace older PIT and RTC. It consists of (usually 64-bit) main counter (which counts up), as well as from 3 to 256 32 or 64 bit wide comparators. HPET is programmed using memory mapped IO, and the base address of HPET can be found using ACPI.

Detecting HPET using ACPI

The HPET specification defines an ACPI 2.0 table that is to be used to detect presence, address and capabilities of HPET present in the system. If this table doesn't exist, you should assume there is no HPET and you should fall back to PIT.

    struct address_structure
    {
        uint8_t address_space_id;    // 0 - system memory, 1 - system I/O
        uint8_t register_bit_width;
        uint8_t register_bit_offset;
        uint8_t reserved;
        uint64_t address;
    } __attribute__((packed));

    struct description_table_header
    {
        char signature[4];    // 'HPET' in case of HPET table
        uint32_t length;
        uint8_t revision;
        uint8_t checksum;
        char oemid[6];
        uint64_t oem_tableid;
        uint32_t oem_revision;
        uint32_t creator_id;
        uint32_t creator_revision;
    } __attribute__((packed));

    struct hpet : public description_table_header
    {
        uint8_t hardware_rev_id;
        uint8_t comparator_count:5;
        uint8_t counter_size:1;
        uint8_t reserved:1;
        uint8_t legacy_replacement:1;
        pci_vendor_t pci_vendor_id;
        address_structure address;
        uint8_t hpet_number;
        uint16_t minimum_tick;
        uint8_t page_protection;
    } __attribute__((packed));

HPET - timer vs comparators

There is just one up counting main counter in the timer, but interrupt generation is handled by *comparators*. There's from 3 to 256 comparators, and the exact amount is indicated by comparator_count field in the above hpet structure. Keep in mind you have to initialize both the main counter and all of the comparators. Also, the routing as well as allowed routing of comparator interrupts is independent, so you have to detect and set it up for each of them individually. More information on this procedure is provided further in the text.

HPET operating modes

HPET offers three operating modes; as of now, this article describes two of them: one-shot (also called "non-periodic" by the specification) and periodic mode.

One-shot mode

In non-periodic mode, the OS programs one of timer's comparator registers with value of main counter that is to trigger an interrupt. If the timer is set to 32 bit mode, it will also generate an interrupt when the counter wraps around. The comparator register's value is never written by the hardware, you are free to write to it and read from it at any time, therefore you can change at what value in the main counter the interrupt will be generated.

Every comparator in HPET must support non-periodic mode.

Periodic mode

Periodic mode is more tricky than non-periodic mode. For periodic mode, similarly to one-shot mode, you write a value at which an interrupt shall be generated to the comparator register. When the interrupt is generated, however, the hardware will increase the value in comparator register by the last value written to it! This is a consequence of HPET's main counter being up-counting.

So, if the main counter's value is 12345 when we set the timer up, and we write 12456 to comparator (i.e. the interrupt should trigger 111 time units from now), when the interrupt triggers, 12456 will be added to the comparator register, so it will become 24912, which is 12456 time units from the first interrupt. There are two techniques to deal with this problem; they will both be described in later part of the article.

Comparators are NOT required to support this mode; you must detect this capability when initializing a comparator. More information on this is provided further in the article.

Interrupt routing

HPET supports three interrupt mapping options: "legacy replacement" option, standard option, and FSB option.

"Legacy replacement" mapping

In this mapping, HPET's timer (comparator) #0 replaces PIT interrupts, whereas timer #1 replaces RTC's interrupts (in other words, PIC and RTC will no longer cause interrupts). While the HPET specification provides the following table describing the routing of timers #0 and #1 in this mapping, it is recommended to at least check the routing of IRQ0 and IRQ8 to I/O APIC in ACPI tables.

Timer PIC mapping IOAPIC mapping
0 IRQ0 IRQ2
1 IRQ8 IRQ8
N As per IRQ Routing Field As per IRQ Routing Field

Standard mapping

In standard mapping, each timer has its own interrupt routing control. Allowed I/O APIC inputs are found by reading timer's capabilities register.

FSB mapping

This mapping is almost identical to PCI's Message Signaled Interrupts. The "Timer N FSB Interrupt Route Register" which defines how FSB interrupts are configured can be found in the specification. FSB interrupts are enabled using "Tn_FSB_EN_CNF" field in timer's configuration register. This mapping mode will not be further discussed in this

HPET registers

The following table and field descriptions can also be found in the specification. "Offset" means offset from the address defined in address field of hpet struct. The following table skips reserved registers defined in the specification.

Offset Register Type
0x000 - 000x7 General Capabilities and ID Register Read only
0x010 - 0x017 General Configuration Register Read/write
0x020 - 0x027 General Interrupt Status Register Read/write clear
0x0F0 - 0x0F7 Main Counter Value Register Read/write
(0x100 + 0x20 * N) - (0x107 + 0x20 * N) Timer N Configuration and Capability Register Read/write
(0x108 + 0x20 * N) - (0x10F + 0x20 * N) Timer N Comparator Value Register Read/write
(0x110 + 0x20 * N) - (0x117 + 0x20 * N) Timer N FSB Interrupt Route Register Read/write

General Capabilities and ID Register

Bits Name Description
63:32 COUNTER_CLK_PERIOD Main counter tick period in femptoseconds (10^-15 seconds). Must not be zero, must be less or equal to 0x05F5E100, or 100 nanoseconds.
31-16 VENDOR_ID This field should be interpreted similarly to PCI's vendor ID.
15 LEG_RT_CAP If this bit is 1, HPET is capable of using "legacy replacement" mapping.
14 Reserved -
13 COUNT_SIZE_CAP If this bit is 1, HPET main counter is capable of operating in 64 bit mode.
12:8 NUM_TIM_CAP The amount of timers - 1.
7:0 REV_ID Indicates which revision of the function is implemented; must not be 0.

General Configuration Register

Bits Name Description
63:2 Reserved -
1 LEG_RT_CNF 0 - "legacy replacement" mapping is disabled

1 - "legacy replacement" mapping is enabled

0 ENABLE_CNF Overall enable.

0 - main counter is halted, timer interrupts are disabled

1 - main counter is running, timer interrupts are allowed if enabled

General Interrupt Status Register

Main Counter Value Register

Timer N Configuration and Capability Register

Timer N Comparator Value Register

See also