diff mbox series

[v42,18/98] hw/sd/sdcard: Introduce sd_cmd_to_sendingdata and sd_generic_read_byte

Message ID 20240628070216.92609-19-philmd@linaro.org (mailing list archive)
State New, archived
Headers show
Series hw/sd/sdcard: Add eMMC support | expand

Commit Message

Philippe Mathieu-Daudé June 28, 2024, 7 a.m. UTC
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(+)

Comments

Cédric Le Goater June 28, 2024, 7:44 a.m. UTC | #1
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;
Philippe Mathieu-Daudé July 1, 2024, 4:40 p.m. UTC | #2
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;
>
Cédric Le Goater July 1, 2024, 4:54 p.m. UTC | #3
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.
Philippe Mathieu-Daudé July 1, 2024, 8:19 p.m. UTC | #4
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)
---
Cédric Le Goater July 1, 2024, 8:50 p.m. UTC | #5
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 mbox series

Patch

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;