#include #include typedef unsigned int addr_t; #define ACPI_NAME_SIZE 4 #define ACPI_OEM_ID_SIZE 6 #define ACPI_OEM_TABLE_ID_SIZE 8 #define ACPI_RSDP_CHECKSUM_LENGTH 20 #define ACPI_RSDP_XCHECKSUM_LENGTH 36 typedef struct __attribute__((packed)) { u32 sig; u32 len; u8 rev; u8 csum; char oem_id[ACPI_OEM_ID_SIZE]; char oem_tid[ACPI_OEM_TABLE_ID_SIZE]; u32 oem_rev; u32 creator_id; u32 creator_rev; }acpi_thead_t; typedef struct __attribute__((packed)) { u8 space_id; /* Address space where struct or register exists */ u8 bit_width; /* Size in bits of given register */ u8 bit_offset; /* Bit offset within the register */ u8 access_width; /* Minimum Access size (ACPI 3.0) */ u64 address; /* 64-bit address of struct or register */ }acpi_address_t; typedef struct __attribute__((packed)) { acpi_thead_t header; /* Common ACPI table header */ u32 id; /* Hardware ID of event timer block */ acpi_address_t address; /* Address of event timer block */ u8 sequence; /* HPET sequence number */ u16 minimum_tick; /* Main counter min tick, periodic mode */ u8 flags; }acpi_hpet_t; typedef struct __attribute__((packed)) { acpi_thead_t header; u32 ptrs[0]; }acpi_rsdt_t; typedef struct __attribute__((packed)) { acpi_thead_t header; u64 ptrs[0]; }acpi_xsdt_t; typedef struct __attribute__((packed)) { u64 sig; u8 csum; char oemid[6]; u8 rev; u32 rsdt_ptr; u32 rsdt_len; u64 xsdt_ptr; u8 xcsum; u8 _rsvd_33[3]; }acpi_rsdp_t; #define OS_BASE 0x80000000 #define ACPI20_PC99_RSDP_START (OS_BASE + 0x0e0000) #define ACPI20_PC99_RSDP_END (OS_BASE + 0x100000) #define ACPI20_PC99_RSDP_SIZE (ACPI20_PC99_RSDP_END - ACPI20_PC99_RSDP_START) static acpi_thead_t* (*sdt_find)(void *sdt, u32 sig); static u8 acpi_tb_checksum (u8 *buffer, u32 len) { u8 sum = 0; u8 *end = buffer + len; while (buffer < end) { sum = (u8)(sum + *(buffer++)); } return sum; } static acpi_rsdp_t* acpi_locate() { addr_t p; for (p = ACPI20_PC99_RSDP_START; p < ACPI20_PC99_RSDP_END; p+=16) { acpi_rsdp_t* r = (acpi_rsdp_t*) p; if (r->sig != 0x2052545020445352 ) continue; if (acpi_tb_checksum ((u8*)r, ACPI_RSDP_CHECKSUM_LENGTH) != 0) continue; if ((r->rev >= 2) && (acpi_tb_checksum ((u8*)r, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) continue; return r; }; return NULL; }; acpi_thead_t* rsdt_find(acpi_rsdt_t *rsdt, u32 sig) { acpi_thead_t *head = NULL; u32 i; for (i = 0; i < ((rsdt->header.len-sizeof(acpi_thead_t))/ sizeof(rsdt->ptrs[0])); i++) { u32 ptr = rsdt->ptrs[i]; acpi_thead_t* t = (acpi_thead_t*)MapIoMem(ptr, 8192, PG_SW); if (t->sig == sig) { head = t; break; }; FreeKernelSpace(t); } return head; }; acpi_thead_t* xsdt_find(acpi_xsdt_t *xsdt, u32 sig) { acpi_thead_t *head = NULL; u32 i; for (i = 0; i < ((xsdt->header.len-sizeof(acpi_thead_t))/ sizeof(xsdt->ptrs[0])); i++) { u32 ptr = xsdt->ptrs[i]; acpi_thead_t* t = (acpi_thead_t*)MapIoMem(ptr, 8192, PG_SW); if (t->sig == sig) { head = t; break; }; FreeKernelSpace(t); } return head; }; static void dump_rsdt(acpi_rsdt_t *rsdt) { int i; for (i = 0; i < ((rsdt->header.len-sizeof(acpi_thead_t))/ sizeof(rsdt->ptrs[0])); i++) { u32 ptr = rsdt->ptrs[i]; dbgprintf("%s ptr= %p\n", __FUNCTION__, ptr); acpi_thead_t* t = (acpi_thead_t*)MapIoMem(ptr, 8192, PG_SW); dbgprintf("%s t= %x\n", __FUNCTION__, t); char *p = (char*)&t->sig; printf("sig %d: %x %c%c%c%c base %p\n", i, t->sig, p[0],p[1],p[2],p[3],rsdt->ptrs[i]); FreeKernelSpace(t); }; }; typedef struct { u64 hpet_cap; /* capabilities */ u64 res0; /* reserved */ u64 hpet_config; /* configuration */ u64 res1; /* reserved */ u64 hpet_isr; /* interrupt status reg */ u64 res2[25]; /* reserved */ union { /* main counter */ volatile u64 _hpet_mc64; u32 _hpet_mc32; unsigned long _hpet_mc; } _u0; u64 res3; /* reserved */ struct hpet_timer { u64 hpet_config; /* configuration/cap */ union { /* timer compare register */ u64 _hpet_hc64; u32 _hpet_hc32; unsigned long _hpet_compare; } _u1; u64 hpet_fsb[2]; /* FSB route */ } hpet_timers[1]; }hpet_t; #define HPET_ID 0x000 #define HPET_PERIOD 0x004 #define HPET_CFG 0x010 #define HPET_STATUS 0x020 #define HPET_COUNTER 0x0f0 #define HPET_ID_NUMBER 0x00001f00 #define HPET_ID_NUMBER_SHIFT 8 #define HPET_CFG_ENABLE 0x001 static void *hpet_virt_address; inline unsigned int hpet_readl(unsigned int a) { return readl(hpet_virt_address + a); } static inline void hpet_writel(unsigned int d, unsigned int a) { writel(d, hpet_virt_address + a); } static void hpet_start_counter(void) { unsigned int cfg = hpet_readl(HPET_CFG); cfg |= HPET_CFG_ENABLE; hpet_writel(cfg, HPET_CFG); } u64 read_htime() { u32 eflags; u64 val; eflags = safe_cli(); asm volatile( "1:\n" "mov 0xf4(%%ebx), %%edx\n" "mov 0xf0(%%ebx), %%eax\n" "mov 0xf4(%%ebx), %%ecx\n" "cmpl %%edx, %%ecx\n" "jnz 1b\n" :"=A"(val) :"b" (hpet_virt_address) :"ecx"); safe_sti(eflags); return val; } static u32 period; void init_hpet() { void *sdt = NULL; acpi_rsdp_t *rsdp = acpi_locate(); if (unlikely(rsdp == NULL)) { printf("No ACPI RSD table\n"); return ; }; printf("rsd base address %p\n", rsdp); if(rsdp->rev > 1) { sdt = (void*)(u32)rsdp->xsdt_ptr; sdt_find = xsdt_find; } else { sdt = (void*)rsdp->rsdt_ptr; sdt_find = rsdt_find; }; printf("sdt address %p\n", sdt); if (sdt == NULL) { printf("Invalid ACPI RSD table\n"); return ; }; sdt = MapIoMem(sdt, 128*1024, PG_SW); printf("sdt mapped address %x\n", sdt); acpi_hpet_t *tbl = (acpi_hpet_t*)sdt_find(sdt, 0x54455048); u32 hpet_address = tbl->address.address; hpet_virt_address = (void*)MapIoMem(hpet_address,1024, PG_SW|0x18); printf("hpet address %x mapped at %x\n", hpet_address, hpet_virt_address); u32 timers, l, h; l = hpet_readl(HPET_ID); h = hpet_readl(HPET_PERIOD); period = h / 1000000; timers = ((l & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; printk(KERN_INFO "hpet: ID: 0x%x, PERIOD: 0x%x\n", l, h); l = hpet_readl(HPET_CFG); h = hpet_readl(HPET_STATUS); printk(KERN_INFO "hpet: CFG: 0x%x, STATUS: 0x%x\n", l, h); l = hpet_readl(HPET_COUNTER); h = hpet_readl(HPET_COUNTER+4); printk(KERN_INFO "hpet: COUNTER_l: 0x%x, COUNTER_h: 0x%x\n", l, h); hpet_start_counter(); }