🆕 HPET驱动

This commit is contained in:
fslongjin 2022-04-08 12:20:53 +08:00
parent 8bf4da2afa
commit d887f9a0f7
12 changed files with 259 additions and 36 deletions

View File

@ -133,3 +133,5 @@ fslongjin
- the GNU GRUB manual
- Intel® 64 and IA-32 Architectures Software Developers Manual
- IA-PC HPET (High Precision Event Timers) Specification

View File

@ -130,3 +130,5 @@ This project refers to the following materials. I sincerely give my thanks to th
- the GNU GRUB manual
- Intel® 64 and IA-32 Architectures Software Developers Manual
- IA-PC HPET (High Precision Event Timers) Specification

View File

@ -112,16 +112,19 @@ ahci.o: driver/disk/ahci/ahci.c
rtc.o: driver/timers/rtc/rtc.c
gcc $(CFLAGS) -c driver/timers/rtc/rtc.c -o driver/timers/rtc/rtc.o
HPET.o: driver/timers/HPET/HPET.c
gcc $(CFLAGS) -c driver/timers/HPET/HPET.c -o driver/timers/HPET/HPET.o
all: kernel
objcopy -I elf64-x86-64 -O elf64-x86-64 -R ".comment" -R ".eh_frame" kernel ../bin/kernel/kernel.elf
#
kernel: head.o entry.o main.o printk.o trap.o mm.o slab.o irq.o pic.o process.o syscall.o multiboot2.o cpu.o acpi.o ps2_keyboard.o ps2_mouse.o ata.o pci.o ahci.o smp.o apu_boot.o rtc.o $(OBJ_LIST)
kernel: head.o entry.o main.o printk.o trap.o mm.o slab.o irq.o pic.o process.o syscall.o multiboot2.o cpu.o acpi.o ps2_keyboard.o ps2_mouse.o ata.o pci.o ahci.o smp.o apu_boot.o rtc.o HPET.o $(OBJ_LIST)
ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o mm/mm.o mm/slab.o process/process.o syscall/syscall.o driver/multiboot2/multiboot2.o \
common/cpu.o smp/smp.o smp/apu_boot.o \
driver/acpi/acpi.o driver/interrupt/pic.o driver/keyboard/ps2_keyboard.o driver/mouse/ps2_mouse.o driver/disk/ata.o driver/pci/pci.o driver/disk/ahci/ahci.o driver/timers/rtc/rtc.o \
driver/acpi/acpi.o driver/interrupt/pic.o driver/keyboard/ps2_keyboard.o driver/mouse/ps2_mouse.o driver/disk/ata.o driver/pci/pci.o driver/disk/ahci/ahci.o driver/timers/rtc/rtc.o driver/timers/HPET/HPET.o \
$(LD_LIST) \
-T link.lds

View File

@ -84,6 +84,22 @@ bool acpi_get_MADT(const struct acpi_system_description_table_header_t *_iter_da
return true;
}
/**
* @brief HPET HPET_description_table
*
* @param _iter_data
* @param _data HPET表的虚拟地址
* @return true
* @return false
*/
bool acpi_get_HPET(const struct acpi_system_description_table_header_t *_iter_data, void *_data)
{
if (!(_iter_data->Signature[0] == 'H' && _iter_data->Signature[1] == 'P' && _iter_data->Signature[2] == 'E' && _iter_data->Signature[3] == 'T'))
return false;
*(ul *)_data = (ul)_iter_data;
return true;
}
/**
* @brief acpi模块

View File

@ -42,7 +42,7 @@ struct acpi_RSDP_t
// 32bit physical address of the RSDT
uint RsdtAddress;
};
} __attribute__((packed));
struct acpi_RSDP_2_t
{
@ -56,7 +56,7 @@ struct acpi_RSDP_2_t
unsigned char ExtendedChecksum; // 整个表的checksum包括了之前的checksum区域
unsigned char Reserved[3];
};
} __attribute__((packed));
struct acpi_system_description_table_header_t
{
@ -74,7 +74,32 @@ struct acpi_system_description_table_header_t
uint OEMRevision;
uint CreatorID;
uint CreatorRevision;
};
} __attribute__((packed));
// HPET描述符结构体sign为HPET
struct acpi_HPET_description_table_t
{
struct acpi_system_description_table_header_t header;
uint8_t hardware_rev_id;
uint8_t comparator_count : 5; // Number of Comparators in 1st Timer Block
uint8_t counter_size : 1; // COUNT_SIZE_CAP counter size
uint8_t reserved0 : 1;
uint8_t legacy_replacement : 1; // LegacyReplacement IRQ Routing Capable
uint16_t pci_vendor_id; // PCI Vendor ID of 1st Timer Block
uint8_t address_space_id; // 0 - system memory, 1 - system I/O
uint8_t register_bit_width;
uint8_t register_bit_offset;
uint8_t reserved1;
uint64_t address;
uint8_t hpet_number;
uint16_t minimum_tick; // The minimum clock ticks can be set without lost interrupts while the counter is programmed to operate in periodic mode
uint8_t page_protection;
} __attribute__((packed));
// =========== MADT结构其中Signature为APIC ============
struct acpi_Multiple_APIC_Description_Table_t
@ -161,7 +186,15 @@ void acpi_iter_SDT(bool (*_fun)(const struct acpi_system_description_table_heade
*/
bool acpi_get_MADT(const struct acpi_system_description_table_header_t *_iter_data, void *_data);
/**
* @brief HPET HPET_description_table
*
* @param _iter_data
* @param _data HPET表的虚拟地址
* @return true
* @return false
*/
bool acpi_get_HPET(const struct acpi_system_description_table_header_t *_iter_data, void *_data);
// 初始化acpi模块
void acpi_init();

