CMOS Hardware Interface
Relevant source files
This document explains the low-level hardware interface for accessing the Real Time Clock (RTC) through CMOS registers on x86_64 systems. It covers the I/O port protocol, register mapping, hardware synchronization, and platform-specific implementation details.
For high-level RTC API usage, see RTC Driver API. For data format conversion details, see Data Format Handling.
CMOS Register Map
The CMOS RTC uses a well-defined register layout accessible through I/O ports. The implementation defines specific register addresses and control flags for accessing time, date, and status information.
Time and Date Registers
flowchart TD
subgraph subGraph3["Format Flags"]
UIP["CMOS_UPDATE_IN_PROGRESS_FLAGBit 7"]
H24["CMOS_24_HOUR_FORMAT_FLAGBit 1"]
BIN["CMOS_BINARY_FORMAT_FLAGBit 2"]
PM["CMOS_12_HOUR_PM_FLAG0x80"]
end
subgraph subGraph2["Status Registers"]
DAY["CMOS_DAY_REGISTER0x07"]
MONTH["CMOS_MONTH_REGISTER0x08"]
YEAR["CMOS_YEAR_REGISTER0x09"]
STATA["CMOS_STATUS_REGISTER_A0x0AUpdate Progress"]
STATB["CMOS_STATUS_REGISTER_B0x0BFormat Control"]
end
subgraph subGraph0["Time Registers"]
SEC["CMOS_SECOND_REGISTER0x00"]
MIN["CMOS_MINUTE_REGISTER0x02"]
HOUR["CMOS_HOUR_REGISTER0x04"]
end
subgraph subGraph1["Date Registers"]
DAY["CMOS_DAY_REGISTER0x07"]
MONTH["CMOS_MONTH_REGISTER0x08"]
YEAR["CMOS_YEAR_REGISTER0x09"]
STATA["CMOS_STATUS_REGISTER_A0x0AUpdate Progress"]
end
HOUR --> PM
STATA --> UIP
STATB --> BIN
STATB --> H24
Sources: src/lib.rs(L10 - L23)
Register Access Pattern
| Register | Address | Purpose | Format Dependencies |
|---|---|---|---|
| CMOS_SECOND_REGISTER | 0x00 | Current second (0-59) | BCD/Binary |
| CMOS_MINUTE_REGISTER | 0x02 | Current minute (0-59) | BCD/Binary |
| CMOS_HOUR_REGISTER | 0x04 | Current hour | BCD/Binary + 12/24-hour |
| CMOS_DAY_REGISTER | 0x07 | Day of month (1-31) | BCD/Binary |
| CMOS_MONTH_REGISTER | 0x08 | Month (1-12) | BCD/Binary |
| CMOS_YEAR_REGISTER | 0x09 | Year (0-99, + 2000) | BCD/Binary |
| CMOS_STATUS_REGISTER_A | 0x0A | Update status | Raw binary |
| CMOS_STATUS_REGISTER_B | 0x0B | Format configuration | Raw binary |
I/O Port Protocol
The CMOS interface uses a two-port protocol where register selection and data transfer are performed through separate I/O ports.
Port Configuration
flowchart TD
subgraph subGraph2["Access Functions"]
READ["read_cmos_register()"]
WRITE["write_cmos_register()"]
end
subgraph subGraph1["Port Operations"]
CMDPORT["Port<u8>COMMAND_PORT"]
DATAPORT["Port<u8>DATA_PORT"]
end
subgraph subGraph0["I/O Port Interface"]
CMD["CMOS_COMMAND_PORT0x70Register Selection"]
DATA["CMOS_DATA_PORT0x71Data Transfer"]
end
CMD --> CMDPORT
CMDPORT --> READ
CMDPORT --> WRITE
DATA --> DATAPORT
DATAPORT --> READ
DATAPORT --> WRITE
Sources: src/lib.rs(L198 - L204)
Hardware Communication Protocol
The CMOS access protocol follows a strict sequence to ensure reliable register access:
sequenceDiagram
participant CPU as CPU
participant COMMAND_PORT0x70 as "COMMAND_PORT (0x70)"
participant DATA_PORT0x71 as "DATA_PORT (0x71)"
participant CMOSChip as "CMOS Chip"
Note over CPU: Read Operation
CPU ->> COMMAND_PORT0x70: "CMOS_DISABLE_NMI | register"
COMMAND_PORT0x70 ->> CMOSChip: "Select Register"
CPU ->> DATA_PORT0x71: "read()"
DATA_PORT0x71 ->> CMOSChip: "Read Request"
CMOSChip ->> DATA_PORT0x71: "Register Value"
DATA_PORT0x71 ->> CPU: "Return Value"
Note over CPU: Write Operation
CPU ->> COMMAND_PORT0x70: "CMOS_DISABLE_NMI | register"
COMMAND_PORT0x70 ->> CMOSChip: "Select Register"
CPU ->> DATA_PORT0x71: "write(value)"
DATA_PORT0x71 ->> CMOSChip: "Write Value"
Sources: src/lib.rs(L206 - L218)
Hardware Access Implementation
Register Read Operation
The read_cmos_register function implements the low-level hardware access protocol:
flowchart TD
subgraph subGraph1["Hardware Control"]
NMI["CMOS_DISABLE_NMIBit 7 = 1Prevents interrupts"]
REGSEL["Register SelectionBits 0-6"]
end
subgraph subGraph0["read_cmos_register Function"]
START["Start: register parameter"]
SELECTREG["Write to COMMAND_PORTCMOS_DISABLE_NMI | register"]
READDATA["Read from DATA_PORT"]
RETURN["Return u8 value"]
end
READDATA --> RETURN
SELECTREG --> NMI
SELECTREG --> READDATA
SELECTREG --> REGSEL
START --> SELECTREG
Sources: src/lib.rs(L206 - L211)
Register Write Operation
The write_cmos_register function handles data updates to CMOS registers:
flowchart TD
subgraph subGraph1["Safety Considerations"]
UNSAFE["unsafe blockRaw port access"]
RAWPTR["raw mut pointerStatic port references"]
end
subgraph subGraph0["write_cmos_register Function"]
START["Start: register, value parameters"]
SELECTREG["Write to COMMAND_PORTCMOS_DISABLE_NMI | register"]
WRITEDATA["Write value to DATA_PORT"]
END["End"]
end
SELECTREG --> UNSAFE
SELECTREG --> WRITEDATA
START --> SELECTREG
WRITEDATA --> END
WRITEDATA --> RAWPTR
Sources: src/lib.rs(L213 - L218)
Status Register Management
Update Synchronization
The CMOS chip updates its registers autonomously, requiring careful synchronization to avoid reading inconsistent values:
flowchart TD
subgraph subGraph0["Update Detection Flow"]
CHECK1["Read CMOS_STATUS_REGISTER_A"]
TESTFLAG1["Test CMOS_UPDATE_IN_PROGRESS_FLAG"]
WAIT["spin_loop() while updating"]
READ1["Read all time registers"]
CHECK2["Read CMOS_STATUS_REGISTER_A again"]
TESTFLAG2["Test update flag again"]
READ2["Read all time registers again"]
COMPARE["Compare both readings"]
RETURN["Return consistent value"]
end
read2["read2"]
CHECK1 --> TESTFLAG1
CHECK2 --> TESTFLAG2
COMPARE --> CHECK1
COMPARE --> RETURN
READ1 --> CHECK2
TESTFLAG1 --> READ1
TESTFLAG1 --> WAIT
TESTFLAG2 --> CHECK1
TESTFLAG2 --> READ2
WAIT --> CHECK1
read2 --> COMPARE
Sources: src/lib.rs(L107 - L129)
Format Detection
The implementation reads CMOS_STATUS_REGISTER_B during initialization to determine data format:
| Flag | Bit Position | Purpose | Impact |
|---|---|---|---|
| CMOS_24_HOUR_FORMAT_FLAG | 1 | Hour format detection | Affects hour register interpretation |
| CMOS_BINARY_FORMAT_FLAG | 2 | Number format detection | Determines BCD vs binary conversion |
Sources: src/lib.rs(L30 - L36)
Platform Abstraction
Conditional Compilation
The implementation uses conditional compilation to provide platform-specific functionality:
flowchart TD
subgraph subGraph2["Fallback Implementation"]
STUBREAD["Stub read_cmos_register()Returns 0"]
STUBWRITE["Stub write_cmos_register()No operation"]
end
subgraph subGraph1["x86/x86_64 Implementation"]
REALPORTS["Real I/O Port Accessx86_64::instructions::port::Port"]
REALREAD["Actual CMOS register reads"]
REALWRITE["Actual CMOS register writes"]
end
subgraph subGraph0["Compilation Targets"]
X86["x86/x86_64target_arch"]
OTHER["Other Architectures"]
end
OTHER --> STUBREAD
OTHER --> STUBWRITE
REALPORTS --> REALREAD
REALPORTS --> REALWRITE
X86 --> REALPORTS
Sources: src/lib.rs(L196 - L226)
Safety Considerations
The hardware access requires unsafe code due to direct I/O port manipulation:
- Raw pointer access: Static
Port<u8>instances require raw mutable references - Interrupt safety:
CMOS_DISABLE_NMIflag prevents hardware interrupts during access - Atomic operations: The two-port protocol ensures atomic register selection and data transfer
Sources: src/lib.rs(L207 - L217)