Skip to content

Commit

Permalink
acpi: support hpet timer
Browse files Browse the repository at this point in the history
Added support for the HPET timer.

Signed-off-by: Daniele Ahmed <ahmeddan amazon c;0m >
  • Loading branch information
82marbag committed Feb 12, 2021
1 parent 86c7681 commit f669534
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 3 deletions.
2 changes: 1 addition & 1 deletion arch/x86/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
#include <console.h>
#include <drivers/pit.h>
#include <ktf.h>
#include <time.h>
#include <lib.h>
#include <percpu.h>
#include <processor.h>
#include <time.h>
#include <traps.h>

static apic_mode_t apic_mode = APIC_MODE_UNKNOWN;
Expand Down
9 changes: 8 additions & 1 deletion common/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <smp/mptables.h>
#include <smp/smp.h>

#include <drivers/hpet.h>
#include <drivers/pic.h>
#include <drivers/pit.h>
#include <drivers/serial.h>
Expand All @@ -63,6 +64,9 @@ bool_cmd("pit", opt_pit);
bool opt_apic_timer = false;
bool_cmd("apic_timer", opt_apic_timer);

bool opt_hpet = false;
bool_cmd("hpet", opt_hpet);

io_port_t com_ports[2] = {COM1_PORT, COM2_PORT};

