-
Notifications
You must be signed in to change notification settings - Fork 116
[DRAFT] Support MMIO regions #1328
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,4 +16,6 @@ pub struct HarnessMetadata { | |
pub original_line: String, | ||
/// Optional data to store unwind value | ||
pub unwind_value: Option<u32>, | ||
/// Optional MMIO regions | ||
pub mmio_regions: Vec<(u128, u128)>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we use |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,3 +73,26 @@ pub fn unwind(attr: TokenStream, item: TokenStream) -> TokenStream { | |
result.extend(item); | ||
result | ||
} | ||
|
||
#[cfg(not(kani))] | ||
#[proc_macro_attribute] | ||
pub fn mmio_region(_attr: TokenStream, item: TokenStream) -> TokenStream { | ||
// When the config is not kani, we should leave the function alone | ||
item | ||
} | ||
|
||
/// Set Loop unwind limit for proof harnesses | ||
/// The attribute '#[kani::unwind(arg)]' can only be called alongside '#[kani::proof]'. | ||
/// arg - Takes in a integer value (u32) that represents the unwind value for the harness. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update comment |
||
#[cfg(kani)] | ||
#[proc_macro_attribute] | ||
pub fn mmio_region(attr: TokenStream, item: TokenStream) -> TokenStream { | ||
let mut result = TokenStream::new(); | ||
|
||
// Translate #[kani::unwind(arg)] to #[kanitool::unwind(arg)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update comment |
||
let insert_string = "#[kanitool::mmio_region(".to_owned() + &attr.clone().to_string() + ")]"; | ||
result.extend(insert_string.parse::<TokenStream>().unwrap()); | ||
|
||
result.extend(item); | ||
result | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
Status: SUCCESS\ | ||
Description: "offset: attempt to compute number in bytes which would overflow" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems irrelevant for your test. I would just remove it. |
||
|
||
Status: SUCCESS\ | ||
Description: "attempt to compute offset which would overflow" | ||
|
||
Status: FAILURE\ | ||
Description: "dereference failure: pointer NULL" | ||
|
||
Status: SUCCESS | ||
Description: "dereference failure: pointer invalid" | ||
|
||
Status: FAILURE\ | ||
Description: "dereference failure: deallocated dynamic object" | ||
|
||
Status: FAILURE\ | ||
Description: "dereference failure: dead object" | ||
|
||
Status: FAILURE\ | ||
Description: "dereference failure: pointer outside object bounds" | ||
|
||
Status: FAILURE\ | ||
Description: "dereference failure: invalid integer address" | ||
|
||
Status: FAILURE\ | ||
Description: "dereference failure: invalid integer address" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
const BUFFER: *mut u32 = 0x8000 as *mut u32; | ||
const BUFFER2: *mut u32 = 0x1000 as *mut u32; | ||
|
||
#[cfg(kani)] | ||
#[kani::proof] | ||
#[kani::mmio_region(0x8000, 8)] | ||
fn test_write() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you rename this to |
||
let val = 12; | ||
unsafe { | ||
//BUFFER+2 is not in the MMIO region. Expect pointer check failures. | ||
*(BUFFER.offset(2)) = val; | ||
//BUFFER2 is not in the MMIO region. Expect pointer check failures. | ||
*BUFFER2 = val; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are not really checking that both fail though. This test will succeed if only one of these fail. You can either add the line in the file to the expected file or break this into two harness and add the function name. I prefer the second since it is always painful to maintain LoC up to date. |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright Kani Contributors | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please document what these tests are testing? |
||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
const BUFFER: *mut u32 = 0x8000 as *mut u32; | ||
|
||
#[cfg(kani)] | ||
#[kani::proof] | ||
#[kani::mmio_region(0x8000, 4)] | ||
fn test_read_after_write_doesnt_havoc() { | ||
let val = 12; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you use |
||
unsafe { | ||
core::ptr::write_volatile(BUFFER, val); | ||
let new_val = core::ptr::read_volatile(BUFFER); | ||
assert_eq!(new_val, val); | ||
} | ||
} | ||
|
||
#[cfg(kani)] | ||
#[kani::proof] | ||
#[kani::mmio_region(0x8000, 4)] | ||
fn test_read_is_stable() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But should it be stable? |
||
unsafe { | ||
let val1 = core::ptr::read_volatile(BUFFER); | ||
let val2 = core::ptr::read_volatile(BUFFER); | ||
assert_eq!(val1, val2); | ||
} | ||
} | ||
|
||
//TODO Weirdly, these fail even tho the other tests pass??? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks like a blocker to me. Maybe we should investigate this behavior a bit better. |
||
#[cfg(kani)] | ||
#[kani::proof] | ||
#[kani::mmio_region(0x8000, 16)] | ||
fn test_writes_dont_alias() { | ||
let val1 = 42; | ||
let val2 = 314; | ||
unsafe { | ||
let p1 = BUFFER; | ||
let p2 = BUFFER.offset(2); | ||
core::ptr::write_volatile(p1, val1); | ||
core::ptr::write_volatile(p2, val2); | ||
assert_eq!(core::ptr::read_volatile(p1), val1); | ||
assert_eq!(core::ptr::read_volatile(p2), val2); | ||
} | ||
} | ||
|
||
//TODO Weirdly, these fail even tho the other tests pass??? | ||
#[cfg(kani)] | ||
#[kani::proof] | ||
#[kani::mmio_region(0x8000, 16)] | ||
fn test_writes_dont_alias2() { | ||
let val1 = 42; | ||
let val2 = 314; | ||
unsafe { | ||
let p1 = BUFFER; | ||
let p2 = BUFFER.offset(2); | ||
*p1 = val1; | ||
*p2 = val2; | ||
assert_eq!(*p1, val1); | ||
assert_eq!(*p2, val2); | ||
assert_eq!(*p2, val1); | ||
assert_eq!(*p1, val2); | ||
Comment on lines
+60
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess that these should be changed like
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Copyright Kani Contributors | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you cover 0 sized operations? |
||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
const BUFFER: *mut u32 = 0x8000 as *mut u32; | ||
const BUFFER2: *mut u32 = 0x1000 as *mut u32; | ||
|
||
#[cfg(kani)] | ||
#[kani::proof] | ||
#[kani::mmio_region(0x8000, 4)] | ||
fn test_write() { | ||
let val = 12; | ||
unsafe { | ||
core::ptr::write_volatile(BUFFER, val); | ||
} | ||
} | ||
|
||
#[cfg(kani)] | ||
#[kani::proof] | ||
#[kani::mmio_region(0x8000, 4)] | ||
#[kani::mmio_region(0x1000, 4)] | ||
fn test_write2() { | ||
let val = 12; | ||
unsafe { | ||
core::ptr::write_volatile(BUFFER, val); | ||
core::ptr::write_volatile(BUFFER2, val); | ||
} | ||
} | ||
|
||
#[cfg(kani)] | ||
#[kani::proof] | ||
#[kani::mmio_region(0x8000, 8)] | ||
/// Check that larger MMIO regions also work | ||
fn test_write3() { | ||
let val = 12; | ||
unsafe { | ||
*BUFFER = val; | ||
*(BUFFER.offset(1)) = val; | ||
} | ||
} |
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.
Can you print or at least log which values we got?