Added RTC driver
This commit is contained in:
@@ -49,7 +49,8 @@ OBJS+=$(O)/sys/amd64/hw/rs232.o \
|
||||
$(O)/sys/amd64/acpi_osl_table.o \
|
||||
$(O)/sys/amd64/acpi_osl_irq.o \
|
||||
$(O)/sys/amd64/acpi_osl_hw.o \
|
||||
$(O)/sys/amd64/sys/binfmt_elf.o
|
||||
$(O)/sys/amd64/sys/binfmt_elf.o \
|
||||
$(O)/sys/amd64/hw/rtc.o
|
||||
|
||||
kernel_LINKER=sys/amd64/link.ld
|
||||
kernel_LDFLAGS=-nostdlib \
|
||||
|
||||
@@ -44,6 +44,49 @@ struct acpi_madt {
|
||||
char entry[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct acpi_fadt {
|
||||
struct acpi_header hdr;
|
||||
|
||||
uint32_t firmware_ctrl;
|
||||
uint32_t dsdt;
|
||||
|
||||
uint8_t __res0;
|
||||
|
||||
uint8_t preferred_pm_profile;
|
||||
uint16_t sci_int;
|
||||
uint32_t sci_cmd_port;
|
||||
uint8_t acpi_enable;
|
||||
uint8_t acpi_disable;
|
||||
uint8_t s4bios_req;
|
||||
uint8_t pstate_control;
|
||||
uint32_t pm1a_event_block;
|
||||
uint32_t pm1b_event_block;
|
||||
uint32_t pm1a_control_block;
|
||||
uint32_t pm1b_control_block;
|
||||
uint32_t pm2_control_block;
|
||||
uint32_t pm_timer_block;
|
||||
uint32_t gpe0_block;
|
||||
uint32_t gpe1_block;
|
||||
uint8_t pm1_event_length;
|
||||
uint8_t pm1_control_length;
|
||||
uint8_t pm2_control_length;
|
||||
uint8_t pm_timer_length;
|
||||
uint8_t gpe0_length;
|
||||
uint8_t gpe1_length;
|
||||
uint8_t gpe1_base;
|
||||
uint8_t cstate_control;
|
||||
uint16_t worst_c2_latency;
|
||||
uint16_t worst_c3_latency;
|
||||
uint16_t flush_size;
|
||||
uint16_t flush_stride;
|
||||
uint8_t duty_offset;
|
||||
uint8_t duty_width;
|
||||
uint8_t day_alarm;
|
||||
uint8_t month_alarm;
|
||||
uint8_t century;
|
||||
//...
|
||||
} __attribute__((packed));
|
||||
|
||||
extern struct acpi_madt *acpi_madt;
|
||||
|
||||
void amd64_acpi_init(void);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
void rtc_set_century(uint8_t c);
|
||||
void rtc_init(void);
|
||||
@@ -1,11 +1,13 @@
|
||||
#include "sys/amd64/hw/acpi.h"
|
||||
#include "sys/amd64/hw/apic.h"
|
||||
#include "sys/amd64/hw/rtc.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/panic.h"
|
||||
#include "acpi.h"
|
||||
|
||||
struct acpi_madt *acpi_madt = NULL;
|
||||
struct acpi_fadt *acpi_fadt = NULL;
|
||||
|
||||
static uint8_t checksum(const void *ptr, size_t size) {
|
||||
uint8_t v = 0;
|
||||
@@ -112,9 +114,21 @@ void amd64_acpi_init(void) {
|
||||
}
|
||||
|
||||
acpi_madt = (struct acpi_madt *) hdr;
|
||||
} else if (!strncmp((const char *) hdr, "FACP", 4)) {
|
||||
kdebug("Found FADT = %p\n", entry_addr);
|
||||
if (checksum(hdr, hdr->length) != 0) {
|
||||
kdebug("Entry is invalid\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
acpi_fadt = (struct acpi_fadt *) hdr;
|
||||
}
|
||||
}
|
||||
|
||||
if (acpi_fadt) {
|
||||
rtc_set_century(acpi_fadt->century);
|
||||
}
|
||||
|
||||
if (!acpi_madt) {
|
||||
panic("ACPI: No MADT present\n");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
#include "sys/amd64/hw/rtc.h"
|
||||
#include "sys/amd64/hw/irq.h"
|
||||
#include "sys/amd64/hw/io.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/string.h"
|
||||
|
||||
#define RTC_CMOS_REG_PORT 0x70
|
||||
#define RTC_CMOS_DATA_PORT 0x71
|
||||
|
||||
#define RTC_DISABLE_NMI 0x80
|
||||
#define RTC_REGA_STATUS 0x0A
|
||||
#define RTC_REGB_STATUS 0x0B
|
||||
#define RTC_REGC_STATUS 0x0C
|
||||
|
||||
#define RTC_REG_SECOND 0x00
|
||||
#define RTC_REG_MINUTE 0x02
|
||||
#define RTC_REG_HOUR 0x04
|
||||
#define RTC_REG_WEEKDAY 0x06
|
||||
#define RTC_REG_DAY 0x07
|
||||
#define RTC_REG_MONTH 0x08
|
||||
#define RTC_REG_YEAR 0x09
|
||||
|
||||
#define RTC_REGB_BCD 0x04
|
||||
#define RTC_REGB_AMPM 0x02
|
||||
|
||||
#define FROMBCD(bcd) ((((bcd) / 16) * 10) + \
|
||||
((bcd & 0xF)))
|
||||
|
||||
struct rtc_time {
|
||||
uint8_t second;
|
||||
uint8_t minute;
|
||||
uint8_t hour;
|
||||
uint8_t weekday;
|
||||
uint8_t day;
|
||||
uint8_t month;
|
||||
uint16_t year;
|
||||
};
|
||||
|
||||
// [s]Please change this in Y3K[/s]I hope x86 dies by 3000
|
||||
static uint8_t rtc_century = 20;
|
||||
|
||||
static inline void cmos_outb(uint8_t reg, uint8_t val) {
|
||||
outb(RTC_CMOS_REG_PORT, RTC_DISABLE_NMI | reg);
|
||||
for (size_t i = 0; i < 1000000; ++i);
|
||||
outb(RTC_CMOS_DATA_PORT, val);
|
||||
}
|
||||
|
||||
static inline uint8_t cmos_inb(uint8_t reg) {
|
||||
outb(RTC_CMOS_REG_PORT, RTC_DISABLE_NMI | reg);
|
||||
for (size_t i = 0; i < 1000000; ++i);
|
||||
return inb(RTC_CMOS_DATA_PORT);
|
||||
// TODO; maybe reenable NMI?
|
||||
}
|
||||
|
||||
static inline uint8_t cmos_read_time(uint8_t reg, uint8_t reg_b) {
|
||||
if (!(reg_b & RTC_REGB_BCD)) {
|
||||
return FROMBCD(cmos_inb(reg));
|
||||
} else {
|
||||
return cmos_inb(reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtc_read(struct rtc_time *time) {
|
||||
uint8_t reg_b = cmos_inb(RTC_REGB_STATUS);
|
||||
|
||||
time->second = cmos_read_time(RTC_REG_SECOND, reg_b);
|
||||
time->minute = cmos_read_time(RTC_REG_MINUTE, reg_b);
|
||||
time->hour = cmos_read_time(RTC_REG_HOUR, reg_b);
|
||||
time->weekday = cmos_read_time(RTC_REG_WEEKDAY, reg_b);
|
||||
time->day = cmos_read_time(RTC_REG_DAY, reg_b);
|
||||
time->month = cmos_read_time(RTC_REG_MONTH, reg_b);
|
||||
time->year = cmos_read_time(RTC_REG_YEAR, reg_b) + 100 * rtc_century;
|
||||
}
|
||||
|
||||
static int rtc_irq(void) {
|
||||
uint8_t reg_c = cmos_inb(RTC_REGC_STATUS);
|
||||
if (reg_c == 0) {
|
||||
return -1;
|
||||
}
|
||||
// Do something here?
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtc_enable_irq(void) {
|
||||
uint8_t prev;
|
||||
|
||||
// Gives IRQs approximately every 0.5s
|
||||
prev = cmos_inb(RTC_REGA_STATUS);
|
||||
prev &= 0xF0;
|
||||
prev |= 0xF;
|
||||
cmos_outb(RTC_REGA_STATUS, prev);
|
||||
|
||||
// Enable IRQs
|
||||
prev = cmos_inb(RTC_REGB_STATUS);
|
||||
cmos_outb(RTC_REGB_STATUS, prev | 0x40);
|
||||
}
|
||||
|
||||
void rtc_set_century(uint8_t century) {
|
||||
uint8_t reg_b = cmos_inb(RTC_REGB_STATUS);
|
||||
uint8_t century_val = cmos_read_time(century, reg_b);
|
||||
|
||||
kdebug("Setting century: %d\n", century_val * 100);
|
||||
rtc_century = century_val;
|
||||
}
|
||||
|
||||
void rtc_init(void) {
|
||||
static const char *day_names[] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
static const char *month_names[] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
|
||||
"Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
struct rtc_time time;
|
||||
|
||||
cmos_inb(RTC_REGC_STATUS);
|
||||
irq_add_leg_handler(8, rtc_irq);
|
||||
rtc_enable_irq();
|
||||
|
||||
rtc_read(&time);
|
||||
kdebug("%s %02u %s %04u %02u:%02u:%02u\n",
|
||||
day_names[(time.weekday - 1) % 7],
|
||||
time.day,
|
||||
month_names[(time.month - 1) % 12],
|
||||
time.year,
|
||||
time.hour, time.minute, time.second);
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "sys/amd64/hw/pci/pci.h"
|
||||
#include "sys/amd64/hw/rs232.h"
|
||||
#include "sys/amd64/hw/ps2.h"
|
||||
#include "sys/amd64/hw/rtc.h"
|
||||
#include "sys/panic.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/fs/vfs.h"
|
||||
@@ -39,6 +40,7 @@ void kernel_main(struct amd64_loader_data *data) {
|
||||
extern void sched_init(void);
|
||||
sched_init();
|
||||
amd64_apic_init();
|
||||
rtc_init();
|
||||
pci_init();
|
||||
|
||||
vfs_init();
|
||||
|
||||
Reference in New Issue
Block a user