mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-10 16:26:48 +00:00
🆕 HPET驱动
This commit is contained in:
parent
8bf4da2afa
commit
d887f9a0f7
@ -133,3 +133,5 @@ fslongjin
|
||||
- the GNU GRUB manual
|
||||
|
||||
- Intel® 64 and IA-32 Architectures Software Developer’s Manual
|
||||
|
||||
- IA-PC HPET (High Precision Event Timers) Specification
|
||||
|
@ -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 Developer’s Manual
|
||||
|
||||
- IA-PC HPET (High Precision Event Timers) Specification
|
||||
|
@ -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
|
||||
|
||||
|
@ -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模块
|
||||
|
@ -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();
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
102
kernel/driver/timers/HPET/HPET.c
Normal file
102
kernel/driver/timers/HPET/HPET.c
Normal 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();
|
||||
|
||||
|
||||
}
|
8
kernel/driver/timers/HPET/HPET.h
Normal file
8
kernel/driver/timers/HPET/HPET.h
Normal 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();
|
@ -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();
|
||||
|
@ -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);
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user