-
Notifications
You must be signed in to change notification settings - Fork 1.9k
aarch64: Implement RTC Pl031 #1103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
dc1ac18
to
a9cf91d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still need to review some parts of the RTC dev implementation, but so far LGTM.
arch/src/aarch64/fdt.rs
Outdated
( | ||
"rtc".to_string(), | ||
MMIODeviceInfo { | ||
addr: 0x00 + LEN, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this overlapping the previous virtio device address space? Am I missing something? 😕
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, Yes indeed I used the same base address for both devices but this is an unit test whose purpose is to check that the fdt turns exactly how we intend it to be. We are not using it to spawn a vm. However, I will change it in order to avoid any confusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check data for size when working with LittleEndian. Otherwise minor nits.
use time::{SteadyTime, Timespec}; | ||
//use bus::Error; | ||
|
||
// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have a link to the documentation in the commit message as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, take a look.
devices/src/legacy/rtc_pl031.rs
Outdated
pub struct RTC { | ||
previous_now: SteadyTime, | ||
tick_offset: Timespec, | ||
// THis is used for implementing the RTC alarm. However, in Firecracker we do not need it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: This
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
devices/src/legacy/rtc_pl031.rs
Outdated
// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf | ||
// at section 3.2 Summary of RTC registers, the total size occupied by this device is 0x000 -> 0xFFC + 4 = 0x1000. | ||
// From 0x0 to 0x1C we have following registers: | ||
const DR: u64 = 0x0; // Data Register. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The documentation lists these as RTCDR, RTCMR, etc. Having them written exactly as such would make it easier to find and match them between the code and the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
devices/src/legacy/rtc_pl031.rs
Outdated
ts.sec as u32 | ||
} | ||
|
||
fn handle_write(&mut self, offset: u64, v: u32) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: v
should be val
or value
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed it to val.
devices/src/legacy/rtc_pl031.rs
Outdated
if read_ok { | ||
LittleEndian::write_u32(data, v); | ||
} else { | ||
error!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This case seems to be an error with the driver of the device and not the device itself. While this could be printed out, I think it should fall under debug or info, maybe warn at most.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, error might be too much. I do think though that it is more than an info since not having the time updated could lead to other serious problems. So, I left it as a warning.
devices/src/legacy/rtc_pl031.rs
Outdated
fn write(&mut self, offset: u64, data: &[u8]) { | ||
let v = LittleEndian::read_u32(data); | ||
if let Err(e) = self.handle_write(offset, v) { | ||
error!("Failed to write to RTC PL031 device: {}", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above: some errors here come from a bad driver implementation and not a faulty device.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified it.
match_value: u32, | ||
// Writes to this register load an update value into the RTC. | ||
load: u32, | ||
imsc: u32, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the spec this could be a boolean, which is more suggestive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the spec this is a 1bit register. Moreover, look at what the documentation specifies for the RTCICR
register: "The interrupt is cleared by writing any data value to the Interrupt Clear Register, RTCICR". Indeed, these register could very well be represented as bool but since my read/write functions receive data of [u8]
type, I d need to add additional post processing logic to transform it to a bool. I d like to keep the model as simple as possible.
// Writes to this register load an update value into the RTC. | ||
load: u32, | ||
imsc: u32, | ||
ris: u32, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also a boolean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See previous comment.
devices/src/legacy/rtc_pl031.rs
Outdated
} | ||
|
||
fn write(&mut self, offset: u64, data: &[u8]) { | ||
let v = LittleEndian::read_u32(data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The byteorder crate seems crazy and according to documentation it might panic instead of returning a result, if data is not the right size. Checking this beforehand is probably recommended, since a badly written driver could try to write an u64 instead. https://docs.rs/byteorder/1.3.1/byteorder/trait.ByteOrder.html#tymethod.read_u32
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a check for that. Take a look.
}; | ||
} | ||
if read_ok { | ||
LittleEndian::write_u32(data, v); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data might not have enough space for a u32 value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, i added a check to ensure data.len <=4
. take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petreeftime @acatangiu addressed comments. Please review.
arch/src/aarch64/fdt.rs
Outdated
( | ||
"rtc".to_string(), | ||
MMIODeviceInfo { | ||
addr: 0x00 + LEN, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, Yes indeed I used the same base address for both devices but this is an unit test whose purpose is to check that the fdt turns exactly how we intend it to be. We are not using it to spawn a vm. However, I will change it in order to avoid any confusion.
use time::{SteadyTime, Timespec}; | ||
//use bus::Error; | ||
|
||
// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, take a look.
devices/src/legacy/rtc_pl031.rs
Outdated
// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf | ||
// at section 3.2 Summary of RTC registers, the total size occupied by this device is 0x000 -> 0xFFC + 4 = 0x1000. | ||
// From 0x0 to 0x1C we have following registers: | ||
const DR: u64 = 0x0; // Data Register. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
devices/src/legacy/rtc_pl031.rs
Outdated
pub struct RTC { | ||
previous_now: SteadyTime, | ||
tick_offset: Timespec, | ||
// THis is used for implementing the RTC alarm. However, in Firecracker we do not need it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// Writes to this register load an update value into the RTC. | ||
load: u32, | ||
imsc: u32, | ||
ris: u32, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See previous comment.
devices/src/legacy/rtc_pl031.rs
Outdated
ts.sec as u32 | ||
} | ||
|
||
fn handle_write(&mut self, offset: u64, v: u32) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed it to val.
}; | ||
} | ||
if read_ok { | ||
LittleEndian::write_u32(data, v); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, i added a check to ensure data.len <=4
. take a look.
devices/src/legacy/rtc_pl031.rs
Outdated
if read_ok { | ||
LittleEndian::write_u32(data, v); | ||
} else { | ||
error!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, error might be too much. I do think though that it is more than an info since not having the time updated could lead to other serious problems. So, I left it as a warning.
devices/src/legacy/rtc_pl031.rs
Outdated
} | ||
|
||
fn write(&mut self, offset: u64, data: &[u8]) { | ||
let v = LittleEndian::read_u32(data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a check for that. Take a look.
devices/src/legacy/rtc_pl031.rs
Outdated
fn write(&mut self, offset: u64, data: &[u8]) { | ||
let v = LittleEndian::read_u32(data); | ||
if let Err(e) = self.handle_write(offset, v) { | ||
error!("Failed to write to RTC PL031 device: {}", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified it.
Since on arm there is no kvmclock, we need to implement an RTC device. This commit implements the AMBA PL031 specification. See https://static.docs.arm.com/ddi0224/c/ real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf Signed-off-by: Diana Popa <[email protected]>
Since on arm there is no kvmclock, we need to
implement an RTC device. Implements RTC PL031.
Follow specification:
https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf
Signed-off-by: Diana Popa [email protected]
Issue #, if available: Fixes #1066
Description of changes:
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.