View File

@ -27,9 +27,9 @@ void apic_io_apic_init()
acpi_iter_SDT(acpi_get_MADT, &madt_addr);
madt = (struct acpi_Multiple_APIC_Description_Table_t *)madt_addr;
//kdebug("MADT->local intr controller addr=%#018lx", madt->Local_Interrupt_Controller_Address);
//kdebug("MADT->length= %d bytes", madt->header.Length);
// 寻找io apic的ICS
// kdebug("MADT->local intr controller addr=%#018lx", madt->Local_Interrupt_Controller_Address);
// kdebug("MADT->length= %d bytes", madt->header.Length);
// 寻找io apic的ICS
void *ent = (void *)(madt_addr) + sizeof(struct acpi_Multiple_APIC_Description_Table_t);
struct apic_Interrupt_Controller_Structure_header_t *header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
while (header->length > 2)
@ -181,7 +181,7 @@ void apic_init_ap_core_local_apic()
kdebug("cmci = %#018lx", *(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI));
*/
//*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER) = 0x10000;
//io_mfence();
// io_mfence();
/*
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL) = 0x1000000;
io_mfence();
@ -628,4 +628,46 @@ uint apic_get_ics(const uint type, ul ret_vaddr[], uint *total)
return APIC_E_NOTFOUND;
else
return APIC_SUCCESS;
}
/**
* @brief RTE Entry结构体
*
* @param entry
* @param vector
* @param deliver_mode
* @param dest_mode
* @param deliver_status
* @param polarity
* @param irr IRR标志位
* @param trigger
* @param mask 0 1
* @param dest_apicID apicID
*/
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask, uint8_t dest_apicID)
{
entry->vector = vector;
entry->deliver_mode = deliver_mode;
entry->dest_mode = dest_mode;
entry->deliver_status = deliver_status;
entry->polarity = polarity;
entry->remote_IRR = irr;
entry->trigger_mode = trigger;
entry->mask = mask;
entry->reserved = 0;
if (dest_mode == DEST_PHYSICAL)
{
entry->destination.physical.phy_dest = dest_apicID;
entry->destination.physical.reserved1 = 0;
entry->destination.physical.reserved2 = 0;
}
else
{
entry->destination.logical.logical_dest = dest_apicID;
entry->destination.logical.reserved1 = 0;
}
}

View File

