Compare commits
2 commits
b164d4bdae
...
15978646bf
| Author | SHA1 | Date | |
|---|---|---|---|
| 15978646bf | |||
| 921d824570 |
1 changed files with 76 additions and 72 deletions
|
|
@ -7,6 +7,7 @@
|
|||
#include <x86_64/cmos.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "sync.h"
|
||||
#include "x86_64/apic.h"
|
||||
|
||||
#define CMOS_SEL_PORT 0x70
|
||||
|
|
@ -33,133 +34,136 @@
|
|||
#define STATB_BINARY 0x04
|
||||
#define STATB_PERIODIC_INTEN 0x40
|
||||
|
||||
/* Make sure only one CPU core interacts with the CMOS chip at once. */
|
||||
static spinlock_t cmos_lock = SPIN_INITIALIZER;
|
||||
|
||||
static uint8_t
|
||||
cmos_read(uint8_t sel)
|
||||
{
|
||||
out8(CMOS_SEL_PORT, sel);
|
||||
return in8(CMOS_DATA_PORT);
|
||||
out8(CMOS_SEL_PORT, sel);
|
||||
return in8(CMOS_DATA_PORT);
|
||||
}
|
||||
|
||||
static void
|
||||
cmos_write(uint8_t sel, uint8_t data)
|
||||
{
|
||||
out8(CMOS_SEL_PORT, sel);
|
||||
out8(CMOS_DATA_PORT, data);
|
||||
out8(CMOS_SEL_PORT, sel);
|
||||
out8(CMOS_DATA_PORT, data);
|
||||
}
|
||||
|
||||
void
|
||||
nmi_enable(void)
|
||||
{
|
||||
int cpu_state = int_disable();
|
||||
cmos_read(CMOS_REG_STATD);
|
||||
int_restore(cpu_state);
|
||||
spin_lock(&cmos_lock);
|
||||
cmos_read(CMOS_REG_STATD);
|
||||
spin_unlock(&cmos_lock);
|
||||
}
|
||||
|
||||
void
|
||||
nmi_disable(void)
|
||||
{
|
||||
int cpu_state = int_disable();
|
||||
cmos_read(CMOS_REG_STATD | CMOS_NMI_DISABLE);
|
||||
int_restore(cpu_state);
|
||||
spin_lock(&cmos_lock);
|
||||
cmos_read(CMOS_REG_STATD | CMOS_NMI_DISABLE);
|
||||
spin_unlock(&cmos_lock);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
bcd_to_binary(uint8_t bcd)
|
||||
{
|
||||
uint8_t hi = bcd & 0xf0;
|
||||
uint8_t lo = bcd & 0x0f;
|
||||
return (hi >> 1) + (hi >> 3) + lo;
|
||||
uint8_t hi = bcd & 0xf0;
|
||||
uint8_t lo = bcd & 0x0f;
|
||||
return (hi >> 1) + (hi >> 3) + lo;
|
||||
}
|
||||
|
||||
static void
|
||||
cmos_access_rtc(struct datetime *dt)
|
||||
{
|
||||
int cpu_state = int_disable();
|
||||
spin_lock(&cmos_lock);
|
||||
|
||||
while (cmos_read(CMOS_REG_STATA | CMOS_NMI_DISABLE) & STATA_UPDATING) {}
|
||||
while (cmos_read(CMOS_REG_STATA | CMOS_NMI_DISABLE) & STATA_UPDATING) {}
|
||||
|
||||
dt->seconds = cmos_read(CMOS_REG_SECONDS | CMOS_NMI_DISABLE);
|
||||
dt->minutes = cmos_read(CMOS_REG_MINUTES | CMOS_NMI_DISABLE);
|
||||
dt->hours = cmos_read(CMOS_REG_HOURS | CMOS_NMI_DISABLE);
|
||||
dt->day = cmos_read(CMOS_REG_DAY | CMOS_NMI_DISABLE);
|
||||
dt->month = cmos_read(CMOS_REG_MONTH | CMOS_NMI_DISABLE);
|
||||
dt->year = cmos_read(CMOS_REG_YEAR);
|
||||
dt->seconds = cmos_read(CMOS_REG_SECONDS | CMOS_NMI_DISABLE);
|
||||
dt->minutes = cmos_read(CMOS_REG_MINUTES | CMOS_NMI_DISABLE);
|
||||
dt->hours = cmos_read(CMOS_REG_HOURS | CMOS_NMI_DISABLE);
|
||||
dt->day = cmos_read(CMOS_REG_DAY | CMOS_NMI_DISABLE);
|
||||
dt->month = cmos_read(CMOS_REG_MONTH | CMOS_NMI_DISABLE);
|
||||
dt->year = cmos_read(CMOS_REG_YEAR);
|
||||
|
||||
int_restore(cpu_state);
|
||||
spin_unlock(&cmos_lock);
|
||||
}
|
||||
|
||||
void
|
||||
rtc_now(struct datetime *dt)
|
||||
{
|
||||
struct datetime dt1, dt2;
|
||||
do {
|
||||
cmos_access_rtc(&dt1);
|
||||
cmos_access_rtc(&dt2);
|
||||
} while (dt1.seconds != dt2.seconds ||
|
||||
dt1.minutes != dt2.minutes ||
|
||||
dt1.hours != dt2.hours ||
|
||||
dt1.day != dt2.day ||
|
||||
dt1.month != dt2.month ||
|
||||
dt1.year != dt2.year);
|
||||
struct datetime dt1, dt2;
|
||||
do {
|
||||
cmos_access_rtc(&dt1);
|
||||
cmos_access_rtc(&dt2);
|
||||
} while (dt1.seconds != dt2.seconds ||
|
||||
dt1.minutes != dt2.minutes ||
|
||||
dt1.hours != dt2.hours ||
|
||||
dt1.day != dt2.day ||
|
||||
dt1.month != dt2.month ||
|
||||
dt1.year != dt2.year);
|
||||
|
||||
int cpu_state = int_disable();
|
||||
uint8_t statb = cmos_read(CMOS_REG_STATB | CMOS_NMI_DISABLE);
|
||||
cmos_read(0);
|
||||
int_restore(cpu_state);
|
||||
spin_lock(&cmos_lock);
|
||||
uint8_t statb = cmos_read(CMOS_REG_STATB | CMOS_NMI_DISABLE);
|
||||
cmos_read(0);
|
||||
spin_unlock(&cmos_lock);
|
||||
|
||||
bool pm = false;
|
||||
if (!(statb & STATB_24HOUR)) {
|
||||
pm = dt1.hours & 0x80;
|
||||
dt1.hours &= 0x7f;
|
||||
}
|
||||
bool pm = false;
|
||||
if (!(statb & STATB_24HOUR)) {
|
||||
pm = dt1.hours & 0x80;
|
||||
dt1.hours &= 0x7f;
|
||||
}
|
||||
|
||||
if (!(statb & STATB_BINARY)) {
|
||||
dt1.seconds = bcd_to_binary(dt1.seconds);
|
||||
dt1.minutes = bcd_to_binary(dt1.minutes);
|
||||
dt1.hours = bcd_to_binary(dt1.hours);
|
||||
dt1.day = bcd_to_binary(dt1.day);
|
||||
dt1.month = bcd_to_binary(dt1.month);
|
||||
dt1.year = bcd_to_binary(dt1.year);
|
||||
}
|
||||
if (!(statb & STATB_BINARY)) {
|
||||
dt1.seconds = bcd_to_binary(dt1.seconds);
|
||||
dt1.minutes = bcd_to_binary(dt1.minutes);
|
||||
dt1.hours = bcd_to_binary(dt1.hours);
|
||||
dt1.day = bcd_to_binary(dt1.day);
|
||||
dt1.month = bcd_to_binary(dt1.month);
|
||||
dt1.year = bcd_to_binary(dt1.year);
|
||||
}
|
||||
|
||||
if (pm) {
|
||||
dt1.hours += 12;
|
||||
}
|
||||
if (pm) {
|
||||
dt1.hours += 12;
|
||||
}
|
||||
|
||||
const uint8_t century = 20;
|
||||
dt1.year += century * 100;
|
||||
const uint8_t century = 20;
|
||||
dt1.year += century * 100;
|
||||
|
||||
*dt = dt1;
|
||||
*dt = dt1;
|
||||
}
|
||||
|
||||
void
|
||||
rtc_set_rate(int rate)
|
||||
{
|
||||
ASSERT(rate == 0 || (rate >= 3 && rate <= 15));
|
||||
int cpu_state = int_disable();
|
||||
uint8_t stata = cmos_read(CMOS_REG_STATA | CMOS_NMI_DISABLE);
|
||||
stata = (stata & 0xF0) | rate;
|
||||
cmos_write(CMOS_REG_STATA, stata);
|
||||
int_restore(cpu_state);
|
||||
ASSERT(rate == 0 || (rate >= 3 && rate <= 15));
|
||||
spin_lock(&cmos_lock);
|
||||
uint8_t stata = cmos_read(CMOS_REG_STATA | CMOS_NMI_DISABLE);
|
||||
stata = (stata & 0xF0) | rate;
|
||||
cmos_write(CMOS_REG_STATA, stata);
|
||||
spin_unlock(&cmos_lock);
|
||||
}
|
||||
|
||||
void
|
||||
rtc_set_periodic(bool enable)
|
||||
{
|
||||
int cpu_state = int_disable();
|
||||
uint8_t statb = cmos_read(CMOS_REG_STATB | CMOS_NMI_DISABLE);
|
||||
statb = statb & 0x8F;
|
||||
if (enable) statb |= STATB_PERIODIC_INTEN;
|
||||
cmos_write(CMOS_REG_STATB, statb);
|
||||
int_restore(cpu_state);
|
||||
spin_lock(&cmos_lock);
|
||||
uint8_t statb = cmos_read(CMOS_REG_STATB | CMOS_NMI_DISABLE);
|
||||
statb = statb & 0x8F;
|
||||
if (enable) statb |= STATB_PERIODIC_INTEN;
|
||||
cmos_write(CMOS_REG_STATB, statb);
|
||||
spin_unlock(&cmos_lock);
|
||||
}
|
||||
|
||||
void
|
||||
rtc_eoi(void)
|
||||
{
|
||||
int cpu_state = int_disable();
|
||||
cmos_read(CMOS_REG_STATC);
|
||||
int_restore(cpu_state);
|
||||
spin_lock(&cmos_lock);
|
||||
cmos_read(CMOS_REG_STATC);
|
||||
spin_unlock(&cmos_lock);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -168,6 +172,6 @@ rtc_init(void)
|
|||
struct datetime dt;
|
||||
rtc_now(&dt);
|
||||
printlinef("IT IS NOW %u-%u-%u %u:%u:%u",
|
||||
dt.year, dt.month, dt.day,
|
||||
dt.hours, dt.minutes, dt.seconds);
|
||||
dt.year, dt.month, dt.day,
|
||||
dt.hours, dt.minutes, dt.seconds);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue