[PATCH v2 0/6] introduce EFI_RAM_DISK_PROTOCOL

This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk mount 41000000 $filesize or => ramdisk mount 41000000 $filesize
ramdisk command works without CONFIG_EFI_LOADER enabled.
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec63f0 (ramdisk_blk#0) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO
000000007eec6560 (ramdisk_blk#0:1) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO
000000007eec66d0 (ramdisk_blk#0:2) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree -s
ramdisk 0 [ + ] ramdisk |-- ramdisk0 blk 0 [ + ] ramdisk_blk | `-- ramdisk_blk#0 partition 0 [ + ] blk_partition | |-- ramdisk_blk#0:1 partition 1 [ + ] blk_partition | `-- ramdisk_blk#0:2
Debian can be successfully installed with this ramdisk on QEMU.
The created ramdisk can be accessed by the existing commands such as 'fatls': => fatls ramdisk 0:2
[TODO] - add ramdisk command documentation - add ramdisk command dm test
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
[Changelog] v1 -> v2 - implement ramdisk uclass and driver, then EFI_RAM_DISK_PROTOCOL is implemented based on the ramdisk uclass
Masahisa Kojima (6): efi_loader: add RAM disk device path ramdisk: add ramdisk uclass and driver cmd: ramdisk: add ramdisk control command efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/efidebug.c | 118 ++++++ cmd/ramdisk.c | 92 ++++ disk/part.c | 3 + drivers/block/Kconfig | 7 +- drivers/block/Makefile | 2 + drivers/block/blk-uclass.c | 1 + drivers/block/blk_ramdisk.c | 187 +++++++++ drivers/block/ramdisk-uclass.c | 14 + include/dm/uclass-id.h | 1 + include/efi_api.h | 32 ++ include/efi_loader.h | 4 + include/ramdisk.h | 32 ++ lib/efi_loader/Kconfig | 7 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path.c | 25 ++ lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 142 +++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 23 files changed, 1211 insertions(+), 1 deletion(-) create mode 100644 cmd/ramdisk.c create mode 100644 drivers/block/blk_ramdisk.c create mode 100644 drivers/block/ramdisk-uclass.c create mode 100644 include/ramdisk.h create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9

This is a preparation to add the EFI_RAM_DISK_PROTOCOL. This commit adds the RAM disk device path structure and text conversion to Device Path to Text Protocol.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- No update since v1
include/efi_api.h | 19 +++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 14 ++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/include/efi_api.h b/include/efi_api.h index 55a4c989fc..4ee4a1b5e9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -682,6 +682,7 @@ struct efi_device_path_uri { # define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02 # define DEVICE_PATH_SUB_TYPE_VENDOR_PATH 0x03 # define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04 +# define DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH 0x09
struct efi_device_path_hard_drive_path { struct efi_device_path dp; @@ -705,6 +706,24 @@ struct efi_device_path_file_path { u16 str[]; } __packed;
+/* This GUID defines a RAM Disk supporting a raw disk format in volatile memory */ +#define EFI_VIRTUAL_DISK_GUID \ + EFI_GUID(0x77ab535a, 0x45fc, 0x624b, \ + 0x55, 0x60, 0xf7, 0xb2, 0x81, 0xd1, 0xf9, 0x6e) + +/* This GUID defines a RAM Disk supporting an ISO image in volatile memory */ +#define EFI_VIRTUAL_CD_GUID \ + EFI_GUID(0x3d5abd30, 0x4175, 0x87ce, \ + 0x6d, 0x64, 0xd2, 0xad, 0xe5, 0x23, 0xc4, 0xbb) + +struct efi_device_path_ram_disk_path { + struct efi_device_path dp; + u64 starting_address; + u64 ending_address; + efi_guid_t disk_type_guid; + u16 disk_instance; +} __packed; + #define EFI_BLOCK_IO_PROTOCOL_GUID \ EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 8c76d8be60..4395e79f33 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -324,6 +324,20 @@ static char *dp_media(char *s, struct efi_device_path *dp) free(buffer); break; } + case DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH: { + struct efi_device_path_ram_disk_path *rddp = + (struct efi_device_path_ram_disk_path *)dp; + u64 start; + u64 end; + + /* Copy from packed structure to aligned memory */ + memcpy(&start, &rddp->starting_address, sizeof(start)); + memcpy(&end, &rddp->ending_address, sizeof(end)); + + s += sprintf(s, "RamDisk(0x%llx,%llx,%pUl,0x%x)", start, end, + &rddp->disk_type_guid, rddp->disk_instance); + break; + } default: s = dp_unknown(s, dp); break;

On 14.07.23 07:44, Masahisa Kojima wrote:
This is a preparation to add the EFI_RAM_DISK_PROTOCOL. This commit adds the RAM disk device path structure and text conversion to Device Path to Text Protocol.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
No update since v1
include/efi_api.h | 19 +++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 14 ++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/include/efi_api.h b/include/efi_api.h index 55a4c989fc..4ee4a1b5e9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -682,6 +682,7 @@ struct efi_device_path_uri { # define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02 # define DEVICE_PATH_SUB_TYPE_VENDOR_PATH 0x03 # define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04 +# define DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH 0x09
struct efi_device_path_hard_drive_path { struct efi_device_path dp; @@ -705,6 +706,24 @@ struct efi_device_path_file_path { u16 str[]; } __packed;
+/* This GUID defines a RAM Disk supporting a raw disk format in volatile memory */ +#define EFI_VIRTUAL_DISK_GUID \
- EFI_GUID(0x77ab535a, 0x45fc, 0x624b, \
- 0x55, 0x60, 0xf7, 0xb2, 0x81, 0xd1, 0xf9, 0x6e)
+/* This GUID defines a RAM Disk supporting an ISO image in volatile memory */ +#define EFI_VIRTUAL_CD_GUID \
- EFI_GUID(0x3d5abd30, 0x4175, 0x87ce, \
0x6d, 0x64, 0xd2, 0xad, 0xe5, 0x23, 0xc4, 0xbb)
+struct efi_device_path_ram_disk_path {
- struct efi_device_path dp;
- u64 starting_address;
- u64 ending_address;
- efi_guid_t disk_type_guid;
- u16 disk_instance;
+} __packed;
- #define EFI_BLOCK_IO_PROTOCOL_GUID \ EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 8c76d8be60..4395e79f33 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -324,6 +324,20 @@ static char *dp_media(char *s, struct efi_device_path *dp) free(buffer); break; }
- case DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH: {
struct efi_device_path_ram_disk_path *rddp =
(struct efi_device_path_ram_disk_path *)dp;
u64 start;
u64 end;
/* Copy from packed structure to aligned memory */
memcpy(&start, &rddp->starting_address, sizeof(start));
memcpy(&end, &rddp->ending_address, sizeof(end));
s += sprintf(s, "RamDisk(0x%llx,%llx,%pUl,0x%x)", start, end,
&rddp->disk_type_guid, rddp->disk_instance);
If there is no alignment guarantee for starting_address, then the same is true for disk_instance which may spread over two u64 blocks.
In case of DEVICE_PATH_SUB_TYPE_MEMORY we don't use memcpy() to align u64.
I don't think we call device_path_to_text before allow_unaligned().
There is a family of functions like get_unaligned_le64() if we should ever need to a align a value. Or we could copy the whole device path node.
Best regards
Heinrich
break;
- } default: s = dp_unknown(s, dp); break;

Hi Heinrich,
On Fri, 14 Jul 2023 at 22:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 14.07.23 07:44, Masahisa Kojima wrote:
This is a preparation to add the EFI_RAM_DISK_PROTOCOL. This commit adds the RAM disk device path structure and text conversion to Device Path to Text Protocol.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
No update since v1
include/efi_api.h | 19 +++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 14 ++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/include/efi_api.h b/include/efi_api.h index 55a4c989fc..4ee4a1b5e9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -682,6 +682,7 @@ struct efi_device_path_uri { # define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02 # define DEVICE_PATH_SUB_TYPE_VENDOR_PATH 0x03 # define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04 +# define DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH 0x09
struct efi_device_path_hard_drive_path { struct efi_device_path dp; @@ -705,6 +706,24 @@ struct efi_device_path_file_path { u16 str[]; } __packed;
+/* This GUID defines a RAM Disk supporting a raw disk format in volatile memory */ +#define EFI_VIRTUAL_DISK_GUID \
EFI_GUID(0x77ab535a, 0x45fc, 0x624b, \
0x55, 0x60, 0xf7, 0xb2, 0x81, 0xd1, 0xf9, 0x6e)
+/* This GUID defines a RAM Disk supporting an ISO image in volatile memory */ +#define EFI_VIRTUAL_CD_GUID \
EFI_GUID(0x3d5abd30, 0x4175, 0x87ce, \
0x6d, 0x64, 0xd2, 0xad, 0xe5, 0x23, 0xc4, 0xbb)
+struct efi_device_path_ram_disk_path {
struct efi_device_path dp;
u64 starting_address;
u64 ending_address;
efi_guid_t disk_type_guid;
u16 disk_instance;
+} __packed;
- #define EFI_BLOCK_IO_PROTOCOL_GUID \ EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 8c76d8be60..4395e79f33 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -324,6 +324,20 @@ static char *dp_media(char *s, struct efi_device_path *dp) free(buffer); break; }
case DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH: {
struct efi_device_path_ram_disk_path *rddp =
(struct efi_device_path_ram_disk_path *)dp;
u64 start;
u64 end;
/* Copy from packed structure to aligned memory */
memcpy(&start, &rddp->starting_address, sizeof(start));
memcpy(&end, &rddp->ending_address, sizeof(end));
s += sprintf(s, "RamDisk(0x%llx,%llx,%pUl,0x%x)", start, end,
&rddp->disk_type_guid, rddp->disk_instance);
If there is no alignment guarantee for starting_address, then the same is true for disk_instance which may spread over two u64 blocks.
disk_instance is a u16 field, so it is aligned.
In case of DEVICE_PATH_SUB_TYPE_MEMORY we don't use memcpy() to align u64.
I don't think we call device_path_to_text before allow_unaligned().
There is a family of functions like get_unaligned_le64() if we should ever need to a align a value. Or we could copy the whole device path node.
OK, I will use get_unaligned_le64().
Thanks, Masahisa Kojima
Best regards
Heinrich
break;
} default: s = dp_unknown(s, dp); break;

Am 18. Juli 2023 03:31:30 MESZ schrieb Masahisa Kojima masahisa.kojima@linaro.org:
Hi Heinrich,
On Fri, 14 Jul 2023 at 22:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 14.07.23 07:44, Masahisa Kojima wrote:
This is a preparation to add the EFI_RAM_DISK_PROTOCOL. This commit adds the RAM disk device path structure and text conversion to Device Path to Text Protocol.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
No update since v1
include/efi_api.h | 19 +++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 14 ++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/include/efi_api.h b/include/efi_api.h index 55a4c989fc..4ee4a1b5e9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -682,6 +682,7 @@ struct efi_device_path_uri { # define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02 # define DEVICE_PATH_SUB_TYPE_VENDOR_PATH 0x03 # define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04 +# define DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH 0x09
struct efi_device_path_hard_drive_path { struct efi_device_path dp; @@ -705,6 +706,24 @@ struct efi_device_path_file_path { u16 str[]; } __packed;
+/* This GUID defines a RAM Disk supporting a raw disk format in volatile memory */ +#define EFI_VIRTUAL_DISK_GUID \
EFI_GUID(0x77ab535a, 0x45fc, 0x624b, \
0x55, 0x60, 0xf7, 0xb2, 0x81, 0xd1, 0xf9, 0x6e)
+/* This GUID defines a RAM Disk supporting an ISO image in volatile memory */ +#define EFI_VIRTUAL_CD_GUID \
EFI_GUID(0x3d5abd30, 0x4175, 0x87ce, \
0x6d, 0x64, 0xd2, 0xad, 0xe5, 0x23, 0xc4, 0xbb)
+struct efi_device_path_ram_disk_path {
struct efi_device_path dp;
u64 starting_address;
u64 ending_address;
efi_guid_t disk_type_guid;
u16 disk_instance;
+} __packed;
- #define EFI_BLOCK_IO_PROTOCOL_GUID \ EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 8c76d8be60..4395e79f33 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -324,6 +324,20 @@ static char *dp_media(char *s, struct efi_device_path *dp) free(buffer); break; }
case DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH: {
struct efi_device_path_ram_disk_path *rddp =
(struct efi_device_path_ram_disk_path *)dp;
u64 start;
u64 end;
/* Copy from packed structure to aligned memory */
memcpy(&start, &rddp->starting_address, sizeof(start));
memcpy(&end, &rddp->ending_address, sizeof(end));
s += sprintf(s, "RamDisk(0x%llx,%llx,%pUl,0x%x)", start, end,
&rddp->disk_type_guid, rddp->disk_instance);
If there is no alignment guarantee for starting_address, then the same is true for disk_instance which may spread over two u64 blocks.
disk_instance is a u16 field, so it is aligned.
A preceding node, e.g. VenHw(), may have an uneven length?
In case of DEVICE_PATH_SUB_TYPE_MEMORY we don't use memcpy() to align u64.
I don't think we call device_path_to_text before allow_unaligned().
There is a family of functions like get_unaligned_le64() if we should ever need to a align a value. Or we could copy the whole device path node.
OK, I will use get_unaligned_le64().
Why do you think this is necessary?
Best regards
Heinrich
Thanks, Masahisa Kojima
Best regards
Heinrich
break;
} default: s = dp_unknown(s, dp); break;

On Tue, 18 Jul 2023 at 14:57, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
Am 18. Juli 2023 03:31:30 MESZ schrieb Masahisa Kojima masahisa.kojima@linaro.org:
Hi Heinrich,
On Fri, 14 Jul 2023 at 22:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 14.07.23 07:44, Masahisa Kojima wrote:
This is a preparation to add the EFI_RAM_DISK_PROTOCOL. This commit adds the RAM disk device path structure and text conversion to Device Path to Text Protocol.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
No update since v1
include/efi_api.h | 19 +++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 14 ++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/include/efi_api.h b/include/efi_api.h index 55a4c989fc..4ee4a1b5e9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -682,6 +682,7 @@ struct efi_device_path_uri { # define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02 # define DEVICE_PATH_SUB_TYPE_VENDOR_PATH 0x03 # define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04 +# define DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH 0x09
struct efi_device_path_hard_drive_path { struct efi_device_path dp; @@ -705,6 +706,24 @@ struct efi_device_path_file_path { u16 str[]; } __packed;
+/* This GUID defines a RAM Disk supporting a raw disk format in volatile memory */ +#define EFI_VIRTUAL_DISK_GUID \
EFI_GUID(0x77ab535a, 0x45fc, 0x624b, \
0x55, 0x60, 0xf7, 0xb2, 0x81, 0xd1, 0xf9, 0x6e)
+/* This GUID defines a RAM Disk supporting an ISO image in volatile memory */ +#define EFI_VIRTUAL_CD_GUID \
EFI_GUID(0x3d5abd30, 0x4175, 0x87ce, \
0x6d, 0x64, 0xd2, 0xad, 0xe5, 0x23, 0xc4, 0xbb)
+struct efi_device_path_ram_disk_path {
struct efi_device_path dp;
u64 starting_address;
u64 ending_address;
efi_guid_t disk_type_guid;
u16 disk_instance;
+} __packed;
- #define EFI_BLOCK_IO_PROTOCOL_GUID \ EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 8c76d8be60..4395e79f33 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -324,6 +324,20 @@ static char *dp_media(char *s, struct efi_device_path *dp) free(buffer); break; }
case DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH: {
struct efi_device_path_ram_disk_path *rddp =
(struct efi_device_path_ram_disk_path *)dp;
u64 start;
u64 end;
/* Copy from packed structure to aligned memory */
memcpy(&start, &rddp->starting_address, sizeof(start));
memcpy(&end, &rddp->ending_address, sizeof(end));
s += sprintf(s, "RamDisk(0x%llx,%llx,%pUl,0x%x)", start, end,
&rddp->disk_type_guid, rddp->disk_instance);
If there is no alignment guarantee for starting_address, then the same is true for disk_instance which may spread over two u64 blocks.
disk_instance is a u16 field, so it is aligned.
A preceding node, e.g. VenHw(), may have an uneven length?
In case of DEVICE_PATH_SUB_TYPE_MEMORY we don't use memcpy() to align u64.
I don't think we call device_path_to_text before allow_unaligned().
There is a family of functions like get_unaligned_le64() if we should ever need to a align a value. Or we could copy the whole device path node.
OK, I will use get_unaligned_le64().
Why do you think this is necessary?
Sorry, I misunderstood your comment. allow_unaligned() is called in efi_init_early(), device_path_to_text will not be called before allow_unaligned(). So we don't need to care about alignment in device_path_to_text like DEVICE_PATH_SUB_TYPE_MEMORY is doing.
Thanks, Masahisa Kojima
Best regards
Heinrich
Thanks, Masahisa Kojima
Best regards
Heinrich
break;
} default: s = dp_unknown(s, dp); break;

This introcudes the ramdisk uclass and driver.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- Newly introcuded in v2
disk/part.c | 3 + drivers/block/Kconfig | 7 +- drivers/block/Makefile | 2 + drivers/block/blk-uclass.c | 1 + drivers/block/blk_ramdisk.c | 187 +++++++++++++++++++++++++++++++ drivers/block/ramdisk-uclass.c | 14 +++ include/dm/uclass-id.h | 1 + include/ramdisk.h | 32 ++++++ lib/efi_loader/efi_device_path.c | 25 +++++ 9 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 drivers/block/blk_ramdisk.c create mode 100644 drivers/block/ramdisk-uclass.c create mode 100644 include/ramdisk.h
diff --git a/disk/part.c b/disk/part.c index 35300df590..d0cee3cc03 100644 --- a/disk/part.c +++ b/disk/part.c @@ -152,6 +152,9 @@ void dev_print(struct blk_desc *dev_desc) case UCLASS_EFI_MEDIA: printf("EFI media Block Device %d\n", dev_desc->devnum); break; + case UCLASS_RAM_DISK: + printf("RAM Disk Block Device %d\n", dev_desc->devnum); + break; case UCLASS_INVALID: puts("device type unknown\n"); return; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 5a1aeb3d2b..ab56ef3406 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -2,7 +2,7 @@ config BLK bool # "Support block devices" depends on DM default y if MMC || USB || SCSI || NVME || IDE || AHCI || SATA - default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK + default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK || RAM_DISK help Enable support for block devices, such as SCSI, MMC and USB flash sticks. These provide a block-level interface which permits @@ -255,3 +255,8 @@ config SYS_64BIT_LBA help Make the block subsystem use 64bit sector addresses, rather than the default of 32bit. + +config RAM_DISK + bool "Enable RAM disk" + help + This option enables to mount the RAM disk. diff --git a/drivers/block/Makefile b/drivers/block/Makefile index a161d145fd..e867c7a126 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -19,3 +19,5 @@ obj-$(CONFIG_BLKMAP) += blkmap.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o +obj-$(CONFIG_RAM_DISK) += blk_ramdisk.o +obj-$(CONFIG_RAM_DISK) += ramdisk-uclass.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 614b975e25..ea411fe674 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -34,6 +34,7 @@ static struct { { UCLASS_VIRTIO, "virtio" }, { UCLASS_PVBLOCK, "pvblock" }, { UCLASS_BLKMAP, "blkmap" }, + { UCLASS_RAM_DISK, "ramdisk" }, };
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname) diff --git a/drivers/block/blk_ramdisk.c b/drivers/block/blk_ramdisk.c new file mode 100644 index 0000000000..8016837a80 --- /dev/null +++ b/drivers/block/blk_ramdisk.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * RAM Disk block device driver + * + * Copyright (c) 2023, Linaro Limited + */ + +#include <blk.h> +#include <common.h> +#include <dm.h> +#include <log.h> +#include <part.h> +#include <ramdisk.h> +#include <dm/device-internal.h> +#include <dm/root.h> + +#if (IS_ENABLED(CONFIG_EFI_LOADER)) +#include <efi_loader.h> +#endif + +#define MEM_BLOCK_SIZE_SHIFT 9 /* 512 bytes */ + +/** + * ramdisk_read() - read from block device + * + * @dev: device + * @blknr: first block to be read + * @blkcnt: number of blocks to read + * @buffer: output buffer + * Return: number of blocks transferred + */ +static ulong ramdisk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + void *buffer) +{ + u8 *start; + struct ramdisk_blk_plat *plat = dev_get_plat(dev); + + log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, + (ulong)blkcnt); + + if (!buffer) + return 0; + + if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT)) + return 0; + + start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT); + memmove(buffer, start, blkcnt << MEM_BLOCK_SIZE_SHIFT); + + return blkcnt; +} + +/** + * ramdisk_write() - write to block device + * + * @dev: device + * @blknr: first block to be write + * @blkcnt: number of blocks to write + * @buffer: input buffer + * Return: number of blocks transferred + */ +static ulong ramdisk_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + const void *buffer) +{ + u8 *start; + struct ramdisk_blk_plat *plat = dev_get_plat(dev); + + log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, + (ulong)blkcnt); + + if (!buffer) + return 0; + + if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT)) + return 0; + + start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT); + memmove(start, buffer, blkcnt << MEM_BLOCK_SIZE_SHIFT); + + return blkcnt; +} + +static const struct blk_ops ramdisk_blk_ops = { + .read = ramdisk_read, + .write = ramdisk_write, +}; + +U_BOOT_DRIVER(ramdisk_blk) = { + .name = "ramdisk_blk", + .id = UCLASS_BLK, + .ops = &ramdisk_blk_ops, + .plat_auto = sizeof(struct ramdisk_blk_plat), +}; + +/* + * ramdisk_mount - mount ramdisk + * + * @start_address: The base address of registered RAM disk + * @size: The size of registered RAM disk + * @guid: The type of registered RAM disk + * Return: Pointer to the udevice strucure, return NULL if failed + */ +struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid) +{ + int ret; + char name[20]; + struct udevice *parent, *bdev; + static struct ramdisk_blk_plat *plat; + + if (!start_address || !size) + return NULL; + + ret = device_bind(dm_root(), DM_DRIVER_GET(ramdisk), "ramdisk", NULL, + ofnode_null(), &parent); + if (ret) { + log_err("bind ramdisk error\n"); + return NULL; + } + snprintf(name, sizeof(name), "ramdisk%d", dev_seq(parent)); + device_set_name(parent, name); + + ret = blk_create_device(parent, "ramdisk_blk", "ramdisk_blk", + UCLASS_RAM_DISK, dev_seq(parent), + 1 << MEM_BLOCK_SIZE_SHIFT, + (size >> MEM_BLOCK_SIZE_SHIFT) - 1, &bdev); + if (ret) { + log_err("ramdisk create block device failed\n"); + goto err; + } + snprintf(name, sizeof(name), "ramdisk_blk#%d", dev_seq(parent)); + device_set_name(bdev, name); + + plat = dev_get_plat(bdev); + plat->start = (u8 *)start_address; + plat->size = size; +#if (IS_ENABLED(CONFIG_EFI_LOADER)) + if (guid) + guidcpy(&plat->disk_type_guid, guid); +#endif + ret = blk_probe_or_unbind(bdev); + if (ret) { + log_err("ramdisk probe error\n"); + goto err; + } + + return bdev; + +err: + if (parent) { + ret = device_remove(parent, DM_REMOVE_NORMAL); + if (ret) + return NULL; + + ret = device_unbind(parent); + } + + return NULL; +} + +/* + * ramdisk_unmount - unmount ramdisk + * + * @dev: The device to be unmounted + * Return: 0 if success, negative value if error + */ +int ramdisk_unmount(struct udevice *dev) +{ + int ret; + struct udevice *parent; + + if (!dev) + return -EINVAL; + + parent = dev->parent; + ret = device_remove(parent, DM_REMOVE_NORMAL); + if (ret) + return ret; + + ret = device_unbind(parent); + + return ret; +} + +U_BOOT_DRIVER(ramdisk) = { + .name = "ramdisk", + .id = UCLASS_RAM_DISK, +}; diff --git a/drivers/block/ramdisk-uclass.c b/drivers/block/ramdisk-uclass.c new file mode 100644 index 0000000000..f1bf68f635 --- /dev/null +++ b/drivers/block/ramdisk-uclass.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * RAM Disk block device driver + * + * Copyright (c) 2023, Linaro Limited + */ + +#include <common.h> +#include <dm.h> + +UCLASS_DRIVER(ramdisk) = { + .name = "ramdisk", + .id = UCLASS_RAM_DISK, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 307ad6931c..42b4907b1f 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -109,6 +109,7 @@ enum uclass_id { UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_QFW, /* QEMU firmware config device */ UCLASS_RAM, /* RAM controller */ + UCLASS_RAM_DISK, /* RAM disk device */ UCLASS_REBOOT_MODE, /* Reboot mode */ UCLASS_REGULATOR, /* Regulator device */ UCLASS_REMOTEPROC, /* Remote Processor device */ diff --git a/include/ramdisk.h b/include/ramdisk.h new file mode 100644 index 0000000000..71383be5b8 --- /dev/null +++ b/include/ramdisk.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * ramdisk support + * + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef _RAMDISK_H +#define _RAMDISK_H + +#ifdef CONFIG_EFI_LOADER +#include <efi.h> +#endif + +/** + * struct ramdisk_blk_plat - attributes of a block device + * + * @handle: handle of the controller on which this driver is installed + * @io: block io protocol proxied by this driver + */ +struct ramdisk_blk_plat { + u8 *start; + u64 size; +#if (IS_ENABLED(CONFIG_EFI_LOADER)) + efi_guid_t disk_type_guid; +#endif +}; + +struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid); +int ramdisk_unmount(struct udevice *dev); + +#endif diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 04ebb449ca..1f16bda6ac 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -17,6 +17,7 @@ #include <nvme.h> #include <efi_loader.h> #include <part.h> +#include <ramdisk.h> #include <uuid.h> #include <asm-generic/unaligned.h> #include <linux/compat.h> /* U16_MAX */ @@ -568,6 +569,11 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) */ return dp_size(dev->parent) + sizeof(struct efi_device_path_vendor) + 1; +#endif +#ifdef CONFIG_RAM_DISK + case UCLASS_RAM_DISK: + return dp_size(dev->parent) + + sizeof(struct efi_device_path_ram_disk_path) + 1; #endif default: return dp_size(dev->parent); @@ -766,6 +772,25 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) dp->controller_number = desc->lun; return &dp[1]; } +#endif +#if defined(CONFIG_RAM_DISK) + case UCLASS_RAM_DISK: { + struct ramdisk_blk_plat *plat = dev_get_plat(dev); + struct efi_device_path_ram_disk_path *dp = + dp_fill(buf, dev->parent); + + dp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; + dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH; + dp->dp.length = + sizeof(struct efi_device_path_ram_disk_path); + put_unaligned_le64((u64)plat->start, + &dp->starting_address); + put_unaligned_le64((u64)(plat->start + plat->size - 1), + &dp->ending_address); + guidcpy(&dp->disk_type_guid, &plat->disk_type_guid); + dp->disk_instance = 0; + return &dp[1]; + } #endif default: debug("%s(%u) %s: unhandled parent class: %s (%u)\n",

On 14.07.23 07:44, Masahisa Kojima wrote:
This introcudes the ramdisk uclass and driver.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
Newly introcuded in v2
disk/part.c | 3 + drivers/block/Kconfig | 7 +- drivers/block/Makefile | 2 + drivers/block/blk-uclass.c | 1 + drivers/block/blk_ramdisk.c | 187 +++++++++++++++++++++++++++++++ drivers/block/ramdisk-uclass.c | 14 +++ include/dm/uclass-id.h | 1 + include/ramdisk.h | 32 ++++++ lib/efi_loader/efi_device_path.c | 25 +++++ 9 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 drivers/block/blk_ramdisk.c create mode 100644 drivers/block/ramdisk-uclass.c create mode 100644 include/ramdisk.h
diff --git a/disk/part.c b/disk/part.c index 35300df590..d0cee3cc03 100644 --- a/disk/part.c +++ b/disk/part.c @@ -152,6 +152,9 @@ void dev_print(struct blk_desc *dev_desc) case UCLASS_EFI_MEDIA: printf("EFI media Block Device %d\n", dev_desc->devnum); break;
- case UCLASS_RAM_DISK:
printf("RAM Disk Block Device %d\n", dev_desc->devnum);
case UCLASS_INVALID: puts("device type unknown\n"); return;break;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 5a1aeb3d2b..ab56ef3406 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -2,7 +2,7 @@ config BLK bool # "Support block devices" depends on DM default y if MMC || USB || SCSI || NVME || IDE || AHCI || SATA
- default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK
- default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK || RAM_DISK help Enable support for block devices, such as SCSI, MMC and USB flash sticks. These provide a block-level interface which permits
@@ -255,3 +255,8 @@ config SYS_64BIT_LBA help Make the block subsystem use 64bit sector addresses, rather than the default of 32bit.
+config RAM_DISK
- bool "Enable RAM disk"
- help
This option enables to mount the RAM disk.
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index a161d145fd..e867c7a126 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -19,3 +19,5 @@ obj-$(CONFIG_BLKMAP) += blkmap.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o +obj-$(CONFIG_RAM_DISK) += blk_ramdisk.o +obj-$(CONFIG_RAM_DISK) += ramdisk-uclass.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 614b975e25..ea411fe674 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -34,6 +34,7 @@ static struct { { UCLASS_VIRTIO, "virtio" }, { UCLASS_PVBLOCK, "pvblock" }, { UCLASS_BLKMAP, "blkmap" },
{ UCLASS_RAM_DISK, "ramdisk" }, };
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
diff --git a/drivers/block/blk_ramdisk.c b/drivers/block/blk_ramdisk.c new file mode 100644 index 0000000000..8016837a80 --- /dev/null +++ b/drivers/block/blk_ramdisk.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- RAM Disk block device driver
- Copyright (c) 2023, Linaro Limited
- */
+#include <blk.h> +#include <common.h> +#include <dm.h> +#include <log.h> +#include <part.h> +#include <ramdisk.h> +#include <dm/device-internal.h> +#include <dm/root.h>
+#if (IS_ENABLED(CONFIG_EFI_LOADER)) +#include <efi_loader.h> +#endif
+#define MEM_BLOCK_SIZE_SHIFT 9 /* 512 bytes */
+/**
- ramdisk_read() - read from block device
- @dev: device
- @blknr: first block to be read
- @blkcnt: number of blocks to read
- @buffer: output buffer
- Return: number of blocks transferred
- */
+static ulong ramdisk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
+{
- u8 *start;
- struct ramdisk_blk_plat *plat = dev_get_plat(dev);
- log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
- if (!buffer)
return 0;
- if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT))
return 0;
- start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT);
- memmove(buffer, start, blkcnt << MEM_BLOCK_SIZE_SHIFT);
- return blkcnt;
+}
+/**
- ramdisk_write() - write to block device
- @dev: device
- @blknr: first block to be write
- @blkcnt: number of blocks to write
- @buffer: input buffer
- Return: number of blocks transferred
- */
+static ulong ramdisk_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
const void *buffer)
+{
- u8 *start;
- struct ramdisk_blk_plat *plat = dev_get_plat(dev);
- log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
- if (!buffer)
return 0;
- if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT))
return 0;
- start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT);
- memmove(start, buffer, blkcnt << MEM_BLOCK_SIZE_SHIFT);
- return blkcnt;
+}
+static const struct blk_ops ramdisk_blk_ops = {
- .read = ramdisk_read,
- .write = ramdisk_write,
+};
+U_BOOT_DRIVER(ramdisk_blk) = {
- .name = "ramdisk_blk",
- .id = UCLASS_BLK,
- .ops = &ramdisk_blk_ops,
- .plat_auto = sizeof(struct ramdisk_blk_plat),
+};
+/*
- ramdisk_mount - mount ramdisk
- @start_address: The base address of registered RAM disk
- @size: The size of registered RAM disk
- @guid: The type of registered RAM disk
- Return: Pointer to the udevice strucure, return NULL if failed
- */
+struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid) +{
- int ret;
- char name[20];
- struct udevice *parent, *bdev;
- static struct ramdisk_blk_plat *plat;
- if (!start_address || !size)
return NULL;
- ret = device_bind(dm_root(), DM_DRIVER_GET(ramdisk), "ramdisk", NULL,
ofnode_null(), &parent);
- if (ret) {
log_err("bind ramdisk error\n");
return NULL;
- }
- snprintf(name, sizeof(name), "ramdisk%d", dev_seq(parent));
- device_set_name(parent, name);
- ret = blk_create_device(parent, "ramdisk_blk", "ramdisk_blk",
UCLASS_RAM_DISK, dev_seq(parent),
1 << MEM_BLOCK_SIZE_SHIFT,
(size >> MEM_BLOCK_SIZE_SHIFT) - 1, &bdev);
- if (ret) {
log_err("ramdisk create block device failed\n");
goto err;
- }
- snprintf(name, sizeof(name), "ramdisk_blk#%d", dev_seq(parent));
- device_set_name(bdev, name);
- plat = dev_get_plat(bdev);
- plat->start = (u8 *)start_address;
- plat->size = size;
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
- if (guid)
guidcpy(&plat->disk_type_guid, guid);
+#endif
- ret = blk_probe_or_unbind(bdev);
- if (ret) {
log_err("ramdisk probe error\n");
goto err;
- }
- return bdev;
+err:
- if (parent) {
ret = device_remove(parent, DM_REMOVE_NORMAL);
if (ret)
return NULL;
ret = device_unbind(parent);
- }
- return NULL;
+}
+/*
- ramdisk_unmount - unmount ramdisk
- @dev: The device to be unmounted
- Return: 0 if success, negative value if error
- */
+int ramdisk_unmount(struct udevice *dev) +{
- int ret;
- struct udevice *parent;
- if (!dev)
return -EINVAL;
- parent = dev->parent;
- ret = device_remove(parent, DM_REMOVE_NORMAL);
- if (ret)
return ret;
- ret = device_unbind(parent);
- return ret;
+}
+U_BOOT_DRIVER(ramdisk) = {
- .name = "ramdisk",
- .id = UCLASS_RAM_DISK,
+}; diff --git a/drivers/block/ramdisk-uclass.c b/drivers/block/ramdisk-uclass.c new file mode 100644 index 0000000000..f1bf68f635 --- /dev/null +++ b/drivers/block/ramdisk-uclass.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- RAM Disk block device driver
- Copyright (c) 2023, Linaro Limited
- */
+#include <common.h> +#include <dm.h>
+UCLASS_DRIVER(ramdisk) = {
- .name = "ramdisk",
- .id = UCLASS_RAM_DISK,
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 307ad6931c..42b4907b1f 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -109,6 +109,7 @@ enum uclass_id { UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_QFW, /* QEMU firmware config device */ UCLASS_RAM, /* RAM controller */
- UCLASS_RAM_DISK, /* RAM disk device */ UCLASS_REBOOT_MODE, /* Reboot mode */ UCLASS_REGULATOR, /* Regulator device */ UCLASS_REMOTEPROC, /* Remote Processor device */
diff --git a/include/ramdisk.h b/include/ramdisk.h new file mode 100644 index 0000000000..71383be5b8 --- /dev/null +++ b/include/ramdisk.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- ramdisk support
- Copyright (c) 2023, Linaro Limited
- */
+#ifndef _RAMDISK_H +#define _RAMDISK_H
+#ifdef CONFIG_EFI_LOADER +#include <efi.h> +#endif
+/**
- struct ramdisk_blk_plat - attributes of a block device
- @handle: handle of the controller on which this driver is installed
- @io: block io protocol proxied by this driver
- */
+struct ramdisk_blk_plat {
- u8 *start;
- u64 size;
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
- efi_guid_t disk_type_guid;
+#endif +};
+struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid); +int ramdisk_unmount(struct udevice *dev);
+#endif diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 04ebb449ca..1f16bda6ac 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -17,6 +17,7 @@ #include <nvme.h> #include <efi_loader.h> #include <part.h> +#include <ramdisk.h> #include <uuid.h> #include <asm-generic/unaligned.h> #include <linux/compat.h> /* U16_MAX */ @@ -568,6 +569,11 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) */ return dp_size(dev->parent) + sizeof(struct efi_device_path_vendor) + 1; +#endif +#ifdef CONFIG_RAM_DISK
case UCLASS_RAM_DISK:
What is the difference to UCLASS_BLKMAP?
[PATCH v2 0/9] blk: blkmap: Composable virtual block devices https://lore.kernel.org/u-boot/20230216153355.448302-1-tobias@waldekranz.com...
Best regards
Heinrich
return dp_size(dev->parent)
#endif default: return dp_size(dev->parent);+ sizeof(struct efi_device_path_ram_disk_path) + 1;
@@ -766,6 +772,25 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) dp->controller_number = desc->lun; return &dp[1]; } +#endif +#if defined(CONFIG_RAM_DISK)
case UCLASS_RAM_DISK: {
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
struct efi_device_path_ram_disk_path *dp =
dp_fill(buf, dev->parent);
dp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH;
dp->dp.length =
sizeof(struct efi_device_path_ram_disk_path);
put_unaligned_le64((u64)plat->start,
&dp->starting_address);
put_unaligned_le64((u64)(plat->start + plat->size - 1),
&dp->ending_address);
guidcpy(&dp->disk_type_guid, &plat->disk_type_guid);
dp->disk_instance = 0;
return &dp[1];
#endif default: debug("%s(%u) %s: unhandled parent class: %s (%u)\n",}

Hi Heinrich,
On Thu, 20 Jul 2023 at 00:10, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 14.07.23 07:44, Masahisa Kojima wrote:
This introcudes the ramdisk uclass and driver.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
Newly introcuded in v2
disk/part.c | 3 + drivers/block/Kconfig | 7 +- drivers/block/Makefile | 2 + drivers/block/blk-uclass.c | 1 + drivers/block/blk_ramdisk.c | 187 +++++++++++++++++++++++++++++++ drivers/block/ramdisk-uclass.c | 14 +++ include/dm/uclass-id.h | 1 + include/ramdisk.h | 32 ++++++ lib/efi_loader/efi_device_path.c | 25 +++++ 9 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 drivers/block/blk_ramdisk.c create mode 100644 drivers/block/ramdisk-uclass.c create mode 100644 include/ramdisk.h
diff --git a/disk/part.c b/disk/part.c index 35300df590..d0cee3cc03 100644 --- a/disk/part.c +++ b/disk/part.c @@ -152,6 +152,9 @@ void dev_print(struct blk_desc *dev_desc) case UCLASS_EFI_MEDIA: printf("EFI media Block Device %d\n", dev_desc->devnum); break;
case UCLASS_RAM_DISK:
printf("RAM Disk Block Device %d\n", dev_desc->devnum);
break; case UCLASS_INVALID: puts("device type unknown\n"); return;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 5a1aeb3d2b..ab56ef3406 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -2,7 +2,7 @@ config BLK bool # "Support block devices" depends on DM default y if MMC || USB || SCSI || NVME || IDE || AHCI || SATA
default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK
default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK || RAM_DISK help Enable support for block devices, such as SCSI, MMC and USB flash sticks. These provide a block-level interface which permits
@@ -255,3 +255,8 @@ config SYS_64BIT_LBA help Make the block subsystem use 64bit sector addresses, rather than the default of 32bit.
+config RAM_DISK
bool "Enable RAM disk"
help
This option enables to mount the RAM disk.
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index a161d145fd..e867c7a126 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -19,3 +19,5 @@ obj-$(CONFIG_BLKMAP) += blkmap.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o +obj-$(CONFIG_RAM_DISK) += blk_ramdisk.o +obj-$(CONFIG_RAM_DISK) += ramdisk-uclass.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 614b975e25..ea411fe674 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -34,6 +34,7 @@ static struct { { UCLASS_VIRTIO, "virtio" }, { UCLASS_PVBLOCK, "pvblock" }, { UCLASS_BLKMAP, "blkmap" },
{ UCLASS_RAM_DISK, "ramdisk" },
};
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
diff --git a/drivers/block/blk_ramdisk.c b/drivers/block/blk_ramdisk.c new file mode 100644 index 0000000000..8016837a80 --- /dev/null +++ b/drivers/block/blk_ramdisk.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- RAM Disk block device driver
- Copyright (c) 2023, Linaro Limited
- */
+#include <blk.h> +#include <common.h> +#include <dm.h> +#include <log.h> +#include <part.h> +#include <ramdisk.h> +#include <dm/device-internal.h> +#include <dm/root.h>
+#if (IS_ENABLED(CONFIG_EFI_LOADER)) +#include <efi_loader.h> +#endif
+#define MEM_BLOCK_SIZE_SHIFT 9 /* 512 bytes */
+/**
- ramdisk_read() - read from block device
- @dev: device
- @blknr: first block to be read
- @blkcnt: number of blocks to read
- @buffer: output buffer
- Return: number of blocks transferred
- */
+static ulong ramdisk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
+{
u8 *start;
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
if (!buffer)
return 0;
if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT))
return 0;
start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT);
memmove(buffer, start, blkcnt << MEM_BLOCK_SIZE_SHIFT);
return blkcnt;
+}
+/**
- ramdisk_write() - write to block device
- @dev: device
- @blknr: first block to be write
- @blkcnt: number of blocks to write
- @buffer: input buffer
- Return: number of blocks transferred
- */
+static ulong ramdisk_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
const void *buffer)
+{
u8 *start;
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
if (!buffer)
return 0;
if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT))
return 0;
start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT);
memmove(start, buffer, blkcnt << MEM_BLOCK_SIZE_SHIFT);
return blkcnt;
+}
+static const struct blk_ops ramdisk_blk_ops = {
.read = ramdisk_read,
.write = ramdisk_write,
+};
+U_BOOT_DRIVER(ramdisk_blk) = {
.name = "ramdisk_blk",
.id = UCLASS_BLK,
.ops = &ramdisk_blk_ops,
.plat_auto = sizeof(struct ramdisk_blk_plat),
+};
+/*
- ramdisk_mount - mount ramdisk
- @start_address: The base address of registered RAM disk
- @size: The size of registered RAM disk
- @guid: The type of registered RAM disk
- Return: Pointer to the udevice strucure, return NULL if failed
- */
+struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid) +{
int ret;
char name[20];
struct udevice *parent, *bdev;
static struct ramdisk_blk_plat *plat;
if (!start_address || !size)
return NULL;
ret = device_bind(dm_root(), DM_DRIVER_GET(ramdisk), "ramdisk", NULL,
ofnode_null(), &parent);
if (ret) {
log_err("bind ramdisk error\n");
return NULL;
}
snprintf(name, sizeof(name), "ramdisk%d", dev_seq(parent));
device_set_name(parent, name);
ret = blk_create_device(parent, "ramdisk_blk", "ramdisk_blk",
UCLASS_RAM_DISK, dev_seq(parent),
1 << MEM_BLOCK_SIZE_SHIFT,
(size >> MEM_BLOCK_SIZE_SHIFT) - 1, &bdev);
if (ret) {
log_err("ramdisk create block device failed\n");
goto err;
}
snprintf(name, sizeof(name), "ramdisk_blk#%d", dev_seq(parent));
device_set_name(bdev, name);
plat = dev_get_plat(bdev);
plat->start = (u8 *)start_address;
plat->size = size;
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
if (guid)
guidcpy(&plat->disk_type_guid, guid);
+#endif
ret = blk_probe_or_unbind(bdev);
if (ret) {
log_err("ramdisk probe error\n");
goto err;
}
return bdev;
+err:
if (parent) {
ret = device_remove(parent, DM_REMOVE_NORMAL);
if (ret)
return NULL;
ret = device_unbind(parent);
}
return NULL;
+}
+/*
- ramdisk_unmount - unmount ramdisk
- @dev: The device to be unmounted
- Return: 0 if success, negative value if error
- */
+int ramdisk_unmount(struct udevice *dev) +{
int ret;
struct udevice *parent;
if (!dev)
return -EINVAL;
parent = dev->parent;
ret = device_remove(parent, DM_REMOVE_NORMAL);
if (ret)
return ret;
ret = device_unbind(parent);
return ret;
+}
+U_BOOT_DRIVER(ramdisk) = {
.name = "ramdisk",
.id = UCLASS_RAM_DISK,
+}; diff --git a/drivers/block/ramdisk-uclass.c b/drivers/block/ramdisk-uclass.c new file mode 100644 index 0000000000..f1bf68f635 --- /dev/null +++ b/drivers/block/ramdisk-uclass.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- RAM Disk block device driver
- Copyright (c) 2023, Linaro Limited
- */
+#include <common.h> +#include <dm.h>
+UCLASS_DRIVER(ramdisk) = {
.name = "ramdisk",
.id = UCLASS_RAM_DISK,
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 307ad6931c..42b4907b1f 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -109,6 +109,7 @@ enum uclass_id { UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_QFW, /* QEMU firmware config device */ UCLASS_RAM, /* RAM controller */
UCLASS_RAM_DISK, /* RAM disk device */ UCLASS_REBOOT_MODE, /* Reboot mode */ UCLASS_REGULATOR, /* Regulator device */ UCLASS_REMOTEPROC, /* Remote Processor device */
diff --git a/include/ramdisk.h b/include/ramdisk.h new file mode 100644 index 0000000000..71383be5b8 --- /dev/null +++ b/include/ramdisk.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- ramdisk support
- Copyright (c) 2023, Linaro Limited
- */
+#ifndef _RAMDISK_H +#define _RAMDISK_H
+#ifdef CONFIG_EFI_LOADER +#include <efi.h> +#endif
+/**
- struct ramdisk_blk_plat - attributes of a block device
- @handle: handle of the controller on which this driver is installed
- @io: block io protocol proxied by this driver
- */
+struct ramdisk_blk_plat {
u8 *start;
u64 size;
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
efi_guid_t disk_type_guid;
+#endif +};
+struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid); +int ramdisk_unmount(struct udevice *dev);
+#endif diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 04ebb449ca..1f16bda6ac 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -17,6 +17,7 @@ #include <nvme.h> #include <efi_loader.h> #include <part.h> +#include <ramdisk.h> #include <uuid.h> #include <asm-generic/unaligned.h> #include <linux/compat.h> /* U16_MAX */ @@ -568,6 +569,11 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) */ return dp_size(dev->parent) + sizeof(struct efi_device_path_vendor) + 1; +#endif +#ifdef CONFIG_RAM_DISK
case UCLASS_RAM_DISK:
What is the difference to UCLASS_BLKMAP?
[PATCH v2 0/9] blk: blkmap: Composable virtual block devices https://lore.kernel.org/u-boot/20230216153355.448302-1-tobias@waldekranz.com...
I was not aware of the blkmap when I created this series. This patch is duplicated, please drop this series.
Thanks, Masahisa Kojima
Best regards
Heinrich
return dp_size(dev->parent)
#endif default: return dp_size(dev->parent);+ sizeof(struct efi_device_path_ram_disk_path) + 1;
@@ -766,6 +772,25 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) dp->controller_number = desc->lun; return &dp[1]; } +#endif +#if defined(CONFIG_RAM_DISK)
case UCLASS_RAM_DISK: {
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
struct efi_device_path_ram_disk_path *dp =
dp_fill(buf, dev->parent);
dp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH;
dp->dp.length =
sizeof(struct efi_device_path_ram_disk_path);
put_unaligned_le64((u64)plat->start,
&dp->starting_address);
put_unaligned_le64((u64)(plat->start + plat->size - 1),
&dp->ending_address);
guidcpy(&dp->disk_type_guid, &plat->disk_type_guid);
dp->disk_instance = 0;
return &dp[1];
#endif default: debug("%s(%u) %s: unhandled parent class: %s (%u)\n",}

Hi Masahisa,
On Thu, 13 Jul 2023 at 23:47, Masahisa Kojima masahisa.kojima@linaro.org wrote:
This introcudes the ramdisk uclass and driver.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
Newly introcuded in v2
disk/part.c | 3 + drivers/block/Kconfig | 7 +- drivers/block/Makefile | 2 + drivers/block/blk-uclass.c | 1 + drivers/block/blk_ramdisk.c | 187 +++++++++++++++++++++++++++++++ drivers/block/ramdisk-uclass.c | 14 +++ include/dm/uclass-id.h | 1 + include/ramdisk.h | 32 ++++++ lib/efi_loader/efi_device_path.c | 25 +++++ 9 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 drivers/block/blk_ramdisk.c create mode 100644 drivers/block/ramdisk-uclass.c create mode 100644 include/ramdisk.h
Please remember to add a sandbox driver and a test in test/dm
diff --git a/disk/part.c b/disk/part.c index 35300df590..d0cee3cc03 100644 --- a/disk/part.c +++ b/disk/part.c @@ -152,6 +152,9 @@ void dev_print(struct blk_desc *dev_desc) case UCLASS_EFI_MEDIA: printf("EFI media Block Device %d\n", dev_desc->devnum); break;
case UCLASS_RAM_DISK:
printf("RAM Disk Block Device %d\n", dev_desc->devnum);
break; case UCLASS_INVALID: puts("device type unknown\n"); return;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 5a1aeb3d2b..ab56ef3406 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -2,7 +2,7 @@ config BLK bool # "Support block devices" depends on DM default y if MMC || USB || SCSI || NVME || IDE || AHCI || SATA
default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK
default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK || RAM_DISK help Enable support for block devices, such as SCSI, MMC and USB flash sticks. These provide a block-level interface which permits
@@ -255,3 +255,8 @@ config SYS_64BIT_LBA help Make the block subsystem use 64bit sector addresses, rather than the default of 32bit.
+config RAM_DISK
bool "Enable RAM disk"
help
This option enables to mount the RAM disk.
??
Please expand that. It tells me almost nothing. You should get a checkpatch warning about writing such short descriptions.
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index a161d145fd..e867c7a126 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -19,3 +19,5 @@ obj-$(CONFIG_BLKMAP) += blkmap.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o +obj-$(CONFIG_RAM_DISK) += blk_ramdisk.o +obj-$(CONFIG_RAM_DISK) += ramdisk-uclass.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 614b975e25..ea411fe674 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -34,6 +34,7 @@ static struct { { UCLASS_VIRTIO, "virtio" }, { UCLASS_PVBLOCK, "pvblock" }, { UCLASS_BLKMAP, "blkmap" },
{ UCLASS_RAM_DISK, "ramdisk" },
};
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname) diff --git a/drivers/block/blk_ramdisk.c b/drivers/block/blk_ramdisk.c new file mode 100644 index 0000000000..8016837a80 --- /dev/null +++ b/drivers/block/blk_ramdisk.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- RAM Disk block device driver
- Copyright (c) 2023, Linaro Limited
- */
+#include <blk.h> +#include <common.h> +#include <dm.h> +#include <log.h> +#include <part.h> +#include <ramdisk.h> +#include <dm/device-internal.h> +#include <dm/root.h>
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
drop the #if
+#include <efi_loader.h> +#endif
+#define MEM_BLOCK_SIZE_SHIFT 9 /* 512 bytes */
+/**
- ramdisk_read() - read from block device
- @dev: device
- @blknr: first block to be read
- @blkcnt: number of blocks to read
- @buffer: output buffer
- Return: number of blocks transferred
- */
+static ulong ramdisk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
+{
u8 *start;
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
if (!buffer)
return 0;
if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT))
return 0;
start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT);
memmove(buffer, start, blkcnt << MEM_BLOCK_SIZE_SHIFT);
return blkcnt;
+}
+/**
- ramdisk_write() - write to block device
- @dev: device
- @blknr: first block to be write
- @blkcnt: number of blocks to write
- @buffer: input buffer
- Return: number of blocks transferred
- */
+static ulong ramdisk_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
const void *buffer)
+{
u8 *start;
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
if (!buffer)
return 0;
if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT))
return 0;
start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT);
memmove(start, buffer, blkcnt << MEM_BLOCK_SIZE_SHIFT);
return blkcnt;
+}
+static const struct blk_ops ramdisk_blk_ops = {
.read = ramdisk_read,
.write = ramdisk_write,
+};
+U_BOOT_DRIVER(ramdisk_blk) = {
.name = "ramdisk_blk",
.id = UCLASS_BLK,
.ops = &ramdisk_blk_ops,
.plat_auto = sizeof(struct ramdisk_blk_plat),
+};
+/*
- ramdisk_mount - mount ramdisk
- @start_address: The base address of registered RAM disk
- @size: The size of registered RAM disk
- @guid: The type of registered RAM disk
- Return: Pointer to the udevice strucure, return NULL if failed
spelling
- */
+struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid)
what is guid? I want to avoid these infecting U-Boot where not nescessary
+{
int ret;
char name[20];
struct udevice *parent, *bdev;
static struct ramdisk_blk_plat *plat;
if (!start_address || !size)
return NULL;
ret = device_bind(dm_root(), DM_DRIVER_GET(ramdisk), "ramdisk", NULL,
ofnode_null(), &parent);
Can you use devicetree to bind this?
if (ret) {
log_err("bind ramdisk error\n");
return NULL;
}
snprintf(name, sizeof(name), "ramdisk%d", dev_seq(parent));
device_set_name(parent, name);
ret = blk_create_device(parent, "ramdisk_blk", "ramdisk_blk",
UCLASS_RAM_DISK, dev_seq(parent),
1 << MEM_BLOCK_SIZE_SHIFT,
(size >> MEM_BLOCK_SIZE_SHIFT) - 1, &bdev);
Can you use blk_create_devicef() ? You should not pass the devnum parameter - use -1 instead.
if (ret) {
log_err("ramdisk create block device failed\n");
goto err;
}
snprintf(name, sizeof(name), "ramdisk_blk#%d", dev_seq(parent));
device_set_name(bdev, name);
plat = dev_get_plat(bdev);
plat->start = (u8 *)start_address;
plat->size = size;
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
Please use if()
But what does this have to do with EFI loader? That code lives in lib/efi_loader, not here.
if (guid)
guidcpy(&plat->disk_type_guid, guid);
+#endif
ret = blk_probe_or_unbind(bdev);
if (ret) {
log_err("ramdisk probe error\n");
goto err;
}
return bdev;
+err:
if (parent) {
ret = device_remove(parent, DM_REMOVE_NORMAL);
if (ret)
return NULL;
ret = device_unbind(parent);
}
return NULL;
+}
+/*
- ramdisk_unmount - unmount ramdisk
- @dev: The device to be unmounted
- Return: 0 if success, negative value if error
- */
+int ramdisk_unmount(struct udevice *dev) +{
int ret;
struct udevice *parent;
if (!dev)
return -EINVAL;
parent = dev->parent;
ret = device_remove(parent, DM_REMOVE_NORMAL);
if (ret)
return ret;
ret = device_unbind(parent);
return ret;
+}
+U_BOOT_DRIVER(ramdisk) = {
.name = "ramdisk",
.id = UCLASS_RAM_DISK,
+}; diff --git a/drivers/block/ramdisk-uclass.c b/drivers/block/ramdisk-uclass.c new file mode 100644 index 0000000000..f1bf68f635 --- /dev/null +++ b/drivers/block/ramdisk-uclass.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- RAM Disk block device driver
- Copyright (c) 2023, Linaro Limited
- */
+#include <common.h> +#include <dm.h>
+UCLASS_DRIVER(ramdisk) = {
.name = "ramdisk",
.id = UCLASS_RAM_DISK,
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 307ad6931c..42b4907b1f 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -109,6 +109,7 @@ enum uclass_id { UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_QFW, /* QEMU firmware config device */ UCLASS_RAM, /* RAM controller */
UCLASS_RAM_DISK, /* RAM disk device */ UCLASS_REBOOT_MODE, /* Reboot mode */ UCLASS_REGULATOR, /* Regulator device */ UCLASS_REMOTEPROC, /* Remote Processor device */
diff --git a/include/ramdisk.h b/include/ramdisk.h new file mode 100644 index 0000000000..71383be5b8 --- /dev/null +++ b/include/ramdisk.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- ramdisk support
- Copyright (c) 2023, Linaro Limited
- */
+#ifndef _RAMDISK_H +#define _RAMDISK_H
+#ifdef CONFIG_EFI_LOADER +#include <efi.h> +#endif
+/**
- struct ramdisk_blk_plat - attributes of a block device
- @handle: handle of the controller on which this driver is installed
- @io: block io protocol proxied by this driver
- */
+struct ramdisk_blk_plat {
u8 *start;
u64 size;
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
efi_guid_t disk_type_guid;
+#endif +};
+struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid); +int ramdisk_unmount(struct udevice *dev);
+#endif diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 04ebb449ca..1f16bda6ac 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c
This should be a separate patch
@@ -17,6 +17,7 @@ #include <nvme.h> #include <efi_loader.h> #include <part.h> +#include <ramdisk.h> #include <uuid.h> #include <asm-generic/unaligned.h> #include <linux/compat.h> /* U16_MAX */ @@ -568,6 +569,11 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) */ return dp_size(dev->parent) + sizeof(struct efi_device_path_vendor) + 1; +#endif +#ifdef CONFIG_RAM_DISK
case UCLASS_RAM_DISK:
return dp_size(dev->parent)
+ sizeof(struct efi_device_path_ram_disk_path) + 1;
#endif default: return dp_size(dev->parent); @@ -766,6 +772,25 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) dp->controller_number = desc->lun; return &dp[1]; } +#endif +#if defined(CONFIG_RAM_DISK)
case UCLASS_RAM_DISK: {
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
struct efi_device_path_ram_disk_path *dp =
dp_fill(buf, dev->parent);
dp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH;
dp->dp.length =
sizeof(struct efi_device_path_ram_disk_path);
put_unaligned_le64((u64)plat->start,
&dp->starting_address);
put_unaligned_le64((u64)(plat->start + plat->size - 1),
&dp->ending_address);
guidcpy(&dp->disk_type_guid, &plat->disk_type_guid);
dp->disk_instance = 0;
return &dp[1];
}
#endif default: debug("%s(%u) %s: unhandled parent class: %s (%u)\n", -- 2.34.1
Regards, Simon

Hi Simon,
On Thu, 20 Jul 2023 at 04:11, Simon Glass sjg@chromium.org wrote:
Hi Masahisa,
On Thu, 13 Jul 2023 at 23:47, Masahisa Kojima masahisa.kojima@linaro.org wrote:
This introcudes the ramdisk uclass and driver.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
Newly introcuded in v2
disk/part.c | 3 + drivers/block/Kconfig | 7 +- drivers/block/Makefile | 2 + drivers/block/blk-uclass.c | 1 + drivers/block/blk_ramdisk.c | 187 +++++++++++++++++++++++++++++++ drivers/block/ramdisk-uclass.c | 14 +++ include/dm/uclass-id.h | 1 + include/ramdisk.h | 32 ++++++ lib/efi_loader/efi_device_path.c | 25 +++++ 9 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 drivers/block/blk_ramdisk.c create mode 100644 drivers/block/ramdisk-uclass.c create mode 100644 include/ramdisk.h
Please remember to add a sandbox driver and a test in test/dm
diff --git a/disk/part.c b/disk/part.c index 35300df590..d0cee3cc03 100644 --- a/disk/part.c +++ b/disk/part.c @@ -152,6 +152,9 @@ void dev_print(struct blk_desc *dev_desc) case UCLASS_EFI_MEDIA: printf("EFI media Block Device %d\n", dev_desc->devnum); break;
case UCLASS_RAM_DISK:
printf("RAM Disk Block Device %d\n", dev_desc->devnum);
break; case UCLASS_INVALID: puts("device type unknown\n"); return;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 5a1aeb3d2b..ab56ef3406 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -2,7 +2,7 @@ config BLK bool # "Support block devices" depends on DM default y if MMC || USB || SCSI || NVME || IDE || AHCI || SATA
default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK
default y if EFI_MEDIA || VIRTIO_BLK || PVBLOCK || RAM_DISK help Enable support for block devices, such as SCSI, MMC and USB flash sticks. These provide a block-level interface which permits
@@ -255,3 +255,8 @@ config SYS_64BIT_LBA help Make the block subsystem use 64bit sector addresses, rather than the default of 32bit.
+config RAM_DISK
bool "Enable RAM disk"
help
This option enables to mount the RAM disk.
??
Please expand that. It tells me almost nothing. You should get a checkpatch warning about writing such short descriptions.
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index a161d145fd..e867c7a126 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -19,3 +19,5 @@ obj-$(CONFIG_BLKMAP) += blkmap.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o +obj-$(CONFIG_RAM_DISK) += blk_ramdisk.o +obj-$(CONFIG_RAM_DISK) += ramdisk-uclass.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 614b975e25..ea411fe674 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -34,6 +34,7 @@ static struct { { UCLASS_VIRTIO, "virtio" }, { UCLASS_PVBLOCK, "pvblock" }, { UCLASS_BLKMAP, "blkmap" },
{ UCLASS_RAM_DISK, "ramdisk" },
};
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname) diff --git a/drivers/block/blk_ramdisk.c b/drivers/block/blk_ramdisk.c new file mode 100644 index 0000000000..8016837a80 --- /dev/null +++ b/drivers/block/blk_ramdisk.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- RAM Disk block device driver
- Copyright (c) 2023, Linaro Limited
- */
+#include <blk.h> +#include <common.h> +#include <dm.h> +#include <log.h> +#include <part.h> +#include <ramdisk.h> +#include <dm/device-internal.h> +#include <dm/root.h>
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
drop the #if
+#include <efi_loader.h> +#endif
+#define MEM_BLOCK_SIZE_SHIFT 9 /* 512 bytes */
+/**
- ramdisk_read() - read from block device
- @dev: device
- @blknr: first block to be read
- @blkcnt: number of blocks to read
- @buffer: output buffer
- Return: number of blocks transferred
- */
+static ulong ramdisk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
+{
u8 *start;
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
if (!buffer)
return 0;
if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT))
return 0;
start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT);
memmove(buffer, start, blkcnt << MEM_BLOCK_SIZE_SHIFT);
return blkcnt;
+}
+/**
- ramdisk_write() - write to block device
- @dev: device
- @blknr: first block to be write
- @blkcnt: number of blocks to write
- @buffer: input buffer
- Return: number of blocks transferred
- */
+static ulong ramdisk_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
const void *buffer)
+{
u8 *start;
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
if (!buffer)
return 0;
if (blknr + blkcnt > (plat->size >> MEM_BLOCK_SIZE_SHIFT))
return 0;
start = plat->start + (blknr << MEM_BLOCK_SIZE_SHIFT);
memmove(start, buffer, blkcnt << MEM_BLOCK_SIZE_SHIFT);
return blkcnt;
+}
+static const struct blk_ops ramdisk_blk_ops = {
.read = ramdisk_read,
.write = ramdisk_write,
+};
+U_BOOT_DRIVER(ramdisk_blk) = {
.name = "ramdisk_blk",
.id = UCLASS_BLK,
.ops = &ramdisk_blk_ops,
.plat_auto = sizeof(struct ramdisk_blk_plat),
+};
+/*
- ramdisk_mount - mount ramdisk
- @start_address: The base address of registered RAM disk
- @size: The size of registered RAM disk
- @guid: The type of registered RAM disk
- Return: Pointer to the udevice strucure, return NULL if failed
spelling
- */
+struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid)
what is guid? I want to avoid these infecting U-Boot where not nescessary
+{
int ret;
char name[20];
struct udevice *parent, *bdev;
static struct ramdisk_blk_plat *plat;
if (!start_address || !size)
return NULL;
ret = device_bind(dm_root(), DM_DRIVER_GET(ramdisk), "ramdisk", NULL,
ofnode_null(), &parent);
Can you use devicetree to bind this?
if (ret) {
log_err("bind ramdisk error\n");
return NULL;
}
snprintf(name, sizeof(name), "ramdisk%d", dev_seq(parent));
device_set_name(parent, name);
ret = blk_create_device(parent, "ramdisk_blk", "ramdisk_blk",
UCLASS_RAM_DISK, dev_seq(parent),
1 << MEM_BLOCK_SIZE_SHIFT,
(size >> MEM_BLOCK_SIZE_SHIFT) - 1, &bdev);
Can you use blk_create_devicef() ? You should not pass the devnum parameter - use -1 instead.
if (ret) {
log_err("ramdisk create block device failed\n");
goto err;
}
snprintf(name, sizeof(name), "ramdisk_blk#%d", dev_seq(parent));
device_set_name(bdev, name);
plat = dev_get_plat(bdev);
plat->start = (u8 *)start_address;
plat->size = size;
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
Please use if()
But what does this have to do with EFI loader? That code lives in lib/efi_loader, not here.
if (guid)
guidcpy(&plat->disk_type_guid, guid);
+#endif
ret = blk_probe_or_unbind(bdev);
if (ret) {
log_err("ramdisk probe error\n");
goto err;
}
return bdev;
+err:
if (parent) {
ret = device_remove(parent, DM_REMOVE_NORMAL);
if (ret)
return NULL;
ret = device_unbind(parent);
}
return NULL;
+}
+/*
- ramdisk_unmount - unmount ramdisk
- @dev: The device to be unmounted
- Return: 0 if success, negative value if error
- */
+int ramdisk_unmount(struct udevice *dev) +{
int ret;
struct udevice *parent;
if (!dev)
return -EINVAL;
parent = dev->parent;
ret = device_remove(parent, DM_REMOVE_NORMAL);
if (ret)
return ret;
ret = device_unbind(parent);
return ret;
+}
+U_BOOT_DRIVER(ramdisk) = {
.name = "ramdisk",
.id = UCLASS_RAM_DISK,
+}; diff --git a/drivers/block/ramdisk-uclass.c b/drivers/block/ramdisk-uclass.c new file mode 100644 index 0000000000..f1bf68f635 --- /dev/null +++ b/drivers/block/ramdisk-uclass.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- RAM Disk block device driver
- Copyright (c) 2023, Linaro Limited
- */
+#include <common.h> +#include <dm.h>
+UCLASS_DRIVER(ramdisk) = {
.name = "ramdisk",
.id = UCLASS_RAM_DISK,
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 307ad6931c..42b4907b1f 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -109,6 +109,7 @@ enum uclass_id { UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_QFW, /* QEMU firmware config device */ UCLASS_RAM, /* RAM controller */
UCLASS_RAM_DISK, /* RAM disk device */ UCLASS_REBOOT_MODE, /* Reboot mode */ UCLASS_REGULATOR, /* Regulator device */ UCLASS_REMOTEPROC, /* Remote Processor device */
diff --git a/include/ramdisk.h b/include/ramdisk.h new file mode 100644 index 0000000000..71383be5b8 --- /dev/null +++ b/include/ramdisk.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- ramdisk support
- Copyright (c) 2023, Linaro Limited
- */
+#ifndef _RAMDISK_H +#define _RAMDISK_H
+#ifdef CONFIG_EFI_LOADER +#include <efi.h> +#endif
+/**
- struct ramdisk_blk_plat - attributes of a block device
- @handle: handle of the controller on which this driver is installed
- @io: block io protocol proxied by this driver
- */
+struct ramdisk_blk_plat {
u8 *start;
u64 size;
+#if (IS_ENABLED(CONFIG_EFI_LOADER))
efi_guid_t disk_type_guid;
+#endif +};
+struct udevice *ramdisk_mount(u64 start_address, u64 size, void *guid); +int ramdisk_unmount(struct udevice *dev);
+#endif diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 04ebb449ca..1f16bda6ac 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c
This should be a separate patch
Thank you for your review. This patch is duplicated, I can use blkmap. Please drop this series.
Thanks, Masahisa Kojima
@@ -17,6 +17,7 @@ #include <nvme.h> #include <efi_loader.h> #include <part.h> +#include <ramdisk.h> #include <uuid.h> #include <asm-generic/unaligned.h> #include <linux/compat.h> /* U16_MAX */ @@ -568,6 +569,11 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) */ return dp_size(dev->parent) + sizeof(struct efi_device_path_vendor) + 1; +#endif +#ifdef CONFIG_RAM_DISK
case UCLASS_RAM_DISK:
return dp_size(dev->parent)
+ sizeof(struct efi_device_path_ram_disk_path) + 1;
#endif default: return dp_size(dev->parent); @@ -766,6 +772,25 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) dp->controller_number = desc->lun; return &dp[1]; } +#endif +#if defined(CONFIG_RAM_DISK)
case UCLASS_RAM_DISK: {
struct ramdisk_blk_plat *plat = dev_get_plat(dev);
struct efi_device_path_ram_disk_path *dp =
dp_fill(buf, dev->parent);
dp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH;
dp->dp.length =
sizeof(struct efi_device_path_ram_disk_path);
put_unaligned_le64((u64)plat->start,
&dp->starting_address);
put_unaligned_le64((u64)(plat->start + plat->size - 1),
&dp->ending_address);
guidcpy(&dp->disk_type_guid, &plat->disk_type_guid);
dp->disk_instance = 0;
return &dp[1];
}
#endif default: debug("%s(%u) %s: unhandled parent class: %s (%u)\n", -- 2.34.1
Regards, Simon

This introcudes the ramdisk command, to control the ramdisk devices.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- Newly introcuded in v2
cmd/Kconfig | 7 ++++ cmd/Makefile | 1 + cmd/ramdisk.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 cmd/ramdisk.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 365371fb51..5f3022b0c9 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1592,6 +1592,13 @@ config CMD_AXI Interface) busses, a on-chip interconnect specification for managing functional blocks in SoC designs, which is also often used in designs involving FPGAs (e.g. communication with IP cores in Xilinx FPGAs). + +config CMD_RAM_DISK + bool "ramdisk" + depends on RAM_DISK + help + This provides commands to control the ramdisk devices. + endmenu
diff --git a/cmd/Makefile b/cmd/Makefile index 6c37521b4e..eb7d86a3c6 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -142,6 +142,7 @@ obj-$(CONFIG_CMD_PWM) += pwm.o obj-$(CONFIG_CMD_PXE) += pxe.o obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_CMD_QFW) += qfw.o +obj-$(CONFIG_CMD_RAM_DISK) += ramdisk.o obj-$(CONFIG_CMD_READ) += read.o obj-$(CONFIG_CMD_WRITE) += read.o obj-$(CONFIG_CMD_REGINFO) += reginfo.o diff --git a/cmd/ramdisk.c b/cmd/ramdisk.c new file mode 100644 index 0000000000..8df29729aa --- /dev/null +++ b/cmd/ramdisk.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * ramdisk command + * + * Copyright (c) 2023, Linaro Limited + */ + +#include <blk.h> +#include <common.h> +#include <command.h> +#include <dm.h> +#include <ramdisk.h> + +static int ramdisk_curr_dev; /* current device */ + +static int get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + *descp = NULL; + ret = uclass_get(UCLASS_BLK, &uc); + if (ret) + return ret; + + uclass_foreach_dev(dev, uc) { + struct blk_desc *desc = dev_get_uclass_plat(dev); + + if (desc->uclass_id == uclass_id) { + if (desc->devnum == devnum) { + *descp = desc; + return 0; + } + } + } + + return -1; +} + +static int do_ramdisk(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int ret; + u64 addr, size; + struct udevice *dev; + + if (strncmp(argv[1], "mount", 5) == 0) { + if (argc != 4) + return CMD_RET_USAGE; + + addr = hextoul(argv[2], NULL); + size = hextoul(argv[3], NULL); + dev = ramdisk_mount(addr, size, NULL); + if (!dev) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; + } + + if (strncmp(argv[1], "umount", 6) == 0) { + struct blk_desc *desc; + + ret = get_desc(UCLASS_RAM_DISK, ramdisk_curr_dev, &desc); + if (ret) { + printf("ramdisk device not found(dev %d)\n", ramdisk_curr_dev); + return CMD_RET_FAILURE; + } + + ret = ramdisk_unmount(desc->bdev); + if (ret) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; + } + + return blk_common_cmd(argc, argv, UCLASS_RAM_DISK, &ramdisk_curr_dev); +} + +U_BOOT_CMD( + ramdisk, 5, 1, do_ramdisk, + "ramdisk sub-system", + "ramdisk info - show available ramdisk devices\n" + "ramdisk mount <address> <size> - mount ramdisk\n" + "ramdisk umount - unmount ramdisk\n" + "ramdisk device [dev] - show or set current device\n" + "ramdisk part [dev] - print partition table of one or all ramdisk devices\n" + "ramdisk read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n" + " to memory address `addr'\n" + "ramdisk write addr blk# cnt - write `cnt' blocks starting at block\n" + " `blk#' from memory address `addr'" +);

This commit adds the EFI_RAM_DISK_PROTOCOL implementation. User can mount the distro installer by registering the memory mapped ISO image through EFI_RAM_DISK_PROTOCOL.
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- Changes in v2: - implement EFI_RAM_DISK_PROTOCOL based on the ramdisk uclass
include/efi_api.h | 13 ++++ include/efi_loader.h | 4 + lib/efi_loader/Kconfig | 7 ++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_ram_disk.c | 142 ++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 6 ++ lib/uuid.c | 4 + 7 files changed, 177 insertions(+) create mode 100644 lib/efi_loader/efi_ram_disk.c
diff --git a/include/efi_api.h b/include/efi_api.h index 4ee4a1b5e9..3982ab89bc 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -764,6 +764,19 @@ struct efi_block_io { efi_status_t (EFIAPI *flush_blocks)(struct efi_block_io *this); };
+#define EFI_RAM_DISK_PROTOCOL_GUID \ + EFI_GUID(0xab38a0df, 0x6873, 0x44a9, \ + 0x87, 0xe6, 0xd4, 0xeb, 0x56, 0x14, 0x84, 0x49) + +struct efi_ram_disk_protocol { + /* "register" is a reserved keyword in C, use "disk_register" instead */ + efi_status_t(EFIAPI *disk_register)( + u64 ram_disk_base, u64 ram_disk_size, efi_guid_t *ram_disk_type, + struct efi_device_path *parent_device_path, + struct efi_device_path **device_path); + efi_status_t (EFIAPI *unregister)(struct efi_device_path *device_path); +}; + struct simple_text_output_mode { s32 max_mode; s32 mode; diff --git a/include/efi_loader.h b/include/efi_loader.h index 604fd765f7..70c8c83099 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -333,6 +333,8 @@ extern const efi_guid_t smbios_guid; /*GUID of console */ extern const efi_guid_t efi_guid_text_input_protocol; extern const efi_guid_t efi_guid_text_output_protocol; +/* GUID of Ram Disk protocol */ +extern const efi_guid_t efi_guid_ram_disk_protocol;
extern char __efi_runtime_start[], __efi_runtime_stop[]; extern char __efi_runtime_rel_start[], __efi_runtime_rel_stop[]; @@ -1159,4 +1161,6 @@ efi_status_t efi_disk_get_device_name(const efi_handle_t handle, char *buf, int */ void efi_add_known_memory(void);
+efi_status_t efi_ram_disk_register(void); + #endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index c5835e6ef6..ff0559e8c4 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -433,4 +433,11 @@ config EFI_RISCV_BOOT_PROTOCOL replace the transfer via the device-tree. The latter is not possible on systems using ACPI.
+config EFI_RAM_DISK_PROTOCOL + bool "EFI_RAM_DISK_PROTOCOL support" + depends on PARTITIONS + depends on RAM_DISK + help + Provide a EFI_RAM_DISK_PROTOCOL implementation to register the + RAM disk and create the block device. endif diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 1a8c8d7cab..4197f594a2 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_EFI_RISCV_BOOT_PROTOCOL) += efi_riscv.o obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o obj-$(CONFIG_EFI_SIGNATURE_SUPPORT) += efi_signature.o obj-$(CONFIG_EFI_ECPT) += efi_conformance.o +obj-$(CONFIG_EFI_RAM_DISK_PROTOCOL) += efi_ram_disk.o
EFI_VAR_SEED_FILE := $(subst $",,$(CONFIG_EFI_VAR_SEED_FILE)) $(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE) diff --git a/lib/efi_loader/efi_ram_disk.c b/lib/efi_loader/efi_ram_disk.c new file mode 100644 index 0000000000..a261d93963 --- /dev/null +++ b/lib/efi_loader/efi_ram_disk.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * RAM Disk Protocol + * + * Copyright (c) 2023, Linaro Limited + */ + +#include <dm.h> +#include <efi_loader.h> +#include <malloc.h> +#include <ramdisk.h> + +const efi_guid_t efi_guid_ram_disk_protocol = EFI_RAM_DISK_PROTOCOL_GUID; + +/* + * ram_disk_register - Register service of the RAM disk protocol + * + * @ram_disk_base: The base address of registered RAM disk + * @ram_disk_size: The size of registered RAM disk + * @ram_disk_type: The type of registered RAM disk + * @parent_device_path: Pointer to the parent device path + * @device_path: Pointer to the device path + * Return: status code + */ +static efi_status_t EFIAPI +ram_disk_register(u64 ram_disk_base, u64 ram_disk_size, + efi_guid_t *ram_disk_type, + struct efi_device_path *parent_device_path, + struct efi_device_path **device_path) +{ + efi_status_t ret; + struct udevice *bdev; + efi_handle_t disk_handle; + struct efi_handler *handler; + struct efi_device_path *dp; + + EFI_ENTRY("%llu %llu %pUs %p, %p", ram_disk_base, ram_disk_size, + ram_disk_type, parent_device_path, device_path); + + if (!ram_disk_size || !ram_disk_type || !device_path) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + *device_path = NULL; + + /* TODO: Add parent_device_path */ + bdev = ramdisk_mount(ram_disk_base, ram_disk_size, ram_disk_type); + if (!bdev) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + if (dev_tag_get_ptr(bdev, DM_TAG_EFI, (void **)&disk_handle)) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + ret = efi_search_protocol(disk_handle, &efi_guid_device_path, &handler); + if (ret != EFI_SUCCESS) + goto out; + + ret = efi_protocol_open(handler, (void **)&dp, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) + goto out; + + log_debug("EFI_RAM_DISK_PROTOCOL register %pD\n", dp); + + *device_path = efi_dp_dup(dp); + if (!(*device_path)) + ret = EFI_OUT_OF_RESOURCES; + +out: + return EFI_EXIT(ret); +} + +/* + * ram_disk_unregister - Unregister service of the RAM disk protocol + * + * @device_path: Pointer to the device path + * Return: status code + */ +static efi_status_t EFIAPI +ram_disk_unregister(struct efi_device_path *device_path) +{ + int ret; + efi_status_t status = EFI_SUCCESS; + enum uclass_id id; + efi_handle_t disk_handle; + + EFI_ENTRY("%pD", device_path); + + if (!device_path) { + status = EFI_INVALID_PARAMETER; + goto out; + } + + disk_handle = efi_dp_find_obj(device_path, &efi_block_io_guid, NULL); + if (!disk_handle) { + status = EFI_NOT_FOUND; + goto out; + } + + id = device_get_uclass_id(disk_handle->dev); + if (id != UCLASS_BLK) { + status = EFI_INVALID_PARAMETER; + goto out; + } + + ret = ramdisk_unmount(disk_handle->dev); + if (ret) { + log_err("EFI_RAM_DISK_PROTOCOL unregister failed(%d)\n", ret); + status = EFI_INVALID_PARAMETER; + goto out; + } + +out: + return EFI_EXIT(status); +} + +static const struct efi_ram_disk_protocol efi_ram_disk_protocol = { + .disk_register = ram_disk_register, + .unregister = ram_disk_unregister, +}; + +/** + * efi_ram_disk_register() - register EFI_RAM_DISK_PROTOCOL + * + * Return: status code + */ +efi_status_t efi_ram_disk_register(void) +{ + efi_status_t ret; + + ret = efi_add_protocol(efi_root, &efi_guid_ram_disk_protocol, + (void *)&efi_ram_disk_protocol); + if (ret != EFI_SUCCESS) + log_err("Cannot install EFI_RAM_DISK_PROTOCOL\n"); + + return ret; +} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 877f3878d6..8c430d4a9c 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -344,6 +344,12 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out;
+ if (IS_ENABLED(CONFIG_EFI_RAM_DISK_PROTOCOL)) { + ret = efi_ram_disk_register(); + if (ret != EFI_SUCCESS) + goto out; + } + /* Initialize EFI runtime services */ ret = efi_reset_system_init(); if (ret != EFI_SUCCESS) diff --git a/lib/uuid.c b/lib/uuid.c index 96e1af3c8b..9827588186 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -195,6 +195,10 @@ static const struct { "Firmware Management", EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID }, + { + "Ram Disk", + EFI_RAM_DISK_PROTOCOL_GUID + }, /* Configuration table GUIDs */ { "ACPI table",

This commit implements the test commands for EFI_RAM_DISK_PROTOCOL. With the disk load/unload commands, user can mount the ISO image in the volatile memory through EFI_RAM_DISK_PROTOCOL.
Currently the load command can load only one image at a time even if UEFI specification does not limit the number of images. Anyway one image is enough for testing.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- Changes in v2: - renamed command load/unload -> mount/umount
cmd/efidebug.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 9622430c47..2f8e6b6234 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1421,6 +1421,114 @@ static int do_efi_query_info(struct cmd_tbl *cmdtp, int flag, return CMD_RET_SUCCESS; }
+#ifdef CONFIG_EFI_RAM_DISK_PROTOCOL +static struct efi_device_path *ram_disk_dp; +static efi_guid_t virtual_cd_guid = EFI_VIRTUAL_CD_GUID; + +static int do_efi_disk_mount(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + u64 addr, size; + efi_status_t ret; + struct efi_ram_disk_protocol *ram_disk = NULL; + + if (ram_disk_dp) { + printf("Only one image can be loaded\n"); + return CMD_RET_FAILURE; + } + + argc--; + argv++; + + if (argc != 2) + return CMD_RET_USAGE; + + addr = hextoul(argv[0], NULL); + size = hextoul(argv[1], NULL); + + ret = EFI_CALL(BS->locate_protocol(&efi_guid_ram_disk_protocol, NULL, + (void **)&ram_disk)); + if (ret != EFI_SUCCESS || !ram_disk) { + printf("No EFI_RAM_DISK_PROTOCOL found(ret = %lu)\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = EFI_CALL(ram_disk->disk_register(addr, size, &virtual_cd_guid, NULL, + &ram_disk_dp)); + if (ret != EFI_SUCCESS || !ram_disk_dp) { + printf("RAM DISK register failed(ret = %lu)\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static int do_efi_disk_umount(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + efi_status_t ret; + struct efi_ram_disk_protocol *ram_disk = NULL; + + ret = EFI_CALL(BS->locate_protocol(&efi_guid_ram_disk_protocol, NULL, + (void **)&ram_disk)); + if (ret != EFI_SUCCESS || !ram_disk) { + printf("No EFI_RAM_DISK_PROTOCOL found(ret = %lu)\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = EFI_CALL(ram_disk->unregister(ram_disk_dp)); + if (ret != EFI_SUCCESS) { + printf("RAM DISK unregister failed(ret = %lu)\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + efi_free_pool(ram_disk_dp); + ram_disk_dp = NULL; + + return CMD_RET_SUCCESS; +} + +static struct cmd_tbl cmd_efidebug_disk_sub[] = { + U_BOOT_CMD_MKENT(mount, CONFIG_SYS_MAXARGS, 1, do_efi_disk_mount, "", ""), + U_BOOT_CMD_MKENT(umount, CONFIG_SYS_MAXARGS, 1, do_efi_disk_umount, "", ""), +}; + +/** + * do_efi_disk() - manage UEFI ram disk device + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, + * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "disk" sub-command. + */ +static int do_efi_disk(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct cmd_tbl *cp; + + if (argc < 2) + return CMD_RET_USAGE; + + argc--; + argv++; + + cp = find_cmd_tbl(argv[0], cmd_efidebug_disk_sub, + ARRAY_SIZE(cmd_efidebug_disk_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} +#endif + static struct cmd_tbl cmd_efidebug_sub[] = { U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""), #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT @@ -1441,6 +1549,10 @@ static struct cmd_tbl cmd_efidebug_sub[] = { "", ""), U_BOOT_CMD_MKENT(query, CONFIG_SYS_MAXARGS, 1, do_efi_query_info, "", ""), +#ifdef CONFIG_EFI_RAM_DISK_PROTOCOL + U_BOOT_CMD_MKENT(disk, CONFIG_SYS_MAXARGS, 1, do_efi_disk, + "", ""), +#endif };
/** @@ -1526,6 +1638,12 @@ static char efidebug_help_text[] = " - show UEFI memory map\n" "efidebug tables\n" " - show UEFI configuration tables\n" +#ifdef CONFIG_EFI_RAM_DISK_PROTOCOL + "efidebug disk mount <address> <size>\n" + " - load ISO image\n" + "efidebug disk umount\n" + " - unload ISO image\n" +#endif #ifdef CONFIG_CMD_BOOTEFI_BOOTMGR "efidebug test bootmgr\n" " - run simple bootmgr for test\n"

This adds the selftest for the EFI_RAM_DISK_PROTOCOL.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- No update since v1
lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ 2 files changed, 512 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index e4d75420bf..899f2278d5 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -70,6 +70,7 @@ endif
ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy) obj-y += efi_selftest_block_device.o +obj-$(CONFIG_EFI_RAM_DISK_PROTOCOL) += efi_selftest_ram_disk.o endif
obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o diff --git a/lib/efi_selftest/efi_selftest_ram_disk.c b/lib/efi_selftest/efi_selftest_ram_disk.c new file mode 100644 index 0000000000..5d6ae1f44f --- /dev/null +++ b/lib/efi_selftest/efi_selftest_ram_disk.c @@ -0,0 +1,511 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_ram_disk + * The disk image defined in efi_selftest_disk_image.h is + * used in this test. + * Most source code originates from efi_selftest_block_device.c. + * + * Copyright (c) 2023, Linaro Limited + */ + +#include <efi_selftest.h> +#include "efi_selftest_disk_image.h" +#include <asm/cache.h> + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +static struct efi_boot_services *boottime; + +static const efi_guid_t block_io_protocol_guid = EFI_BLOCK_IO_PROTOCOL_GUID; +static const efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID; +static const efi_guid_t guid_simple_file_system_protocol = + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +static const efi_guid_t guid_file_system_info = EFI_FILE_SYSTEM_INFO_GUID; +static const efi_guid_t guid_ram_disk_protocol = EFI_RAM_DISK_PROTOCOL_GUID; +static efi_guid_t guid_virtual_disk = EFI_VIRTUAL_DISK_GUID; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed disk image */ +struct compressed_disk_image { + size_t length; + struct line lines[]; +}; + +static const struct compressed_disk_image img = EFI_ST_DISK_IMG; + +/* Decompressed disk image */ +static u8 *image; +static u8 *image2; + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * Return: status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * Return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + + decompress(&image); + decompress(&image2); + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t r; + + if (image) { + r = boottime->free_pool(image); + if (r != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + if (image2) { + r = boottime->free_pool(image2); + if (r != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Get length of device path without end tag. + * + * @dp device path + * Return: length of device path in bytes + */ +static efi_uintn_t dp_size(struct efi_device_path *dp) +{ + struct efi_device_path *pos = dp; + + while (pos->type != DEVICE_PATH_TYPE_END) + pos = (struct efi_device_path *)((char *)pos + pos->length); + return (char *)pos - (char *)dp; +} + +/* + * Execute unit test. + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + struct efi_device_path *ram_disk_dp, *ram_disk_dp2; + struct efi_ram_disk_protocol *ram_disk = NULL; + efi_uintn_t no_handles, i, len; + efi_handle_t *handles; + efi_handle_t handle_partition = NULL; + struct efi_device_path *dp_partition; + struct efi_block_io *block_io_protocol; + struct efi_simple_file_system_protocol *file_system; + struct efi_file_handle *root, *file; + struct { + struct efi_file_system_info info; + u16 label[12]; + } system_info; + efi_uintn_t buf_size; + char buf[16] __aligned(ARCH_DMA_MINALIGN); + u32 part1_size; + u64 pos; + char block_io_aligned[1 << LB_BLOCK_SIZE] __aligned(1 << LB_BLOCK_SIZE); + + /* load first disk image */ + ret = boottime->locate_protocol(&guid_ram_disk_protocol, NULL, (void **)&ram_disk); + if (ret != EFI_SUCCESS || !ram_disk) { + efi_st_error("Failed to locate ram disk protocol\n"); + return EFI_ST_FAILURE; + } + ret = ram_disk->disk_register((u64)image, img.length, &guid_virtual_disk, + NULL, &ram_disk_dp); + if (ret != EFI_SUCCESS || !ram_disk_dp) { + efi_st_error("Failed to register ram disk image\n"); + return EFI_ST_FAILURE; + } + + /* Get the handle for the partition */ + ret = boottime->locate_handle_buffer( + BY_PROTOCOL, &guid_device_path, NULL, + &no_handles, &handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to locate handles\n"); + return EFI_ST_FAILURE; + } + len = dp_size(ram_disk_dp); + for (i = 0; i < no_handles; ++i) { + ret = boottime->open_protocol(handles[i], &guid_device_path, + (void **)&dp_partition, + NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open device path protocol\n"); + return EFI_ST_FAILURE; + } + if (len >= dp_size(dp_partition)) + continue; + if (memcmp(ram_disk_dp, dp_partition, len)) + continue; + handle_partition = handles[i]; + break; + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free pool memory\n"); + return EFI_ST_FAILURE; + } + if (!handle_partition) { + efi_st_error("Partition handle not found\n"); + return EFI_ST_FAILURE; + } + + /* Open the block_io_protocol */ + ret = boottime->open_protocol(handle_partition, + &block_io_protocol_guid, + (void **)&block_io_protocol, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open block IO protocol\n"); + return EFI_ST_FAILURE; + } + /* Get size of first MBR partition */ + memcpy(&part1_size, image + 0x1ca, sizeof(u32)); + if (block_io_protocol->media->last_block != part1_size - 1) { + efi_st_error("Last LBA of partition %x, expected %x\n", + (unsigned int)block_io_protocol->media->last_block, + part1_size - 1); + return EFI_ST_FAILURE; + } + /* Open the simple file system protocol */ + ret = boottime->open_protocol(handle_partition, + &guid_simple_file_system_protocol, + (void **)&file_system, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open simple file system protocol\n"); + return EFI_ST_FAILURE; + } + + /* Open volume */ + ret = file_system->open_volume(file_system, &root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open volume\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(system_info); + ret = root->getinfo(root, &guid_file_system_info, &buf_size, + &system_info); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to get file system info\n"); + return EFI_ST_FAILURE; + } + if (system_info.info.block_size != 512) { + efi_st_error("Wrong block size %u, expected 512\n", + system_info.info.block_size); + return EFI_ST_FAILURE; + } + if (efi_st_strcmp_16_8(system_info.info.volume_label, "U-BOOT TEST")) { + efi_st_todo( + "Wrong volume label '%ps', expected 'U-BOOT TEST'\n", + system_info.info.volume_label); + } + + /* Read file */ + ret = root->open(root, &file, u"hello.txt", EFI_FILE_MODE_READ, + 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + ret = file->setpos(file, 1); + if (ret != EFI_SUCCESS) { + efi_st_error("SetPosition failed\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(buf) - 1; + ret = file->read(file, &buf_size, buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to read file\n"); + return EFI_ST_FAILURE; + } + if (buf_size != 12) { + efi_st_error("Wrong number of bytes read: %u\n", + (unsigned int)buf_size); + return EFI_ST_FAILURE; + } + if (memcmp(buf, "ello world!", 11)) { + efi_st_error("Unexpected file content\n"); + return EFI_ST_FAILURE; + } + ret = file->getpos(file, &pos); + if (ret != EFI_SUCCESS) { + efi_st_error("GetPosition failed\n"); + return EFI_ST_FAILURE; + } + if (pos != 13) { + efi_st_error("GetPosition returned %u, expected 13\n", + (unsigned int)pos); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } + + /* + * Test that read_blocks() can read same file data. + * + * In the test data, the partition starts at block 1 and the file + * hello.txt with the content 'Hello world!' is located at 0x5000 + * of the disk. Here we read block 0x27 (offset 0x4e00 of the + * partition) and expect the string 'Hello world!' to be at the + * start of block. + */ + ret = block_io_protocol->read_blocks(block_io_protocol, + block_io_protocol->media->media_id, + (0x5000 >> LB_BLOCK_SIZE) - 1, + block_io_protocol->media->block_size, + block_io_aligned); + if (ret != EFI_SUCCESS) { + efi_st_error("ReadBlocks failed\n"); + return EFI_ST_FAILURE; + } + + if (memcmp(block_io_aligned + 1, buf, 11)) { + efi_st_error("Unexpected block content\n"); + return EFI_ST_FAILURE; + } + +#ifdef CONFIG_FAT_WRITE + /* Write file */ + ret = root->open(root, &file, u"u-boot.txt", EFI_FILE_MODE_READ | + EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + buf_size = 7; + boottime->set_mem(buf, sizeof(buf), 0); + boottime->copy_mem(buf, "U-Boot", buf_size); + ret = file->write(file, &buf_size, buf); + if (ret != EFI_SUCCESS || buf_size != 7) { + efi_st_error("Failed to write file\n"); + return EFI_ST_FAILURE; + } + ret = file->getpos(file, &pos); + if (ret != EFI_SUCCESS) { + efi_st_error("GetPosition failed\n"); + return EFI_ST_FAILURE; + } + if (pos != 7) { + efi_st_error("GetPosition returned %u, expected 7\n", + (unsigned int)pos); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } + + /* Verify file */ + boottime->set_mem(buf, sizeof(buf), 0); + ret = root->open(root, &file, u"u-boot.txt", EFI_FILE_MODE_READ, + 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(buf) - 1; + ret = file->read(file, &buf_size, buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to read file\n"); + return EFI_ST_FAILURE; + } + if (buf_size != 7) { + efi_st_error("Wrong number of bytes read: %u\n", + (unsigned int)buf_size); + return EFI_ST_FAILURE; + } + if (memcmp(buf, "U-Boot", 7)) { + efi_st_error("Unexpected file content %s\n", buf); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } +#else + efi_st_todo("CONFIG_FAT_WRITE is not set\n"); +#endif /* CONFIG_FAT_WRITE */ + + /* Close volume */ + ret = root->close(root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close volume\n"); + return EFI_ST_FAILURE; + } + +#ifdef CONFIG_FAT_WRITE + /* load second disk image, then check the disk image is same as original */ + ret = ram_disk->disk_register((u64)image2, img.length, + &guid_virtual_disk, NULL, &ram_disk_dp2); + if (ret != EFI_SUCCESS || !ram_disk_dp2) { + efi_st_error("Failed to register ram disk image\n"); + return EFI_ST_FAILURE; + } + + /* Get the handle for the partition */ + ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid_device_path, + NULL, &no_handles, &handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to locate handles\n"); + return EFI_ST_FAILURE; + } + len = dp_size(ram_disk_dp2); + for (i = 0; i < no_handles; ++i) { + ret = boottime->open_protocol(handles[i], &guid_device_path, + (void **)&dp_partition, NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open device path protocol\n"); + return EFI_ST_FAILURE; + } + if (len >= dp_size(dp_partition)) + continue; + if (memcmp(ram_disk_dp2, dp_partition, len)) + continue; + handle_partition = handles[i]; + break; + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free pool memory\n"); + return EFI_ST_FAILURE; + } + if (!handle_partition) { + efi_st_error("Partition handle not found\n"); + return EFI_ST_FAILURE; + } + + /* Open the block_io_protocol */ + ret = boottime->open_protocol(handle_partition, &block_io_protocol_guid, + (void **)&block_io_protocol, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open block IO protocol\n"); + return EFI_ST_FAILURE; + } + + /* Open the simple file system protocol */ + ret = boottime->open_protocol(handle_partition, + &guid_simple_file_system_protocol, + (void **)&file_system, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open simple file system protocol\n"); + return EFI_ST_FAILURE; + } + + /* Open volume */ + ret = file_system->open_volume(file_system, &root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open volume\n"); + return EFI_ST_FAILURE; + } + + boottime->set_mem(buf, sizeof(buf), 0); + ret = root->open(root, &file, u"u-boot.txt", EFI_FILE_MODE_READ, 0); + if (ret == EFI_SUCCESS) { + efi_st_error("wrong image loaded\n"); + return EFI_ST_FAILURE; + } + + /* Close volume */ + ret = root->close(root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close volume\n"); + return EFI_ST_FAILURE; + } + + /* unload disk images */ + ret = ram_disk->unregister(ram_disk_dp); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unregister ramdisk\n"); + return EFI_ST_FAILURE; + } + ret = ram_disk->unregister(ram_disk_dp2); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unregister ramdisk2\n"); + return EFI_ST_FAILURE; + } +#endif + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(ramdisk) = { + .name = "ramdisk", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +};

Hi Masahisa,
On fre, jul 14, 2023 at 14:44, Masahisa Kojima masahisa.kojima@linaro.org wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image.
A while back, I added the blkmap command and backend to U-Boot, which is, among other things, capable of creating ramdisks. What exactly does this series add that can't be supported by a block map? There is some documentation available here:

Hi Tobias,
On Sat, 15 Jul 2023 at 07:01, Tobias Waldekranz tobias@waldekranz.com wrote:
Hi Masahisa,
On fre, jul 14, 2023 at 14:44, Masahisa Kojima masahisa.kojima@linaro.org wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image.
A while back, I added the blkmap command and backend to U-Boot, which is, among other things, capable of creating ramdisks. What exactly does this series add that can't be supported by a block map? There is some documentation available here:
Thank you for your comment. I am not aware of the blkmap feature. Yes, I can use blkmap for creating ramdisk.
Thanks, Masahisa Kojima
participants (4)
-
Heinrich Schuchardt
-
Masahisa Kojima
-
Simon Glass
-
Tobias Waldekranz