static unsigned bsp_cpu_id = 0;
Expand Down Expand Up @@ -240,7 +244,10 @@ void __noreturn __text_init kernel_start(uint32_t multiboot_magic,
uart_input_init(get_bsp_cpu_id());

/* Initialize timers */
if (opt_pit)
bool hpet_initialized = false;
if (opt_hpet)
hpet_initialized = init_hpet(get_bsp_cpu_id());
if (!hpet_initialized && opt_pit)
init_pit(get_bsp_cpu_id());
if (opt_apic_timer)
init_apic_timer();
Expand Down
92 changes: 92 additions & 0 deletions drivers/hpet.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright © 2020 Amazon.com, Inc. or its affiliates.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <drivers/hpet.h>
#include <ioapic.h>

bool init_hpet(uint8_t dst_cpus) {
acpi_hpet_t *hpet;
mfn_t hpet_base_mfn;
volatile acpi_hpet_timer_t *config;
volatile acpi_hpet_general_t *general;
volatile uint64_t *main_counter;

printk("Initializing HPET\n");

hpet = (acpi_hpet_t *) acpi_find_table(HPET_SIGNATURE);

if (!hpet) {
printk("HPET not initialized\n");
return false;
}

hpet_base_mfn = paddr_to_mfn(hpet->address.address);
vmap((uint64_t *) hpet->address.address, hpet_base_mfn, PAGE_ORDER_4K, L1_PROT);
config = (acpi_hpet_timer_t *) (hpet->address.address +
HPET_OFFSET_TIMER_0_CONFIG_CAP_REG);
general =
(acpi_hpet_general_t *) (hpet->address.address + HPET_OFFSET_GENERAL_CAP_REG);
main_counter =
(uint64_t *) (hpet->address.address + HPET_OFFSET_GENERAL_MAIN_COUNTER_REG);

general->enabled = 0;

if (config->cfg_int_type != HPET_CONFIG_INT_TYPE_TRIGGER_MODE) {
return false;
}

if (!config->cap_int_periodic) {
return false;
}

if (general->num_timers_cap == 0) {
return false;
}

/* Disable all timers */
for (int i = 0; i < general->num_timers_cap; ++i) {
(config + i)->cfg_int_enabled = 0;
}

*main_counter = 0;

/* 1 fs = 10^15s */
uint64_t freq_hz = 1000000000000000 / general->counter_clock_period;
uint64_t ticks = freq_hz / 1000; /* Interrupt every 1ms */

config->cfg_int_enabled = 1;
config->cfg_int_route = 0;
config->cfg_fsb_enable = 0;
config->cfg_type = 1;
config->cfg_value_set = 1;
config->comparator = ticks;

general->leg_repl_cfg = 0; /* Disable legacy route */
general->enabled = 1;

configure_isa_irq(HPET_IRQ, HPET_IRQ_OFFSET, IOAPIC_DEST_MODE_PHYSICAL, dst_cpus);
dprintk("Initialized HPET\n");
return true;
}
3 changes: 2 additions & 1 deletion drivers/pit.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
#include <drivers/pic.h>
#include <drivers/pit.h>
#include <ioapic.h>
#include <time.h>
#include <lib.h>
#include <time.h>

void init_pit(uint8_t dst_cpus) {
printk("Initializing PIT\n");
outb(PIT_COMMAND_PORT,
PIT_CHANNEL_0 & PIT_ACCESS_MODE_LH & PIT_OP_MODE_RATE & PIT_BCD_MODE);
outb(PIT_DATA_PORT_CH0, PIT_FREQUENCY & 0xFF); /* send low byte */
Expand Down
107 changes: 107 additions & 0 deletions include/drivers/hpet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@

/*
* Copyright © 2020 Amazon.com, Inc. or its affiliates.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef KTF_HPET_H
#define KTF_HPET_H

#include <acpi.h>
#include <drivers/pit.h>

#define HPET_SIGNATURE (('H') | ('P' << 8) | ('E' << 16) | ('T' << 24))
#define HPET_IRQ PIT_IRQ
#define HPET_IRQ_OFFSET PIT_IRQ0_OFFSET

struct acpi_hpet {
acpi_table_hdr_t 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;
uint16_t pci_vendor_id;
acpi_gas_t address;
uint8_t hpet_number;
uint16_t minimum_tick;
uint8_t page_protection;
} __packed;
typedef struct acpi_hpet acpi_hpet_t;

struct acpi_hpet_timer {
uint64_t resv0 : 1;
uint64_t cfg_int_type : 1;
uint64_t cfg_int_enabled : 1;
uint64_t cfg_type : 1;
uint64_t cap_int_periodic : 1;
uint64_t cap_size : 1;
uint64_t cfg_value_set : 1;
uint64_t resv1 : 1;
uint64_t cfg_32bit_mode : 1;
uint64_t cfg_int_route : 5;
uint64_t cfg_fsb_enable : 1;
uint64_t cap_fsb_int_delivery : 1;
uint64_t resv2 : 8;
uint64_t cap_int_route : 32;
uint64_t comparator;
uint64_t fsb;
uint64_t resv3;
};
typedef struct acpi_hpet_timer acpi_hpet_timer_t;

struct acpi_hpet_general {
uint64_t rev_id : 8;
uint64_t num_timers_cap : 5;
uint64_t count_size_cap : 1;
uint64_t resv0 : 1;
uint64_t leg_repl_cap : 1;
uint64_t vendor_id : 16;
uint64_t counter_clock_period : 32;
uint64_t _pad;
uint64_t enabled : 1;
uint64_t leg_repl_cfg : 1;
uint64_t resv1 : 62;
uint64_t _pad2;
uint64_t timer_n_int_status : 32; /* n^th bit for the n^th timer */
uint32_t resv2;
};
typedef struct acpi_hpet_general acpi_hpet_general_t;

enum {
HPET_OFFSET_GENERAL_CAP_REG = 0x000,
HPET_OFFSET_GENERAL_CONFIG_REG = 0x010,
HPET_OFFSET_GENERAL_INT_STATUS_REG = 0x020,
HPET_OFFSET_GENERAL_MAIN_COUNTER_REG = 0x0f0,
HPET_OFFSET_TIMER_0_CONFIG_CAP_REG = 0x100,
HPET_OFFSET_TIMER_0_COMPARATOR_REG = 0x108,
HPET_OFFSET_TIMER_0_FSB_ROUTE_REG = 0x110,
};

#define HPET_CONFIG_INT_TYPE_TRIGGER_MODE 0

/* External Declarations */

extern bool init_hpet(uint8_t dst_cpus);

#endif /* KTF_HPET_H */

0 comments on commit f669534

Please sign in to comment.