@ -73,8 +73,6 @@
// 分频配置寄存器(定时器专用)
#define LOCAL_APIC_OFFSET_Local_APIC_CLKDIV 0x3e0
/*
1: LVT CMCI
@ -269,10 +267,9 @@ ul apic_ioapic_read_rte(unsigned char index);
*/
void apic_ioapic_write_rte(unsigned char index, ul value);
/**
* @brief AP处理器的Local apic
*
*
*/
void apic_init_ap_core_local_apic();
@ -284,13 +281,13 @@ void apic_init();
/**
* @brief Interrupt Control Structure
*
*
* @param type ics的类型
* @param ret_vaddr ICS的虚拟地址数组
* @param total
* @return uint
* @return uint
*/
uint apic_get_ics(const uint type, ul ret_vaddr[], uint * total);
uint apic_get_ics(const uint type, ul ret_vaddr[], uint *total);
// =========== 中断控制操作接口 ============
void apic_ioapic_enable(ul irq_num);
@ -301,4 +298,21 @@ void apic_ioapic_level_ack(ul irq_num); // ioapic电平触发 应答
void apic_ioapic_edge_ack(ul irq_num); // ioapic边沿触发 应答
// void apic_local_apic_level_ack(ul irq_num);// local apic电平触发 应答
void apic_local_apic_edge_ack(ul irq_num);// local apic边沿触发 应答
void apic_local_apic_edge_ack(ul irq_num); // local apic边沿触发 应答
/**
* @brief RTE Entry结构体
*
* @param entry
* @param vector
* @param deliver_mode
* @param dest_mode
* @param deliver_status
* @param polarity
* @param irr IRR标志位
* @param trigger
* @param mask 0 1
* @param dest_apicID apicID
*/
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask, uint8_t dest_apicID);

View File

@ -0,0 +1,102 @@
#include "HPET.h"
#include <common/kprint.h>
#include <mm/mm.h>
#include <driver/interrupt/apic/apic.h>
static struct acpi_HPET_description_table_t *hpet_table;
static uint64_t HPET_REG_BASE = 0;
static uint32_t HPET_COUNTER_CLK_PERIOD = 0; // 主计数器时间精度(单位:飞秒)
static double HPET_freq = 0; // 主计时器频率
static uint8_t HPET_NUM_TIM_CAP = 0; // 定时器数量
extern struct rtc_time_t rtc_now; // 导出全局墙上时钟
enum
{
GCAP_ID = 0x00,
GEN_CONF = 0x10,
GINTR_STA = 0x20,
MAIN_CNT = 0xf0,
TIM0_CONF = 0x100,
TIM0_COMP = 0x108,
TIM1_CONF = 0x120,
TIM1_COMP = 0x128,
TIM2_CONF = 0x140,
TIM2_COMP = 0x148,
TIM3_CONF = 0x160,
TIM3_COMP = 0x168,
TIM4_CONF = 0x180,
TIM4_COMP = 0x188,
TIM5_CONF = 0x1a0,
TIM5_COMP = 0x1a8,
TIM6_CONF = 0x1c0,
TIM6_COMP = 0x1c8,
TIM7_CONF = 0x1e0,
TIM7_COMP = 0x1e8,
};
hardware_intr_controller HPET_intr_controller =
{
.enable = apic_ioapic_enable,
.disable = apic_ioapic_disable,
.install = apic_ioapic_install,
.uninstall = apic_ioapic_uninstall,
.ack = apic_ioapic_edge_ack,
};
void HPET_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
{
//printk_color(ORANGE, BLACK, "(HPET)");
switch (param)
{
case 0:
rtc_get_cmos_time(&rtc_now);
break;
default:
break;
}
}
int HPET_init()
{
// 从acpi获取hpet结构体
ul hpet_table_addr = 0;
acpi_iter_SDT(acpi_get_HPET, &hpet_table_addr);
if (hpet_table_addr == 0)
{
kerror("HPET Not Found On This Computer!");
return E_HPET_INIT_FAILED;
}
hpet_table = (struct acpi_HPET_description_table_t *)hpet_table_addr;
// 由于这段内存与io/apic的映射在同一物理页内因此不需要重复映射
HPET_REG_BASE = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + hpet_table->address;
// 读取计时精度并计算频率
uint64_t tmp;
tmp = *(uint64_t *)(HPET_REG_BASE + GCAP_ID);
HPET_COUNTER_CLK_PERIOD = (tmp >> 32) & 0xffffffff;
HPET_freq = 1.0 * 1e15 / HPET_COUNTER_CLK_PERIOD;
HPET_NUM_TIM_CAP = (tmp >> 8) & 0x1f; // 读取计时器数量
kinfo("HPET CLK_PERIOD=%#03lx Frequency=%f", HPET_COUNTER_CLK_PERIOD, HPET_freq);
struct apic_IO_APIC_RTE_entry entry;
// 使用I/O APIC 的IRQ2接收hpet定时器0的中断
apic_make_rte_entry(&entry, 34, IO_APIC_FIXED, DEST_PHYSICAL, IDLE, POLARITY_HIGH, IRR_RESET, EDGE_TRIGGER, MASKED, 0);
// 注册中断
irq_register(34, &entry, &HPET_handler, 0, &HPET_intr_controller, "HPET0");
*(uint64_t *)(HPET_REG_BASE + GEN_CONF) = 3; // 置位旧设备中断路由兼容标志位、定时器组使能标志位
io_mfence();
*(uint64_t *)(HPET_REG_BASE + TIM0_CONF) = 0x004c; // 设置定时器0为周期定时边沿触发投递到IO APIC的2号引脚这里有点绕写的是8259的引脚号但是因为禁用了8259因此会被路由到IO APIC的2号引脚
io_mfence();
*(uint64_t *)(HPET_REG_BASE + TIM0_COMP) = HPET_freq; // 1s触发一次中断
io_mfence();
rtc_get_cmos_time(&rtc_now);
*(uint64_t *)(HPET_REG_BASE + MAIN_CNT) = 0;
io_mfence();
}

