Skip to content

Commit 00892c2

Browse files
committed
Clamp unaligned SDHCI disk I/O spans
F/2566
1 parent 42c312e commit 00892c2

3 files changed

Lines changed: 205 additions & 1 deletion

File tree

src/sdhci.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,9 @@ int disk_read(int drv, uint64_t start, uint32_t count, uint8_t *buf)
15501550
start_offset != 0 || /* start not block aligned */
15511551
((uintptr_t)buf % 4) != 0) /* buf not 4-byte aligned */
15521552
{
1553+
if (read_sz > (SDHCI_BLOCK_SIZE - start_offset)) {
1554+
read_sz = SDHCI_BLOCK_SIZE - start_offset;
1555+
}
15531556
/* block read to temporary buffer */
15541557
status = sdhci_read(MMC_CMD17_READ_SINGLE, block_addr,
15551558
tmp_block, SDHCI_BLOCK_SIZE);
@@ -1602,6 +1605,9 @@ int disk_write(int drv, uint64_t start, uint32_t count, const uint8_t *buf)
16021605
start_offset != 0 || /* start not block aligned */
16031606
((uintptr_t)buf % 4) != 0) /* buf not 4-byte aligned */
16041607
{
1608+
if (write_sz > (SDHCI_BLOCK_SIZE - start_offset)) {
1609+
write_sz = SDHCI_BLOCK_SIZE - start_offset;
1610+
}
16051611
/* read-modify-write for partial block */
16061612
status = sdhci_read(MMC_CMD17_READ_SINGLE, block_addr,
16071613
tmp_block, SDHCI_BLOCK_SIZE);

tools/unit-tests/Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ TESTS:=unit-parser unit-fdt unit-extflash unit-string unit-spi-flash unit-aes128
5252
unit-update-disk unit-multiboot unit-boot-x86-fsp unit-qspi-flash unit-tpm-rsa-exp \
5353
unit-image-nopart unit-image-sha384 unit-image-sha3-384 unit-store-sbrk \
5454
unit-tpm-blob unit-policy-create unit-policy-sign unit-rot-auth unit-sdhci-response-bits \
55-
unit-sign-encrypted-output
55+
unit-sdhci-disk-unaligned unit-sign-encrypted-output
5656
TESTS+=unit-tpm-check-rot-auth
5757

5858
include unit-sign-encrypted-output.mkfrag
@@ -207,6 +207,10 @@ unit-sdhci-response-bits: ../../include/target.h unit-sdhci-response-bits.c
207207
gcc -o $@ $^ $(CFLAGS) -ffunction-sections -fdata-sections $(LDFLAGS) \
208208
-Wl,--gc-sections
209209

210+
unit-sdhci-disk-unaligned: ../../include/target.h unit-sdhci-disk-unaligned.c
211+
gcc -o $@ $^ $(CFLAGS) -ffunction-sections -fdata-sections $(LDFLAGS) \
212+
-Wl,--gc-sections
213+
210214
unit-aes128: ../../include/target.h unit-extflash.c
211215
gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)
212216

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/* unit-sdhci-disk-unaligned.c
2+
*
3+
* Unit tests for unaligned disk I/O via sdhci.c.
4+
*
5+
* Copyright (C) 2026 wolfSSL Inc.
6+
*
7+
* This file is part of wolfBoot.
8+
*
9+
* wolfBoot is free software; you can redistribute it and/or modify
10+
* it under the terms of the GNU General Public License as published by
11+
* the Free Software Foundation; either version 3 of the License, or
12+
* (at your option) any later version.
13+
*
14+
* wolfBoot is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program; if not, write to the Free Software
21+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
22+
*/
23+
24+
#define DISK_SDCARD 1
25+
26+
#include <check.h>
27+
#include <stdint.h>
28+
#include <string.h>
29+
30+
#include "sdhci.h"
31+
32+
static uint32_t mock_regs[0x260 / sizeof(uint32_t)];
33+
static uint8_t mock_disk[SDHCI_BLOCK_SIZE * 4];
34+
35+
struct transfer_state {
36+
int active;
37+
int is_read;
38+
uint32_t block_addr;
39+
uint32_t word_index;
40+
uint32_t word_count;
41+
};
42+
43+
static struct transfer_state xfer;
44+
45+
uint64_t hal_get_timer_us(void)
46+
{
47+
static uint64_t now;
48+
return ++now;
49+
}
50+
51+
uint32_t sdhci_reg_read(uint32_t offset)
52+
{
53+
if (offset == SDHCI_SRS08 && xfer.active && xfer.is_read) {
54+
uint32_t pos = xfer.block_addr * SDHCI_BLOCK_SIZE + (xfer.word_index * 4);
55+
uint32_t val;
56+
57+
memcpy(&val, &mock_disk[pos], sizeof(val));
58+
xfer.word_index++;
59+
return val;
60+
}
61+
62+
return mock_regs[offset / sizeof(uint32_t)];
63+
}
64+
65+
void sdhci_reg_write(uint32_t offset, uint32_t val)
66+
{
67+
uint32_t *reg = &mock_regs[offset / sizeof(uint32_t)];
68+
69+
if (offset == SDHCI_SRS08 && xfer.active && !xfer.is_read) {
70+
uint32_t pos = xfer.block_addr * SDHCI_BLOCK_SIZE + (xfer.word_index * 4);
71+
72+
memcpy(&mock_disk[pos], &val, sizeof(val));
73+
xfer.word_index++;
74+
return;
75+
}
76+
77+
if (offset == SDHCI_SRS11) {
78+
*reg = val | (val & SDHCI_SRS11_ICE ? SDHCI_SRS11_ICS : 0);
79+
*reg &= ~SDHCI_SRS11_RESET_DAT_CMD;
80+
return;
81+
}
82+
83+
if (offset == SDHCI_SRS12) {
84+
*reg &= ~val;
85+
return;
86+
}
87+
88+
*reg = val;
89+
90+
if (offset == SDHCI_SRS03) {
91+
if (val & SDHCI_SRS03_DPS) {
92+
xfer.active = 1;
93+
xfer.is_read = (val & SDHCI_SRS03_DTDS) != 0;
94+
xfer.block_addr = mock_regs[SDHCI_SRS02 / sizeof(uint32_t)];
95+
xfer.word_index = 0;
96+
xfer.word_count = SDHCI_BLOCK_SIZE / sizeof(uint32_t);
97+
mock_regs[SDHCI_SRS12 / sizeof(uint32_t)] |= xfer.is_read ?
98+
(SDHCI_SRS12_BRR | SDHCI_SRS12_TC) :
99+
(SDHCI_SRS12_BWR | SDHCI_SRS12_TC);
100+
}
101+
else {
102+
mock_regs[SDHCI_SRS04 / sizeof(uint32_t)] = (1U << 8);
103+
mock_regs[SDHCI_SRS12 / sizeof(uint32_t)] |= SDHCI_SRS12_CC;
104+
}
105+
}
106+
}
107+
108+
void sdhci_platform_init(void)
109+
{
110+
}
111+
112+
void sdhci_platform_irq_init(void)
113+
{
114+
}
115+
116+
void sdhci_platform_set_bus_mode(int is_emmc)
117+
{
118+
(void)is_emmc;
119+
}
120+
121+
#include "../../src/sdhci.c"
122+
123+
static void reset_mock_state(void)
124+
{
125+
uint32_t i;
126+
127+
memset(mock_regs, 0, sizeof(mock_regs));
128+
memset(&xfer, 0, sizeof(xfer));
129+
for (i = 0; i < sizeof(mock_disk); i++) {
130+
mock_disk[i] = (uint8_t)i;
131+
}
132+
}
133+
134+
START_TEST(test_disk_read_unaligned_spans_blocks)
135+
{
136+
uint8_t out[SDHCI_BLOCK_SIZE];
137+
uint8_t expected[SDHCI_BLOCK_SIZE];
138+
139+
reset_mock_state();
140+
141+
memcpy(expected, &mock_disk[SDHCI_BLOCK_SIZE - 1], 1);
142+
memcpy(expected + 1, &mock_disk[SDHCI_BLOCK_SIZE], SDHCI_BLOCK_SIZE - 1);
143+
144+
ck_assert_int_eq(disk_read(0, SDHCI_BLOCK_SIZE - 1, sizeof(out), out), 0);
145+
ck_assert_mem_eq(out, expected, sizeof(out));
146+
}
147+
END_TEST
148+
149+
START_TEST(test_disk_write_unaligned_spans_blocks)
150+
{
151+
uint8_t in[SDHCI_BLOCK_SIZE];
152+
uint8_t before[sizeof(mock_disk)];
153+
uint32_t i;
154+
155+
reset_mock_state();
156+
memcpy(before, mock_disk, sizeof(before));
157+
158+
for (i = 0; i < sizeof(in); i++) {
159+
in[i] = (uint8_t)(0xA0U + (i & 0x1FU));
160+
}
161+
162+
ck_assert_int_eq(disk_write(0, SDHCI_BLOCK_SIZE - 1, sizeof(in), in), 0);
163+
ck_assert_mem_eq(mock_disk, before, SDHCI_BLOCK_SIZE - 1);
164+
ck_assert_uint_eq(mock_disk[SDHCI_BLOCK_SIZE - 1], in[0]);
165+
ck_assert_mem_eq(&mock_disk[SDHCI_BLOCK_SIZE], in + 1, SDHCI_BLOCK_SIZE - 1);
166+
ck_assert_uint_eq(mock_disk[(2 * SDHCI_BLOCK_SIZE) - 1],
167+
before[(2 * SDHCI_BLOCK_SIZE) - 1]);
168+
}
169+
END_TEST
170+
171+
Suite *sdhci_disk_suite(void)
172+
{
173+
Suite *s = suite_create("sdhci-disk");
174+
TCase *tc = tcase_create("unaligned");
175+
176+
tcase_add_test(tc, test_disk_read_unaligned_spans_blocks);
177+
tcase_add_test(tc, test_disk_write_unaligned_spans_blocks);
178+
suite_add_tcase(s, tc);
179+
180+
return s;
181+
}
182+
183+
int main(void)
184+
{
185+
int fails;
186+
Suite *s = sdhci_disk_suite();
187+
SRunner *sr = srunner_create(s);
188+
189+
srunner_run_all(sr, CK_NORMAL);
190+
fails = srunner_ntests_failed(sr);
191+
srunner_free(sr);
192+
193+
return fails;
194+
}

0 commit comments

Comments
 (0)