Implement RTC support
This commit is contained in:
@@ -54,10 +54,6 @@
|
|||||||
/* Maximum number of I/O APICs */
|
/* Maximum number of I/O APICs */
|
||||||
#define APIC_MAX_IOAPICS 64
|
#define APIC_MAX_IOAPICS 64
|
||||||
|
|
||||||
/* CMOS controller I/O ports */
|
|
||||||
#define CMOS_ADDRESS_PORT 0x70
|
|
||||||
#define CMOS_DATA_PORT 0x71
|
|
||||||
|
|
||||||
/* I/O APIC base address */
|
/* I/O APIC base address */
|
||||||
#define IOAPIC_DEFAULT_BASE 0xFEC00000
|
#define IOAPIC_DEFAULT_BASE 0xFEC00000
|
||||||
|
|
||||||
@@ -94,6 +90,40 @@
|
|||||||
#define PIT_DATA_PORT1 0x41
|
#define PIT_DATA_PORT1 0x41
|
||||||
#define PIT_DATA_PORT2 0x42
|
#define PIT_DATA_PORT2 0x42
|
||||||
|
|
||||||
|
/* CMOS controller access ports */
|
||||||
|
#define CMOS_SELECT_PORT 0x70
|
||||||
|
#define CMOS_DATA_PORT 0x71
|
||||||
|
|
||||||
|
/* CMOD Select port definitions */
|
||||||
|
#define CMOS_NMI_SELECT 0x80
|
||||||
|
#define CMOS_REGISTER_SECOND 0x00
|
||||||
|
#define CMOS_REGISTER_MINUTE 0x02
|
||||||
|
#define CMOS_REGISTER_HOUR 0x04
|
||||||
|
#define CMOS_REGISTER_WEEKDAY 0x06
|
||||||
|
#define CMOS_REGISTER_DAY 0x07
|
||||||
|
#define CMOS_REGISTER_MONTH 0x08
|
||||||
|
#define CMOS_REGISTER_YEAR 0x09
|
||||||
|
#define CMOS_REGISTER_A 0x0A
|
||||||
|
#define CMOS_REGISTER_B 0x0B
|
||||||
|
#define CMOS_REGISTER_C 0x0C
|
||||||
|
|
||||||
|
/* CMOS Register A definitions */
|
||||||
|
#define CMOS_REGISTER_A_RATE_MASK 0x0F
|
||||||
|
#define CMOS_REGISTER_A_UPDATE_IN_PROGRESS 0x80
|
||||||
|
|
||||||
|
/* CMOS Register B definitions */
|
||||||
|
#define CMOS_REGISTER_B_24_HOUR 0x02
|
||||||
|
#define CMOS_REGISTER_B_BINARY 0x04
|
||||||
|
#define CMOS_REGISTER_B_PERIODIC 0x40
|
||||||
|
#define CMOS_REGISTER_B_SET_CLOCK 0x80
|
||||||
|
|
||||||
|
/* CMOS Register C definitions */
|
||||||
|
#define CMOS_REGISTER_C_PERIODIC 0x40
|
||||||
|
#define CMOS_REGISTER_C_INTERRUPT 0x80
|
||||||
|
|
||||||
|
/* CMOS RTC 24-hour mode */
|
||||||
|
#define CMOS_RTC_POST_MERIDIEM 0x80
|
||||||
|
|
||||||
/* Serial ports information */
|
/* Serial ports information */
|
||||||
#define COMPORT_ADDRESS {0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8}
|
#define COMPORT_ADDRESS {0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8}
|
||||||
#define COMPORT_COUNT 8
|
#define COMPORT_COUNT 8
|
||||||
|
|||||||
@@ -60,10 +60,6 @@
|
|||||||
/* Maximum number of I/O APICs */
|
/* Maximum number of I/O APICs */
|
||||||
#define APIC_MAX_IOAPICS 64
|
#define APIC_MAX_IOAPICS 64
|
||||||
|
|
||||||
/* CMOS controller I/O ports */
|
|
||||||
#define CMOS_ADDRESS_PORT 0x70
|
|
||||||
#define CMOS_DATA_PORT 0x71
|
|
||||||
|
|
||||||
/* I/O APIC base address */
|
/* I/O APIC base address */
|
||||||
#define IOAPIC_DEFAULT_BASE 0xFEC00000
|
#define IOAPIC_DEFAULT_BASE 0xFEC00000
|
||||||
|
|
||||||
@@ -99,6 +95,42 @@
|
|||||||
/* PIT ports definitions */
|
/* PIT ports definitions */
|
||||||
#define PIT_COMMAND_PORT 0x43
|
#define PIT_COMMAND_PORT 0x43
|
||||||
#define PIT_DATA_PORT0 0x40
|
#define PIT_DATA_PORT0 0x40
|
||||||
|
#define PIT_DATA_PORT1 0x41
|
||||||
|
#define PIT_DATA_PORT2 0x42
|
||||||
|
|
||||||
|
/* CMOS controller access ports */
|
||||||
|
#define CMOS_SELECT_PORT 0x70
|
||||||
|
#define CMOS_DATA_PORT 0x71
|
||||||
|
|
||||||
|
/* CMOD Select port definitions */
|
||||||
|
#define CMOS_NMI_SELECT 0x80
|
||||||
|
#define CMOS_REGISTER_SECOND 0x00
|
||||||
|
#define CMOS_REGISTER_MINUTE 0x02
|
||||||
|
#define CMOS_REGISTER_HOUR 0x04
|
||||||
|
#define CMOS_REGISTER_WEEKDAY 0x06
|
||||||
|
#define CMOS_REGISTER_DAY 0x07
|
||||||
|
#define CMOS_REGISTER_MONTH 0x08
|
||||||
|
#define CMOS_REGISTER_YEAR 0x09
|
||||||
|
#define CMOS_REGISTER_A 0x0A
|
||||||
|
#define CMOS_REGISTER_B 0x0B
|
||||||
|
#define CMOS_REGISTER_C 0x0C
|
||||||
|
|
||||||
|
/* CMOS Register A definitions */
|
||||||
|
#define CMOS_REGISTER_A_RATE_MASK 0x0F
|
||||||
|
#define CMOS_REGISTER_A_UPDATE_IN_PROGRESS 0x80
|
||||||
|
|
||||||
|
/* CMOS Register B definitions */
|
||||||
|
#define CMOS_REGISTER_B_24_HOUR 0x02
|
||||||
|
#define CMOS_REGISTER_B_BINARY 0x04
|
||||||
|
#define CMOS_REGISTER_B_PERIODIC 0x40
|
||||||
|
#define CMOS_REGISTER_B_SET_CLOCK 0x80
|
||||||
|
|
||||||
|
/* CMOS Register C definitions */
|
||||||
|
#define CMOS_REGISTER_C_PERIODIC 0x40
|
||||||
|
#define CMOS_REGISTER_C_INTERRUPT 0x80
|
||||||
|
|
||||||
|
/* CMOS RTC 24-hour mode */
|
||||||
|
#define CMOS_RTC_POST_MERIDIEM 0x80
|
||||||
|
|
||||||
/* Serial ports information */
|
/* Serial ports information */
|
||||||
#define COMPORT_ADDRESS {0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8}
|
#define COMPORT_ADDRESS {0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8}
|
||||||
|
|||||||
@@ -111,5 +111,18 @@ typedef struct _RTL_SHA1_CONTEXT
|
|||||||
UCHAR Buffer[SHA1_BLOCK_SIZE];
|
UCHAR Buffer[SHA1_BLOCK_SIZE];
|
||||||
} RTL_SHA1_CONTEXT, *PRTL_SHA1_CONTEXT;
|
} RTL_SHA1_CONTEXT, *PRTL_SHA1_CONTEXT;
|
||||||
|
|
||||||
|
/* Runtime time fields structure definition */
|
||||||
|
typedef struct _TIME_FIELDS
|
||||||
|
{
|
||||||
|
SHORT Year;
|
||||||
|
SHORT Month;
|
||||||
|
SHORT Day;
|
||||||
|
SHORT Hour;
|
||||||
|
SHORT Minute;
|
||||||
|
SHORT Second;
|
||||||
|
SHORT Milliseconds;
|
||||||
|
SHORT Weekday;
|
||||||
|
} TIME_FIELDS, *PTIME_FIELDS;
|
||||||
|
|
||||||
#endif /* __XTOS_ASSEMBLER__ */
|
#endif /* __XTOS_ASSEMBLER__ */
|
||||||
#endif /* __XTDK_RTLTYPES_H */
|
#endif /* __XTDK_RTLTYPES_H */
|
||||||
|
|||||||
@@ -335,6 +335,7 @@ typedef struct _STRING STRING, *PSTRING;
|
|||||||
typedef struct _STRING32 STRING32, *PSTRING32;
|
typedef struct _STRING32 STRING32, *PSTRING32;
|
||||||
typedef struct _STRING64 STRING64, *PSTRING64;
|
typedef struct _STRING64 STRING64, *PSTRING64;
|
||||||
typedef struct _THREAD_INFORMATION_BLOCK THREAD_INFORMATION_BLOCK, *PTHREAD_INFORMATION_BLOCK;
|
typedef struct _THREAD_INFORMATION_BLOCK THREAD_INFORMATION_BLOCK, *PTHREAD_INFORMATION_BLOCK;
|
||||||
|
typedef struct _TIME_FIELDS TIME_FIELDS, *PTIME_FIELDS;
|
||||||
typedef struct _UEFI_FIRMWARE_INFORMATION UEFI_FIRMWARE_INFORMATION, *PUEFI_FIRMWARE_INFORMATION;
|
typedef struct _UEFI_FIRMWARE_INFORMATION UEFI_FIRMWARE_INFORMATION, *PUEFI_FIRMWARE_INFORMATION;
|
||||||
typedef struct _UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;
|
typedef struct _UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;
|
||||||
typedef struct _UNICODE_STRING32 UNICODE_STRING32, *PUNICODE_STRING32;
|
typedef struct _UNICODE_STRING32 UNICODE_STRING32, *PUNICODE_STRING32;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ list(APPEND XTOSKRNL_SOURCE
|
|||||||
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/ioport.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/ioport.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/irq.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/irq.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/pic.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/pic.cc
|
||||||
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/rtc.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/runlevel.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/runlevel.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/timer.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/timer.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/acpi.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/acpi.cc
|
||||||
|
|||||||
13
xtoskrnl/hl/amd64/rtc.cc
Normal file
13
xtoskrnl/hl/amd64/rtc.cc
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* PROJECT: ExectOS
|
||||||
|
* COPYRIGHT: See COPYING.md in the top level directory
|
||||||
|
* FILE: xtoskrnl/hl/amd64/rtc.cc
|
||||||
|
* DESCRIPTION: Hardware Real-Time Clock (RTC) support
|
||||||
|
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/* Include common RTC interface */
|
||||||
|
#include ARCH_COMMON(rtc.cc)
|
||||||
13
xtoskrnl/hl/i686/rtc.cc
Normal file
13
xtoskrnl/hl/i686/rtc.cc
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* PROJECT: ExectOS
|
||||||
|
* COPYRIGHT: See COPYING.md in the top level directory
|
||||||
|
* FILE: xtoskrnl/hl/i686/rtc.cc
|
||||||
|
* DESCRIPTION: Hardware Real-Time Clock (RTC) support
|
||||||
|
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/* Include common RTC interface */
|
||||||
|
#include ARCH_COMMON(rtc.cc)
|
||||||
328
xtoskrnl/hl/x86/rtc.cc
Normal file
328
xtoskrnl/hl/x86/rtc.cc
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
/**
|
||||||
|
* PROJECT: ExectOS
|
||||||
|
* COPYRIGHT: See COPYING.md in the top level directory
|
||||||
|
* FILE: xtoskrnl/hl/x86/rtc.cc
|
||||||
|
* DESCRIPTION: Hardware Real-Time Clock (RTC) support
|
||||||
|
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries the hardware Real-Time Clock (RTC) for the current date and time.
|
||||||
|
*
|
||||||
|
* @param Time
|
||||||
|
* Supplies a pointer to a structure to receive the system time.
|
||||||
|
*
|
||||||
|
* @return This routine returns the status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
HL::Rtc::GetRealTimeClock(OUT PTIME_FIELDS Time)
|
||||||
|
{
|
||||||
|
UCHAR Century1, Century2, CenturyRegister, RegisterB;
|
||||||
|
TIME_FIELDS TimeProbe1, TimeProbe2;
|
||||||
|
PACPI_FADT FadtTable;
|
||||||
|
BOOLEAN PostMeridiem;
|
||||||
|
XTSTATUS Status;
|
||||||
|
ULONG Index;
|
||||||
|
|
||||||
|
/* Locate the ACPI FADT table */
|
||||||
|
Status = HL::Acpi::GetAcpiTable(ACPI_FADT_SIGNATURE, (PACPI_DESCRIPTION_HEADER*)&FadtTable);
|
||||||
|
if(Status == STATUS_SUCCESS && FadtTable && FadtTable->CenturyAlarmIndex)
|
||||||
|
{
|
||||||
|
/* Cache the dynamically provided Century register index */
|
||||||
|
CenturyRegister = FadtTable->CenturyAlarmIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Century register is unavailable */
|
||||||
|
CenturyRegister = 0;
|
||||||
|
Century1 = 0;
|
||||||
|
Century2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the RTC Status Register B to determine hardware data formats */
|
||||||
|
RegisterB = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_B);
|
||||||
|
|
||||||
|
/* Assume failure */
|
||||||
|
Status = STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
|
/* Execute a maximum of 100 retries to obtain a stable RTC snapshot */
|
||||||
|
for(Index = 0; Index < 100; Index++)
|
||||||
|
{
|
||||||
|
/* Wait until the RTC hardware finishes any ongoing background updates */
|
||||||
|
while(HL::Firmware::ReadCmosRegister(CMOS_REGISTER_A) & CMOS_REGISTER_A_UPDATE_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
/* Yield the processor */
|
||||||
|
AR::CpuFunc::YieldProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Latch the first sequential hardware time snapshot */
|
||||||
|
TimeProbe1.Hour = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_HOUR);
|
||||||
|
TimeProbe1.Minute = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_MINUTE);
|
||||||
|
TimeProbe1.Second = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_SECOND);
|
||||||
|
TimeProbe1.Day = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_DAY);
|
||||||
|
TimeProbe1.Month = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_MONTH);
|
||||||
|
TimeProbe1.Year = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_YEAR);
|
||||||
|
TimeProbe1.Weekday = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_WEEKDAY);
|
||||||
|
|
||||||
|
/* Check if Century register is available */
|
||||||
|
if(CenturyRegister)
|
||||||
|
{
|
||||||
|
/* Read the corresponding Century register */
|
||||||
|
Century1 = HL::Firmware::ReadCmosRegister(CenturyRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until the RTC hardware finishes any ongoing background updates */
|
||||||
|
while(HL::Firmware::ReadCmosRegister(CMOS_REGISTER_A) & CMOS_REGISTER_A_UPDATE_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
/* Yield the processor */
|
||||||
|
AR::CpuFunc::YieldProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Latch the second sequential hardware time snapshot for verification */
|
||||||
|
TimeProbe2.Hour = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_HOUR);
|
||||||
|
TimeProbe2.Minute = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_MINUTE);
|
||||||
|
TimeProbe2.Second = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_SECOND);
|
||||||
|
TimeProbe2.Day = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_DAY);
|
||||||
|
TimeProbe2.Month = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_MONTH);
|
||||||
|
TimeProbe2.Year = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_YEAR);
|
||||||
|
TimeProbe2.Weekday = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_WEEKDAY);
|
||||||
|
|
||||||
|
/* Check if Century register is available */
|
||||||
|
if(CenturyRegister)
|
||||||
|
{
|
||||||
|
/* Read the corresponding Century register */
|
||||||
|
Century2 = HL::Firmware::ReadCmosRegister(CenturyRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare both snapshots to guarantee data consistency */
|
||||||
|
if((TimeProbe1.Hour == TimeProbe2.Hour) &&
|
||||||
|
(TimeProbe1.Minute == TimeProbe2.Minute) &&
|
||||||
|
(TimeProbe1.Second == TimeProbe2.Second) &&
|
||||||
|
(TimeProbe1.Day == TimeProbe2.Day) &&
|
||||||
|
(TimeProbe1.Month == TimeProbe2.Month) &&
|
||||||
|
(TimeProbe1.Year == TimeProbe2.Year) &&
|
||||||
|
(TimeProbe1.Weekday == TimeProbe2.Weekday) &&
|
||||||
|
(Century1 == Century2))
|
||||||
|
{
|
||||||
|
/* A stable time sample was acquired, break the loop */
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the validated data into the output buffer */
|
||||||
|
Time->Hour = TimeProbe1.Hour;
|
||||||
|
Time->Minute = TimeProbe1.Minute;
|
||||||
|
Time->Second = TimeProbe1.Second;
|
||||||
|
Time->Milliseconds = 0;
|
||||||
|
Time->Day = TimeProbe1.Day;
|
||||||
|
Time->Month = TimeProbe1.Month;
|
||||||
|
Time->Year = TimeProbe1.Year;
|
||||||
|
Time->Weekday = TimeProbe1.Weekday;
|
||||||
|
|
||||||
|
/* Check if RTC is operating in 12-hour mode */
|
||||||
|
if(!(RegisterB & CMOS_REGISTER_B_24_HOUR))
|
||||||
|
{
|
||||||
|
/* Cache the PM status and strip the hardware flag */
|
||||||
|
PostMeridiem = (Time->Hour & CMOS_RTC_POST_MERIDIEM) != 0;
|
||||||
|
Time->Hour &= ~CMOS_RTC_POST_MERIDIEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert Binary-Coded Decimal (BCD) values to standard integers if necessary */
|
||||||
|
if(!(RegisterB & CMOS_REGISTER_B_BINARY))
|
||||||
|
{
|
||||||
|
/* Decode all standard time fields */
|
||||||
|
Time->Hour = BCD_TO_DECIMAL(Time->Hour);
|
||||||
|
Time->Minute = BCD_TO_DECIMAL(Time->Minute);
|
||||||
|
Time->Second = BCD_TO_DECIMAL(Time->Second);
|
||||||
|
Time->Day = BCD_TO_DECIMAL(Time->Day);
|
||||||
|
Time->Month = BCD_TO_DECIMAL(Time->Month);
|
||||||
|
Time->Year = BCD_TO_DECIMAL(Time->Year);
|
||||||
|
Time->Weekday = BCD_TO_DECIMAL(Time->Weekday);
|
||||||
|
|
||||||
|
/* Check if Century byte is available */
|
||||||
|
if(CenturyRegister)
|
||||||
|
{
|
||||||
|
/* Convert Century byte */
|
||||||
|
Century1 = BCD_TO_DECIMAL(Century1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standardize hours into a strict 24-hour format */
|
||||||
|
if(!(RegisterB & CMOS_REGISTER_B_24_HOUR))
|
||||||
|
{
|
||||||
|
/* Adjust for midnight and noon boundary cases */
|
||||||
|
if(Time->Hour == 12)
|
||||||
|
{
|
||||||
|
/* 12 AM evaluates to 00:00, 12 PM evaluates to 12:00 */
|
||||||
|
Time->Hour = PostMeridiem ? 12 : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Add 12 hours for PM times */
|
||||||
|
Time->Hour += PostMeridiem ? 12 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Merge the century offset with the 2-digit hardware year */
|
||||||
|
if(Century1 >= 19 && Century1 <= 30)
|
||||||
|
{
|
||||||
|
/* Utilize the hardware-provided century base */
|
||||||
|
Time->Year += (Century1 * 100);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Century byte is invalid; apply the sliding window */
|
||||||
|
Time->Year += (Time->Year > 80) ? 1900 : 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return status code */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the hardware Real-Time Clock (RTC) with the provided date and time.
|
||||||
|
*
|
||||||
|
* @param Time
|
||||||
|
* Supplies a pointer to a structure with populated data and time.
|
||||||
|
*
|
||||||
|
* @return This routine returns the status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
HL::Rtc::SetRealTimeClock(IN PTIME_FIELDS Time)
|
||||||
|
{
|
||||||
|
UCHAR Century, CenturyRegister, RegisterB;
|
||||||
|
TIME_FIELDS SystemTime;
|
||||||
|
BOOLEAN PostMeridiem;
|
||||||
|
PACPI_FADT FadtTable;
|
||||||
|
XTSTATUS Status;
|
||||||
|
|
||||||
|
/* Validate the input time boundaries against calendar limits */
|
||||||
|
if(Time->Hour > 23 || Time->Minute > 59 || Time->Second > 59 ||
|
||||||
|
Time->Day == 0 || Time->Day > 31 || Time->Month == 0 ||
|
||||||
|
Time->Month > 12 || Time->Weekday == 0 || Time->Weekday > 7)
|
||||||
|
{
|
||||||
|
/* Invalid time parameters, return error code */
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assume Ante Meridiem */
|
||||||
|
PostMeridiem = FALSE;
|
||||||
|
|
||||||
|
/* Extract local copy */
|
||||||
|
SystemTime.Hour = Time->Hour;
|
||||||
|
SystemTime.Minute = Time->Minute;
|
||||||
|
SystemTime.Second = Time->Second;
|
||||||
|
SystemTime.Day = Time->Day;
|
||||||
|
SystemTime.Month = Time->Month;
|
||||||
|
SystemTime.Year = (Time->Year % 100);
|
||||||
|
SystemTime.Weekday = Time->Weekday;
|
||||||
|
Century = (UCHAR)(Time->Year / 100);
|
||||||
|
|
||||||
|
/* Locate the ACPI FADT table */
|
||||||
|
Status = HL::Acpi::GetAcpiTable(ACPI_FADT_SIGNATURE, (PACPI_DESCRIPTION_HEADER*)&FadtTable);
|
||||||
|
if(Status == STATUS_SUCCESS && FadtTable && FadtTable->CenturyAlarmIndex)
|
||||||
|
{
|
||||||
|
/* Cache the dynamically provided Century register index */
|
||||||
|
CenturyRegister = FadtTable->CenturyAlarmIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Century register is unavailable */
|
||||||
|
CenturyRegister = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the RTC Status Register B to determine hardware data formats */
|
||||||
|
RegisterB = HL::Firmware::ReadCmosRegister(CMOS_REGISTER_B);
|
||||||
|
|
||||||
|
/* Format hours if the hardware is running in 12-hour mode */
|
||||||
|
if(!(RegisterB & CMOS_REGISTER_B_24_HOUR))
|
||||||
|
{
|
||||||
|
/* Determine if the time is PM */
|
||||||
|
PostMeridiem = (SystemTime.Hour >= 12);
|
||||||
|
|
||||||
|
/* Adjust for midnight and noon boundary cases */
|
||||||
|
if(SystemTime.Hour == 0)
|
||||||
|
{
|
||||||
|
/* Midnight evaluates to 12 AM */
|
||||||
|
SystemTime.Hour = 12;
|
||||||
|
}
|
||||||
|
else if(SystemTime.Hour > 12)
|
||||||
|
{
|
||||||
|
/* Post-noon hour */
|
||||||
|
SystemTime.Hour -= 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert to BCD first if needed and apply the hardware PM flag */
|
||||||
|
if(!(RegisterB & CMOS_REGISTER_B_BINARY))
|
||||||
|
{
|
||||||
|
/* Encode to BCD */
|
||||||
|
SystemTime.Hour = DECIMAL_TO_BCD(SystemTime.Hour);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply the hardware PM flag to the highest bit */
|
||||||
|
if(PostMeridiem)
|
||||||
|
{
|
||||||
|
/* Set PM flag */
|
||||||
|
SystemTime.Hour |= CMOS_RTC_POST_MERIDIEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 24-hour mode, simply encode to BCD if necessary */
|
||||||
|
if(!(RegisterB & CMOS_REGISTER_B_BINARY))
|
||||||
|
{
|
||||||
|
/* Encode to BCD */
|
||||||
|
SystemTime.Hour = DECIMAL_TO_BCD(SystemTime.Hour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert remaining standard fields to BCD if necessary */
|
||||||
|
if(!(RegisterB & CMOS_REGISTER_B_BINARY))
|
||||||
|
{
|
||||||
|
/* Encode all standard time fields */
|
||||||
|
SystemTime.Minute = DECIMAL_TO_BCD(SystemTime.Minute);
|
||||||
|
SystemTime.Second = DECIMAL_TO_BCD(SystemTime.Second);
|
||||||
|
SystemTime.Day = DECIMAL_TO_BCD(SystemTime.Day);
|
||||||
|
SystemTime.Month = DECIMAL_TO_BCD(SystemTime.Month);
|
||||||
|
SystemTime.Year = DECIMAL_TO_BCD(SystemTime.Year);
|
||||||
|
SystemTime.Weekday = DECIMAL_TO_BCD((UCHAR)SystemTime.Weekday);
|
||||||
|
|
||||||
|
/* Encode the Century byte */
|
||||||
|
Century = DECIMAL_TO_BCD(Century);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Freeze the RTC to prevent data tearing */
|
||||||
|
HL::Firmware::WriteCmosRegister(CMOS_REGISTER_B, RegisterB | CMOS_REGISTER_B_SET_CLOCK);
|
||||||
|
|
||||||
|
/* Push the formatted time values into the hardware registers */
|
||||||
|
HL::Firmware::WriteCmosRegister(CMOS_REGISTER_HOUR, SystemTime.Hour);
|
||||||
|
HL::Firmware::WriteCmosRegister(CMOS_REGISTER_MINUTE, SystemTime.Minute);
|
||||||
|
HL::Firmware::WriteCmosRegister(CMOS_REGISTER_SECOND, SystemTime.Second);
|
||||||
|
HL::Firmware::WriteCmosRegister(CMOS_REGISTER_DAY, SystemTime.Day);
|
||||||
|
HL::Firmware::WriteCmosRegister(CMOS_REGISTER_MONTH, SystemTime.Month);
|
||||||
|
HL::Firmware::WriteCmosRegister(CMOS_REGISTER_YEAR, SystemTime.Year);
|
||||||
|
HL::Firmware::WriteCmosRegister(CMOS_REGISTER_WEEKDAY, SystemTime.Weekday);
|
||||||
|
|
||||||
|
/* Check if Century register is available */
|
||||||
|
if(CenturyRegister)
|
||||||
|
{
|
||||||
|
/* Write the corresponding Century register */
|
||||||
|
HL::Firmware::WriteCmosRegister(CenturyRegister, Century);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unfreeze the RTC */
|
||||||
|
HL::Firmware::WriteCmosRegister(CMOS_REGISTER_B, RegisterB);
|
||||||
|
|
||||||
|
/* Return success status code */
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <hl/ioreg.hh>
|
#include <hl/ioreg.hh>
|
||||||
#include <hl/irq.hh>
|
#include <hl/irq.hh>
|
||||||
#include <hl/pic.hh>
|
#include <hl/pic.hh>
|
||||||
|
#include <hl/rtc.hh>
|
||||||
#include <hl/runlevel.hh>
|
#include <hl/runlevel.hh>
|
||||||
#include <hl/timer.hh>
|
#include <hl/timer.hh>
|
||||||
|
|
||||||
|
|||||||
26
xtoskrnl/includes/hl/rtc.hh
Normal file
26
xtoskrnl/includes/hl/rtc.hh
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* PROJECT: ExectOS
|
||||||
|
* COPYRIGHT: See COPYING.md in the top level directory
|
||||||
|
* FILE: xtoskrnl/includes/hl/rtc.hh
|
||||||
|
* DESCRIPTION: Hardware Real-Time Clock (RTC) support
|
||||||
|
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __XTOSKRNL_HL_RTC_HH
|
||||||
|
#define __XTOSKRNL_HL_RTC_HH
|
||||||
|
|
||||||
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/* Hardware Layer */
|
||||||
|
namespace HL
|
||||||
|
{
|
||||||
|
class Rtc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
STATIC XTAPI XTSTATUS GetRealTimeClock(OUT PTIME_FIELDS Time);
|
||||||
|
STATIC XTAPI XTSTATUS SetRealTimeClock(IN PTIME_FIELDS Time);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __XTOSKRNL_HL_RTC_HH */
|
||||||
Reference in New Issue
Block a user