View File

@ -0,0 +1,8 @@
#pragma once
#include <common/glib.h>
#include <driver/acpi/acpi.h>
#include<driver/timers/rtc/rtc.h>
#define E_HPET_INIT_FAILED 1
int HPET_init();

View File

@ -2,12 +2,12 @@
#include <common/kprint.h>
/*置位0x70的第7位禁止不可屏蔽中断*/
/*
#define read_cmos(addr) ({ \
io_out8(0x70, 0x80 | addr); \
io_in8(0x71); \
})
*/
enum CMOSTimeSelector
{
T_SECOND = 0x0,
@ -18,14 +18,8 @@ enum CMOSTimeSelector
T_YEAR = 0x9,
};
int read_cmos(uint8_t addr)
{
io_out8(0x70, 0x80 | addr);
io_mfence();
return (uint8_t)(io_in8(0x71) & 0xff);
}
int rtc_get_cmos_time(struct time *t)
int rtc_get_cmos_time(struct rtc_time_t *t)
{
// 为防止中断请求打断该过程,需要先关中断
cli();

View File

@ -1,6 +1,6 @@
#pragma once
#include <common/glib.h>
struct time
struct rtc_time_t
{
int second;
int minute;
@ -8,7 +8,7 @@ struct time
int day;
int month;
int year;
};
}rtc_now; // rtc_now为墙上时钟由HPET定时器0维护
/**
* @brief cmos中获取时间
@ -16,5 +16,4 @@ struct time
* @param t time结构体
* @return int 0
*/
int rtc_get_cmos_time(struct time*t);
int get_cmos_time(struct time *time);
int rtc_get_cmos_time(struct rtc_time_t*t);

View File

@ -23,6 +23,7 @@
#include "driver/pci/pci.h"
#include "driver/disk/ahci/ahci.h"
#include <driver/timers/rtc/rtc.h>
#include <driver/timers/HPET/HPET.h>
unsigned int *FR_address = (unsigned int *)0xb8000; //帧缓存区的地址
@ -166,8 +167,9 @@ void system_initialize()
acpi_init();
// 初始化中断模块
irq_init();
HPET_init();
smp_init();
// 先初始化系统调用模块
@ -229,10 +231,16 @@ void Start_Kernel(void)
*/
// ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0xc8, ICR_APIC_FIXED, ICR_No_Shorthand, true, 1); // 测试ipi
struct time tt;
rtc_get_cmos_time(&tt);
kinfo("Current Time: %04d/%02d/%02d %02d:%02d:%02d", tt.year, tt.month, tt.day, tt.hour, tt.minute, tt.second);
int last_sec = rtc_now.second;
while (1)
{
if (last_sec != rtc_now.second)
{
last_sec = rtc_now.second;
kinfo("Current Time: %04d/%02d/%02d %02d:%02d:%02d", rtc_now.year, rtc_now.month, rtc_now.day, rtc_now.hour, rtc_now.minute, rtc_now.second);
}
}
while (1)
hlt();
}