[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 1/2] hw/sd/sdhci: Fix boundary_count overflow in sdhci_sdma_tr
From: |
Jamin Lin |
Subject: |
[PATCH v2 1/2] hw/sd/sdhci: Fix boundary_count overflow in sdhci_sdma_transfer_multi_blocks |
Date: |
Fri, 13 Dec 2024 11:12:04 +0800 |
How to reproduce it:
1. The value of "s->blksie" was 0x7200. The bits[14:12] was "111", so the buffer
boundary was 0x80000.(512Kbytes). This SDMA buffer boundary was the same as
u-boot default value.
The bit[11:0] was "001000000000", so the block size was 0x200.(512bytes)
2. The SDMA address was 0x83123456 which was not page aligned and
"s->sdmasysad % boundary_chk" was 0x23456. The value of boundary_count was
0x5cbaa.("boundary_chk - (s->sdmasysad % boundary_chk)" -->
"(0x80000 - 0x23456)")
However, boundary_count did not align the block size 512 bytes and the SDMA
address was not page aligned(0x80000), so the following if-statement never be
true,
```
if (((boundary_count + begin) < block_size) && page_aligned)
````
Finally, it caused boundary_count overflow because its data type was uint32_t.
Ex: the last boundary_count was 0x1aa and "0x1aa - 0x200" became "0xffffffaa".
It is the wrong behavior.
To fix it, change to check boundary_count smaller than block size if system
address did not page align
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/sd/sdhci.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 37875c02c3..f1a329fdaf 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -618,7 +618,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
sdbus_read_data(&s->sdbus, s->fifo_buffer, block_size);
}
begin = s->data_count;
- if (((boundary_count + begin) < block_size) && page_aligned) {
+ if (((boundary_count + begin) < block_size) && !page_aligned) {
s->data_count = boundary_count + begin;
boundary_count = 0;
} else {
@@ -634,7 +634,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
if (s->data_count == block_size) {
s->data_count = 0;
}
- if (page_aligned && boundary_count == 0) {
+ if (boundary_count == 0) {
break;
}
}
@@ -642,7 +642,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
s->prnsts |= SDHC_DOING_WRITE;
while (s->blkcnt) {
begin = s->data_count;
- if (((boundary_count + begin) < block_size) && page_aligned) {
+ if (((boundary_count + begin) < block_size) && !page_aligned) {
s->data_count = boundary_count + begin;
boundary_count = 0;
} else {
@@ -659,7 +659,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
s->blkcnt--;
}
}
- if (page_aligned && boundary_count == 0) {
+ if (boundary_count == 0) {
break;
}
}
--
2.34.1