Message ID | 20240628070216.92609-19-philmd@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | hw/sd/sdcard: Add eMMC support | expand |
On 6/28/24 9:00 AM, Philippe Mathieu-Daudé wrote: > All commands switching from TRANSFER state to (sending)DATA > do the same: send stream of data on the DAT lines. Instead > of duplicating the same code many times, introduce 2 helpers: > - sd_cmd_to_sendingdata() on the I/O line setup the data to > be transferred, > - sd_generic_read_byte() on the DAT lines to fetch the data. > > Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> > --- > hw/sd/sd.c | 39 +++++++++++++++++++++++++++++++++++++++ > 1 file changed, 39 insertions(+) > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index d85b2906f4..1a8d06804d 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -142,8 +142,10 @@ struct SDState { > */ > bool expecting_acmd; > uint32_t blk_written; > + > uint64_t data_start; > uint32_t data_offset; > + size_t data_size; > uint8_t data[512]; > uint8_t vendor_data[512]; > > @@ -1083,6 +1085,29 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) > return sd_illegal; > } > > +/* Configure fields for following sd_generic_read_byte() calls */ > +__attribute__((unused)) > +static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, > + uint64_t start, > + const void *data, size_t size) > +{ > + if (sd->state != sd_transfer_state) { > + sd_invalid_state_for_cmd(sd, req); > + } > + > + sd->state = sd_sendingdata_state; > + sd->data_start = start; > + sd->data_offset = 0; > + if (data) { > + assert(size); Shouldn't we check for buffer overrun ? sizeof(sd->data) Thanks, C. > + memcpy(sd->data, data, size); > + } > + if (size) { > + sd->data_size = size; > + } > + return sd_r1; > +} > + > /* CMD0 */ > static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) > { > @@ -1920,6 +1945,20 @@ send_response: > return rsplen; > } > > +/* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */ > +__attribute__((unused)) > +static bool sd_generic_read_byte(SDState *sd, uint8_t *value) > +{ > + *value = sd->data[sd->data_offset]; > + > + if (++sd->data_offset >= sd->data_size) { > + sd->state = sd_transfer_state; > + return true; > + } > + > + return false; > +} > + > void sd_write_byte(SDState *sd, uint8_t value) > { > int i;
On 28/6/24 09:44, Cédric Le Goater wrote: > On 6/28/24 9:00 AM, Philippe Mathieu-Daudé wrote: >> All commands switching from TRANSFER state to (sending)DATA >> do the same: send stream of data on the DAT lines. Instead >> of duplicating the same code many times, introduce 2 helpers: >> - sd_cmd_to_sendingdata() on the I/O line setup the data to >> be transferred, >> - sd_generic_read_byte() on the DAT lines to fetch the data. >> >> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> >> --- >> hw/sd/sd.c | 39 +++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 39 insertions(+) >> >> diff --git a/hw/sd/sd.c b/hw/sd/sd.c >> index d85b2906f4..1a8d06804d 100644 >> --- a/hw/sd/sd.c >> +++ b/hw/sd/sd.c >> @@ -142,8 +142,10 @@ struct SDState { >> */ >> bool expecting_acmd; >> uint32_t blk_written; >> + >> uint64_t data_start; >> uint32_t data_offset; >> + size_t data_size; >> uint8_t data[512]; >> uint8_t vendor_data[512]; >> @@ -1083,6 +1085,29 @@ static sd_rsp_type_t >> sd_cmd_unimplemented(SDState *sd, SDRequest req) >> return sd_illegal; >> } >> +/* Configure fields for following sd_generic_read_byte() calls */ >> +__attribute__((unused)) >> +static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, >> + uint64_t start, >> + const void *data, size_t >> size) >> +{ >> + if (sd->state != sd_transfer_state) { >> + sd_invalid_state_for_cmd(sd, req); >> + } >> + >> + sd->state = sd_sendingdata_state; >> + sd->data_start = start; >> + sd->data_offset = 0; >> + if (data) { >> + assert(size); > > Shouldn't we check for buffer overrun ? sizeof(sd->data) OK if I squash this? -- >8 -- diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d292e0adb5..f2d069c2da 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1123,7 +1123,7 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, sd->data_start = start; sd->data_offset = 0; if (data) { - assert(size); + assert(size > 0 && size <= sizeof(sd->data)); memcpy(sd->data, data, size); } --- > > Thanks, > > C. > > > >> + memcpy(sd->data, data, size); >> + } >> + if (size) { >> + sd->data_size = size; >> + } >> + return sd_r1; >> +} >> + >> /* CMD0 */ >> static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) >> { >> @@ -1920,6 +1945,20 @@ send_response: >> return rsplen; >> } >> +/* Return true when buffer is consumed. Configured by >> sd_cmd_to_sendingdata() */ >> +__attribute__((unused)) >> +static bool sd_generic_read_byte(SDState *sd, uint8_t *value) >> +{ >> + *value = sd->data[sd->data_offset]; >> + >> + if (++sd->data_offset >= sd->data_size) { >> + sd->state = sd_transfer_state; >> + return true; >> + } >> + >> + return false; >> +} >> + >> void sd_write_byte(SDState *sd, uint8_t value) >> { >> int i; >
On 7/1/24 6:40 PM, Philippe Mathieu-Daudé wrote: > On 28/6/24 09:44, Cédric Le Goater wrote: >> On 6/28/24 9:00 AM, Philippe Mathieu-Daudé wrote: >>> All commands switching from TRANSFER state to (sending)DATA >>> do the same: send stream of data on the DAT lines. Instead >>> of duplicating the same code many times, introduce 2 helpers: >>> - sd_cmd_to_sendingdata() on the I/O line setup the data to >>> be transferred, >>> - sd_generic_read_byte() on the DAT lines to fetch the data. >>> >>> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> >>> --- >>> hw/sd/sd.c | 39 +++++++++++++++++++++++++++++++++++++++ >>> 1 file changed, 39 insertions(+) >>> >>> diff --git a/hw/sd/sd.c b/hw/sd/sd.c >>> index d85b2906f4..1a8d06804d 100644 >>> --- a/hw/sd/sd.c >>> +++ b/hw/sd/sd.c >>> @@ -142,8 +142,10 @@ struct SDState { >>> */ >>> bool expecting_acmd; >>> uint32_t blk_written; >>> + >>> uint64_t data_start; >>> uint32_t data_offset; >>> + size_t data_size; >>> uint8_t data[512]; >>> uint8_t vendor_data[512]; >>> @@ -1083,6 +1085,29 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) >>> return sd_illegal; >>> } >>> +/* Configure fields for following sd_generic_read_byte() calls */ >>> +__attribute__((unused)) >>> +static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, >>> + uint64_t start, >>> + const void *data, size_t size) >>> +{ >>> + if (sd->state != sd_transfer_state) { >>> + sd_invalid_state_for_cmd(sd, req); >>> + } >>> + >>> + sd->state = sd_sendingdata_state; >>> + sd->data_start = start; >>> + sd->data_offset = 0; >>> + if (data) { >>> + assert(size); >> >> Shouldn't we check for buffer overrun ? sizeof(sd->data) > > OK if I squash this? > > -- >8 -- > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index d292e0adb5..f2d069c2da 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -1123,7 +1123,7 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, > sd->data_start = start; > sd->data_offset = 0; > if (data) { > - assert(size); > + assert(size > 0 && size <= sizeof(sd->data)); > memcpy(sd->data, data, size); > } > --- sure. Thanks, C.
On 1/7/24 18:54, Cédric Le Goater wrote: > On 7/1/24 6:40 PM, Philippe Mathieu-Daudé wrote: >> On 28/6/24 09:44, Cédric Le Goater wrote: >>> On 6/28/24 9:00 AM, Philippe Mathieu-Daudé wrote: >>>> All commands switching from TRANSFER state to (sending)DATA >>>> do the same: send stream of data on the DAT lines. Instead >>>> of duplicating the same code many times, introduce 2 helpers: >>>> - sd_cmd_to_sendingdata() on the I/O line setup the data to >>>> be transferred, >>>> - sd_generic_read_byte() on the DAT lines to fetch the data. >>>> >>>> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> >>>> --- >>>> hw/sd/sd.c | 39 +++++++++++++++++++++++++++++++++++++++ >>>> 1 file changed, 39 insertions(+) >>> Shouldn't we check for buffer overrun ? sizeof(sd->data) >> >> OK if I squash this? >> >> -- >8 -- >> diff --git a/hw/sd/sd.c b/hw/sd/sd.c >> index d292e0adb5..f2d069c2da 100644 >> --- a/hw/sd/sd.c >> +++ b/hw/sd/sd.c >> @@ -1123,7 +1123,7 @@ static sd_rsp_type_t >> sd_cmd_to_sendingdata(SDState *sd, SDRequest req, >> sd->data_start = start; >> sd->data_offset = 0; >> if (data) { >> - assert(size); >> + assert(size > 0 && size <= sizeof(sd->data)); >> memcpy(sd->data, data, size); >> } >> --- > > sure. Great. Can I get your R-b tag? The final patch is: -- >8 -- Author: Philippe Mathieu-Daudé <philmd@linaro.org> Date: Thu Jun 13 16:21:12 2024 +0200 hw/sd/sdcard: Introduce sd_cmd_to_sendingdata and sd_generic_read_byte All commands switching from TRANSFER state to (sending)DATA do the same: send stream of data on the DAT lines. Instead of duplicating the same code many times, introduce 2 helpers: - sd_cmd_to_sendingdata() on the I/O line setup the data to be transferred, - sd_generic_read_byte() on the DAT lines to fetch the data. Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 18bb2f9fd8..60235d3898 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -143,4 +143,6 @@ struct SDState { uint32_t blk_written; + uint64_t data_start; uint32_t data_offset; + size_t data_size; uint8_t data[512]; @@ -1080,2 +1082,25 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) +/* Configure fields for following sd_generic_read_byte() calls */ +__attribute__((unused)) +static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, + uint64_t start, + const void *data, size_t size) +{ + if (sd->state != sd_transfer_state) { + sd_invalid_state_for_cmd(sd, req); + } + + sd->state = sd_sendingdata_state; + sd->data_start = start; + sd->data_offset = 0; + if (data) { + assert(size > 0 && size <= sizeof(sd->data)); + memcpy(sd->data, data, size); + } + if (size) { + sd->data_size = size; + } + return sd_r1; +} + /* CMD0 */ @@ -1914,2 +1939,16 @@ send_response: +/* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */ +__attribute__((unused)) +static bool sd_generic_read_byte(SDState *sd, uint8_t *value) +{ + *value = sd->data[sd->data_offset]; + + if (++sd->data_offset >= sd->data_size) { + sd->state = sd_transfer_state; + return true; + } + + return false; +} + void sd_write_byte(SDState *sd, uint8_t value) ---
On 7/1/24 10:19 PM, Philippe Mathieu-Daudé wrote: > On 1/7/24 18:54, Cédric Le Goater wrote: >> On 7/1/24 6:40 PM, Philippe Mathieu-Daudé wrote: >>> On 28/6/24 09:44, Cédric Le Goater wrote: >>>> On 6/28/24 9:00 AM, Philippe Mathieu-Daudé wrote: >>>>> All commands switching from TRANSFER state to (sending)DATA >>>>> do the same: send stream of data on the DAT lines. Instead >>>>> of duplicating the same code many times, introduce 2 helpers: >>>>> - sd_cmd_to_sendingdata() on the I/O line setup the data to >>>>> be transferred, >>>>> - sd_generic_read_byte() on the DAT lines to fetch the data. >>>>> >>>>> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> >>>>> --- >>>>> hw/sd/sd.c | 39 +++++++++++++++++++++++++++++++++++++++ >>>>> 1 file changed, 39 insertions(+) > >>>> Shouldn't we check for buffer overrun ? sizeof(sd->data) >>> >>> OK if I squash this? >>> >>> -- >8 -- >>> diff --git a/hw/sd/sd.c b/hw/sd/sd.c >>> index d292e0adb5..f2d069c2da 100644 >>> --- a/hw/sd/sd.c >>> +++ b/hw/sd/sd.c >>> @@ -1123,7 +1123,7 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, >>> sd->data_start = start; >>> sd->data_offset = 0; >>> if (data) { >>> - assert(size); >>> + assert(size > 0 && size <= sizeof(sd->data)); >>> memcpy(sd->data, data, size); >>> } >>> --- >> >> sure. > > Great. Can I get your R-b tag? The final patch is: Reviewed-by: Cédric Le Goater <clg@redhat.com> Thanks, C. > > -- >8 -- > Author: Philippe Mathieu-Daudé <philmd@linaro.org> > Date: Thu Jun 13 16:21:12 2024 +0200 > > hw/sd/sdcard: Introduce sd_cmd_to_sendingdata and sd_generic_read_byte > > All commands switching from TRANSFER state to (sending)DATA > do the same: send stream of data on the DAT lines. Instead > of duplicating the same code many times, introduce 2 helpers: > - sd_cmd_to_sendingdata() on the I/O line setup the data to > be transferred, > - sd_generic_read_byte() on the DAT lines to fetch the data. > > Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index 18bb2f9fd8..60235d3898 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -143,4 +143,6 @@ struct SDState { > uint32_t blk_written; > + > uint64_t data_start; > uint32_t data_offset; > + size_t data_size; > uint8_t data[512]; > @@ -1080,2 +1082,25 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) > > +/* Configure fields for following sd_generic_read_byte() calls */ > +__attribute__((unused)) > +static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, > + uint64_t start, > + const void *data, size_t size) > +{ > + if (sd->state != sd_transfer_state) { > + sd_invalid_state_for_cmd(sd, req); > + } > + > + sd->state = sd_sendingdata_state; > + sd->data_start = start; > + sd->data_offset = 0; > + if (data) { > + assert(size > 0 && size <= sizeof(sd->data)); > + memcpy(sd->data, data, size); > + } > + if (size) { > + sd->data_size = size; > + } > + return sd_r1; > +} > + > /* CMD0 */ > @@ -1914,2 +1939,16 @@ send_response: > > +/* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */ > +__attribute__((unused)) > +static bool sd_generic_read_byte(SDState *sd, uint8_t *value) > +{ > + *value = sd->data[sd->data_offset]; > + > + if (++sd->data_offset >= sd->data_size) { > + sd->state = sd_transfer_state; > + return true; > + } > + > + return false; > +} > + > void sd_write_byte(SDState *sd, uint8_t value) > --- >
diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d85b2906f4..1a8d06804d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -142,8 +142,10 @@ struct SDState { */ bool expecting_acmd; uint32_t blk_written; + uint64_t data_start; uint32_t data_offset; + size_t data_size; uint8_t data[512]; uint8_t vendor_data[512]; @@ -1083,6 +1085,29 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) return sd_illegal; } +/* Configure fields for following sd_generic_read_byte() calls */ +__attribute__((unused)) +static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, + uint64_t start, + const void *data, size_t size) +{ + if (sd->state != sd_transfer_state) { + sd_invalid_state_for_cmd(sd, req); + } + + sd->state = sd_sendingdata_state; + sd->data_start = start; + sd->data_offset = 0; + if (data) { + assert(size); + memcpy(sd->data, data, size); + } + if (size) { + sd->data_size = size; + } + return sd_r1; +} + /* CMD0 */ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) { @@ -1920,6 +1945,20 @@ send_response: return rsplen; } +/* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */ +__attribute__((unused)) +static bool sd_generic_read_byte(SDState *sd, uint8_t *value) +{ + *value = sd->data[sd->data_offset]; + + if (++sd->data_offset >= sd->data_size) { + sd->state = sd_transfer_state; + return true; + } + + return false; +} + void sd_write_byte(SDState *sd, uint8_t value) { int i;
All commands switching from TRANSFER state to (sending)DATA do the same: send stream of data on the DAT lines. Instead of duplicating the same code many times, introduce 2 helpers: - sd_cmd_to_sendingdata() on the I/O line setup the data to be transferred, - sd_generic_read_byte() on the DAT lines to fetch the data. Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/sd/sd.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)