clean_dcache_by_address misses the last cache line when addr is not line-aligned
Maintainer thường phản hồi trong vòng 2 ngày
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 79/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- rust
- Lĩnh vực
- embedded-iot
Hướng nghiên cứu
Tìm clean_dcache_by_address và clean_invalidate_dcache_by_address, mà theo báo cáo sử dụng cùng một phép tính số dòng; lần theo các helper slice và tham chiếu gọi hàm clean. Trước tiên, hãy kiểm tra kích thước dòng cache và cách làm tròn địa chỉ trong các phần triển khai đó. Công việc hoàn tất khi mọi dòng cache bị tác động bởi các buffer không căn chỉnh đều được clean và hành vi ở ranh giới nhất quán với phép tính byte cuối cùng được báo cáo.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
cortex-m 0.7.10 (same code on main), Cortex-M7.
Steps to reproduce (on a PC, the line count only):
cargo new lines && cd lines- Put the program below in
src/main.rs. cargo run -q
What the program does:
- Copies the line count of
clean_dcache_by_address. - Takes a 1460-byte buffer at three addresses.
- The first address is on a line.
- The second is 20 bytes into a line.
- The third is 28 bytes into a line.
- Computes the range the function cleans for each.
- Prints how many bytes at the end of the buffer are not cleaned.
Expected: 0 bytes not cleaned for every address.
The docs say the function cleans "until all of slice has been cleaned".
The docs only recommend alignment.
Got:
addr 0x24000000 size 1460: cleans 0x24000000..0x240005c0, buffer ends 0x240005b4, last 0 bytes not cleaned
addr 0x24000014 size 1460: cleans 0x24000000..0x240005c0, buffer ends 0x240005c8, last 8 bytes not cleaned
addr 0x2400001c size 1460: cleans 0x24000000..0x240005c0, buffer ends 0x240005d0, last 16 bytes not cleaned
On hardware (STM32H753, Cortex-M7, cortex-m 0.7.9, which has the same code):
- A 1460-byte buffer on the stack.
- The CPU writes the buffer.
clean_dcache_by_sliceon the buffer.- The USART's TX DMA sends the buffer.
Expected: the receiver gets the bytes the CPU wrote.
Got: the last 8 bytes were stale in 609 of 685 writes.
With the buffer aligned to 32 bytes: 0 wrong.
Cause:
clean_dcache_by_addressroundsaddrdown to its cache line:let mut addr = addr & mask;- It counts the lines from
sizealone:let num_lines = ((size - 1) / line_size) + 1; - A buffer that starts inside a line reaches one line further than
sizealone says. - That last line is never cleaned.
- The DMA reads old bytes from RAM there.
Also affected:
clean_invalidate_dcache_by_addresshas the same computation.clean_dcache_by_slicecallsclean_dcache_by_address.clean_dcache_by_refcallsclean_dcache_by_address.
Not affected in the same way:
invalidate_dcache_by_addresshas the same computation.- But it is
unsafe. - And it requires an aligned
addrandsize.
Fix:
- Round
addrdown to its line: the first line. - Round the last byte,
addr + size - 1, down to its line: the last line. - Count the lines from the first line to the last line.
let first = addr & mask;
let last = addr.saturating_add(size - 1) & mask;
let num_lines = (last - first) / line_size + 1;
Why the last byte and not the end:
- The end,
addr + size, rounded up can overflow at the top of the address space. - The last byte's address always fits.
saturating_addstops a range that runs past the top at the top.
Workaround until a release has the fix:
- Align the buffer to 32 bytes.
- Or round
addrdown andaddr + sizeup yourself before the call.
Program:
// The line count of cortex-m 0.7.10's SCB::clean_dcache_by_address, next to the lines a buffer touches.
const LINE: usize = 32;
fn cleaned(addr: usize, size: usize) -> (usize, usize) {
let num_lines = ((size - 1) / LINE) + 1; // as in clean_dcache_by_address
let start = addr & !(LINE - 1);
(start, start + num_lines * LINE) // [start, end) the function cleans
}
fn main() {
let size = 1460;
for addr in [0x2400_0000, 0x2400_0014, 0x2400_001c] {
let (start, end) = cleaned(addr, size);
let missed = (addr + size).saturating_sub(end);
println!("addr {addr:#x} size {size}: cleans {start:#x}..{end:#x}, buffer ends {:#x}, last {missed} bytes not cleaned", addr + size);
}
}
- Ngôn ngữ chính
- Rust
- Star
- 1k
- Fork
- 203
- Merge trung bình
- 1 ngày 4 giờ
- Pull request đã merge (30 ngày)
- 2
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của rust-embedded/cortex-m
-
Deprecation of `bare-metal`Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
rust-embedded/cortex-m#651 · 5 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
rust-embedded/cortex-m#637 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
rust-embedded/cortex-m#511 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Rename default branch to `main`Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 55/100
rust-embedded/cortex-m#700 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Add CFI directives to asm blocksĐang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
rust-embedded/cortex-m#695 ·
Maintainer thường phản hồi trong vòng 2 ngày
Tất cả issue của rust-embedded/cortex-m
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
apache/datafusion-iceberg#100 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Bug]: cua-driver skill fails Agent Skills frontmatter validationCó thể đã có người làm @Mearman đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area/tools bug session-analysis
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 80/100
oracle/rust-oracledb#66 ·
-
`PrimitiveArray::validate_decimal_precision` rejects every decimal array with a negative scaleĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày