From cc0d52bde775c68e646987bd725048103ac11373 Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Wed, 22 Jul 2026 22:57:49 +0800 Subject: [PATCH 1/2] [dm][block] add 4K support for EFI partion Signed-off-by: GuEe-GUI <2991707448@qq.com> --- components/drivers/block/partitions/efi.c | 124 +++++++++++++++++++--- 1 file changed, 109 insertions(+), 15 deletions(-) diff --git a/components/drivers/block/partitions/efi.c b/components/drivers/block/partitions/efi.c index 22f6ba16591..92088c8f202 100644 --- a/components/drivers/block/partitions/efi.c +++ b/components/drivers/block/partitions/efi.c @@ -171,29 +171,106 @@ static int is_pmbr_valid(legacy_mbr *mbr, rt_size_t total_sectors) static rt_size_t read_lba(struct rt_blk_disk *disk, rt_uint64_t lba, rt_uint8_t *buffer, rt_size_t count) { + rt_uint32_t lbs; + rt_ssize_t cap_ss, lbs_ss; rt_size_t totalreadcount = 0; + rt_uint8_t *secbuf = RT_NULL; + rt_uint64_t capacity, disk_bytes, n512; - if (!buffer || lba > last_lba(disk)) + if (!buffer || count == 0) { return 0; } - for (rt_uint64_t n = lba; count; ++n) + cap_ss = rt_blk_disk_get_capacity(disk); + lbs_ss = rt_blk_disk_get_logical_block_size(disk); + if (cap_ss < 0 || lbs_ss < 0) + { + return 0; + } + + lbs = (rt_uint32_t)lbs_ss; + capacity = (rt_uint64_t)cap_ss; + + if (lbs < 512 || (lbs % 512) != 0) + { + return 0; + } + + if (lba >= capacity) + { + return 0; + } + + disk_bytes = capacity * (rt_uint64_t)lbs; + n512 = lba * ((rt_uint64_t)lbs / 512); + + secbuf = rt_malloc(lbs); + if (!secbuf) + { + return 0; + } + + while (count > 0) { int copied = 512; + rt_ssize_t rd; + rt_uint32_t off; + rt_uint64_t log_sec, byte_off = n512 * 512; + + if (byte_off >= disk_bytes) + { + break; + } + + if (copied > (int)count) + { + copied = (int)count; + } + + if ((rt_uint64_t)copied > disk_bytes - byte_off) + { + copied = (int)(disk_bytes - byte_off); + } - disk->ops->read(disk, n, buffer, 1); + log_sec = byte_off / lbs; + off = (rt_uint32_t)(byte_off % lbs); - if (copied > count) + if (off + (rt_uint32_t)copied <= lbs) + { + rd = disk->ops->read(disk, (rt_off_t)log_sec, secbuf, 1); + if (rd != 1) + { + break; + } + rt_memcpy(buffer, secbuf + off, copied); + } + else { - copied = count; + rt_uint32_t first = lbs - off; + + rd = disk->ops->read(disk, (rt_off_t)log_sec, secbuf, 1); + if (rd != 1) + { + break; + } + rt_memcpy(buffer, secbuf + off, first); + + rd = disk->ops->read(disk, (rt_off_t)(log_sec + 1), secbuf, 1); + if (rd != 1) + { + break; + } + rt_memcpy(buffer + first, secbuf, copied - first); } buffer += copied; totalreadcount += copied; count -= copied; + ++n512; } + rt_free(secbuf); return totalreadcount; } @@ -255,7 +332,14 @@ static gpt_entry *alloc_read_gpt_entries(struct rt_blk_disk *disk, static gpt_header *alloc_read_gpt_header(struct rt_blk_disk *disk, rt_uint64_t lba) { gpt_header *gpt; - rt_uint32_t ssz = rt_blk_disk_get_logical_block_size(disk); + rt_uint32_t ssz; + rt_ssize_t lbs_ss = rt_blk_disk_get_logical_block_size(disk); + + if (lbs_ss <= 0) + { + return RT_NULL; + } + ssz = (rt_uint32_t)lbs_ss; gpt = rt_malloc(ssz); @@ -316,13 +400,17 @@ static rt_bool_t is_gpt_valid(struct rt_blk_disk *disk, /* Check the GUID Partition Table header size is too big */ logical_block_size = rt_blk_disk_get_logical_block_size(disk); + if (logical_block_size <= 0) + { + goto _fail; + } - if (rt_le32_to_cpu((*gpt)->header_size) > logical_block_size) + if (rt_le32_to_cpu((*gpt)->header_size) > (rt_uint32_t)logical_block_size) { LOG_D("%s: GUID Partition Table Header size is too large: %u > %u", to_disk_name(disk), rt_le32_to_cpu((*gpt)->header_size), - logical_block_size); + (rt_uint32_t)logical_block_size); goto _fail; } @@ -411,11 +499,6 @@ static rt_bool_t is_gpt_valid(struct rt_blk_disk *disk, pt_size = (rt_uint64_t)rt_le32_to_cpu((*gpt)->num_partition_entries) * rt_le32_to_cpu((*gpt)->sizeof_partition_entry); - if (pt_size > (rt_uint64_t)RT_UINT32_MAX) - { - goto _fail; - } - if (!(*ptes = alloc_read_gpt_entries(disk, *gpt))) { goto _fail; @@ -611,7 +694,8 @@ static rt_bool_t find_valid_gpt(struct rt_blk_disk *disk, gpt_header *pgpt = RT_NULL, *agpt = RT_NULL; gpt_entry *pptes = RT_NULL, *aptes = RT_NULL; legacy_mbr *legacymbr; - rt_size_t total_sectors = rt_blk_disk_get_capacity(disk); + rt_ssize_t cap_ss = rt_blk_disk_get_capacity(disk); + rt_size_t total_sectors; rt_size_t lastlba; if (!ptes) @@ -619,6 +703,12 @@ static rt_bool_t find_valid_gpt(struct rt_blk_disk *disk, return RT_FALSE; } + if (cap_ss < 0) + { + return RT_FALSE; + } + total_sectors = (rt_size_t)cap_ss; + lastlba = last_lba(disk); if (!force_gpt) @@ -631,7 +721,11 @@ static rt_bool_t find_valid_gpt(struct rt_blk_disk *disk, return RT_FALSE; } - read_lba(disk, 0, (rt_uint8_t *)legacymbr, sizeof(*legacymbr)); + if (read_lba(disk, 0, (rt_uint8_t *)legacymbr, sizeof(*legacymbr)) < sizeof(*legacymbr)) + { + rt_free(legacymbr); + return RT_FALSE; + } good_pmbr = is_pmbr_valid(legacymbr, total_sectors); rt_free(legacymbr); From ab4348e7d4de1a99df76ad29b7cb1da0fbc4b2aa Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Wed, 22 Jul 2026 22:59:57 +0800 Subject: [PATCH 2/2] [dm][ufs] fixup the linkup flow Signed-off-by: GuEe-GUI <2991707448@qq.com> --- components/drivers/include/drivers/ufs.h | 11 ++ components/drivers/ufs/ufs.c | 149 +++++++++++++++++++---- components/drivers/ufs/ufs_pm.c | 36 ++++++ 3 files changed, 170 insertions(+), 26 deletions(-) diff --git a/components/drivers/include/drivers/ufs.h b/components/drivers/include/drivers/ufs.h index c38de94e4ab..b4ed3c6c1e5 100755 --- a/components/drivers/include/drivers/ufs.h +++ b/components/drivers/include/drivers/ufs.h @@ -542,6 +542,7 @@ struct rt_ufs_ops rt_err_t (*init)(struct rt_ufs_host *ufs); rt_err_t (*exit)(struct rt_ufs_host *ufs); rt_err_t (*reset)(struct rt_ufs_host *ufs); + rt_err_t (*hce_enable_notify)(struct rt_ufs_host *ufs, enum rt_ufs_notify_change_status status); rt_err_t (*link_startup_notify)(struct rt_ufs_host *ufs, enum rt_ufs_notify_change_status status); }; @@ -587,6 +588,16 @@ void rt_ufs_pm_post_linkup(struct rt_ufs_host *ufs); */ rt_err_t rt_ufs_dme_set(struct rt_ufs_host *ufs, rt_uint32_t attr_sel, rt_uint32_t value); +/** + * @brief UIC DME_RESET + */ +rt_err_t rt_ufs_dme_reset(struct rt_ufs_host *ufs); + +/** + * @brief UIC DME_ENABLE + */ +rt_err_t rt_ufs_dme_enable(struct rt_ufs_host *ufs); + /** * @brief UIC DME_GET * diff --git a/components/drivers/ufs/ufs.c b/components/drivers/ufs/ufs.c index 9c35e32f9ed..a860c5f4bd3 100755 --- a/components/drivers/ufs/ufs.c +++ b/components/drivers/ufs/ufs.c @@ -35,6 +35,88 @@ /* UTRD dword_0 command type bits */ #define RT_UFS_UTRD_CMD_TYPE_SCSI (1U << RT_UFS_UPIU_COMMAND_TYPE_OFFSET) +static rt_err_t ufs_wait_hce(struct rt_ufs_host *ufs) +{ + rt_tick_t deadline = rt_tick_get() + rt_tick_from_millisecond(1000); + + while (!(HWREG32(ufs->regs + RT_UFS_REG_HCE) & 0x1)) + { + if (rt_tick_get() >= deadline) + { + LOG_E("%s: UFS HCE enable timeout", rt_dm_dev_get_name(ufs->parent.dev)); + return -RT_ETIMEOUT; + } + + rt_thread_mdelay(1); + } + + return RT_EOK; +} + +static rt_err_t ufs_link_startup(struct rt_ufs_host *ufs) +{ + rt_err_t err; + rt_uint32_t value = 0; + + if (ufs->ops->link_startup_notify) + { + ufs->ops->link_startup_notify(ufs, RT_UFS_NOTIFY_CHANGE_STATUS_PRE); + } + + err = rt_ufs_uic_cmd_send(ufs, RT_UFS_CMDOP_DME_LINKSTARTUP, 0, &value, 0); + + if (ufs->ops->link_startup_notify) + { + ufs->ops->link_startup_notify(ufs, RT_UFS_NOTIFY_CHANGE_STATUS_POST); + } + + return err; +} + +static rt_err_t ufs_wait_utrd_complete(struct rt_ufs_host *ufs, rt_tick_t timeout) +{ + rt_tick_t deadline = rt_tick_get() + timeout; + rt_bool_t db_seen = RT_FALSE; + + while (rt_tick_get() < deadline) + { + rt_uint32_t is = HWREG32(ufs->regs + RT_UFS_REG_IS); + rt_uint32_t db = HWREG32(ufs->regs + RT_UFS_REG_UTRLDBR); + + if (db & RT_BIT(RT_UFS_SLOT_ID)) + { + db_seen = RT_TRUE; + } + + if ((ufs->irq_status | is) & RT_UFS_REG_IS_UTRCS) + { + ufs->irq_status &= ~RT_UFS_REG_IS_UTRCS; + HWREG32(ufs->regs + RT_UFS_REG_IS) = RT_UFS_REG_IS_UTRCS; + return RT_EOK; + } + + if (db_seen && !(db & RT_BIT(RT_UFS_SLOT_ID))) + { + return RT_EOK; + } + + if ((ufs->irq_status | is) & (RT_UFS_REG_IS_UTPES | RT_UFS_REG_IS_DFES | RT_UFS_REG_IS_UE)) + { + return -RT_ERROR; + } + + rt_thread_mdelay(1); + } + + return -RT_ETIMEOUT; +} + +static rt_uint8_t ufs_utrd_ocs(struct rt_ufs_host *ufs) +{ + rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, ufs->utrd, sizeof(*ufs->utrd)); + return rt_le32_to_cpu(ufs->utrd->header.dword_2) & 0xf; +} + static rt_uint8_t ufs_scsi_cmd_data_dir(struct rt_scsi_cmd *cmd) { switch (cmd->op.unknow.opcode) @@ -318,12 +400,16 @@ static rt_err_t ufs_utp_transfer(struct rt_ufs_host *ufs, struct rt_scsi_device HWREG32(regs + RT_UFS_REG_UTRLDBR) = RT_BIT(RT_UFS_SLOT_ID); rt_spin_unlock(&ufs->lock); - /* Interrupt mode: wait for completion signaled by ISR */ - if ((err = rt_completion_wait(&ufs->done, rt_tick_from_millisecond(RT_UFS_UTP_TIMEOUT_MS)))) + /* + * Poll UTRCS directly. QEMU and some PCI hosts may complete the transfer + * before the INTx/MSI handler is wired up during early probe. + */ + if ((err = ufs_wait_utrd_complete(ufs, rt_tick_from_millisecond(RT_UFS_UTP_TIMEOUT_MS)))) { - LOG_E("%s: UFS UTP wait timeout: IS=%#08x irq_status=%#08x", + LOG_E("%s: UFS UTP wait timeout: IS=%#08x irq_status=%#08x UTRLDBR=%#08x OCS=%#x", rt_dm_dev_get_name(ufs->parent.dev), - HWREG32(regs + RT_UFS_REG_IS), ufs->irq_status); + HWREG32(regs + RT_UFS_REG_IS), ufs->irq_status, + HWREG32(regs + RT_UFS_REG_UTRLDBR), ufs_utrd_ocs(ufs)); /* Dump UPIU header and PRDT entry for post-mortem */ LOG_E("%s: UTP UPIU: tx=%u flags=%#02x lun=%u tag=%u seg_len(be16)=%u", @@ -334,16 +420,18 @@ static rt_err_t ufs_utp_transfer(struct rt_ufs_host *ufs, struct rt_scsi_device if (cmd->data.size > 0) { + struct rt_ufs_sg_entry *prd = ((struct rt_utp_transfer_cmd_desc *)ufs->ucd_base)->prd_table; + LOG_E("%s: UTP PRDT[0]: addr=%#llx size(le32)=%#08x", rt_dm_dev_get_name(ufs->parent.dev), - (rt_uint64_t)(&((struct rt_utp_transfer_cmd_desc *)ufs->ucd_base)->prd_table[0])->addr, - (&((struct rt_utp_transfer_cmd_desc *)ufs->ucd_base)->prd_table[0])->size); + (unsigned long long)rt_le64_to_cpu(prd[0].addr), + rt_le32_to_cpu(prd[0].size)); } goto _end; } - is = ufs->irq_status | HWREG32(regs + RT_UFS_REG_IS); + is = HWREG32(regs + RT_UFS_REG_IS); if (is & (RT_UFS_REG_IS_UTPES | RT_UFS_REG_IS_DFES | RT_UFS_REG_IS_UE)) { err = -RT_ERROR; @@ -423,8 +511,16 @@ static rt_err_t ufs_utp_transfer(struct rt_ufs_host *ufs, struct rt_scsi_device goto _end; } - if (rsp->header.status != 0) + /* + * SCSI status lives in the response UPIU header. CHECK CONDITION (0x02) + * may still carry valid data; sense is handled by the SCSI core if needed. + */ + if (rsp->header.status != 0 && rsp->header.status != 0x02) { + LOG_E("%s: UFS SCSI status=%#02x sense_len=%u", + rt_dm_dev_get_name(ufs->parent.dev), + rsp->header.status, + rt_be16_to_cpu(rsp->sr.sense_data_len)); err = -RT_ERROR; goto _end; } @@ -527,7 +623,6 @@ static void ufs_isr(int irqno, void *param) rt_err_t rt_ufs_host_register(struct rt_ufs_host *ufs) { rt_err_t err; - rt_uint32_t value; char dev_name[RT_NAME_MAX]; struct rt_scsi_host *scsi; @@ -585,11 +680,21 @@ rt_err_t rt_ufs_host_register(struct rt_ufs_host *ufs) goto _fail; } + if (ufs->ops->hce_enable_notify && + (err = ufs->ops->hce_enable_notify(ufs, RT_UFS_NOTIFY_CHANGE_STATUS_PRE))) + { + goto _fail; + } + /* Enable controller (HCE 1) */ HWREG32(ufs->regs + RT_UFS_REG_HCE) = 0; rt_thread_mdelay(1); HWREG32(ufs->regs + RT_UFS_REG_HCE) = 0x1; - rt_thread_mdelay(1); + + if ((err = ufs_wait_hce(ufs))) + { + goto _fail; + } /* Program UTRD/UTMRD list base addresses */ HWREG32(ufs->regs + RT_UFS_REG_UTRLBA) = rt_lower_32_bits(ufs->utrl_handle); @@ -611,24 +716,16 @@ rt_err_t rt_ufs_host_register(struct rt_ufs_host *ufs) HWREG32(ufs->regs + RT_UFS_REG_UTRLRSR) = 0x1; HWREG32(ufs->regs + RT_UFS_REG_UTMRLRSR) = 0x1; - /* Link startup: set UTRLRDY/UTMRLRDY */ - value = HWREG32(ufs->regs + RT_UFS_REG_HCS); - if (!(value & RT_UFS_REG_HCS_UTRLRDY) || !(value & RT_UFS_REG_HCS_UTMRLRDY) || !(value & RT_UFS_REG_HCS_UCRDY)) + if (ufs->ops->hce_enable_notify && + (err = ufs->ops->hce_enable_notify(ufs, RT_UFS_NOTIFY_CHANGE_STATUS_POST))) { - if (ufs->ops->link_startup_notify) - { - ufs->ops->link_startup_notify(ufs, RT_UFS_NOTIFY_CHANGE_STATUS_PRE); - } - - if ((err = rt_ufs_uic_cmd_send(ufs, RT_UFS_CMDOP_DME_LINKSTARTUP, 0, &value, 0))) - { - goto _fail; - } + goto _fail; + } - if (ufs->ops->link_startup_notify) - { - ufs->ops->link_startup_notify(ufs, RT_UFS_NOTIFY_CHANGE_STATUS_POST); - } + /* Link startup: required before the first SCSI/UTP transfer */ + if ((err = ufs_link_startup(ufs))) + { + goto _fail; } ufs->pwr_active_valid = 0; diff --git a/components/drivers/ufs/ufs_pm.c b/components/drivers/ufs/ufs_pm.c index 86284efee02..74b35589a75 100755 --- a/components/drivers/ufs/ufs_pm.c +++ b/components/drivers/ufs/ufs_pm.c @@ -43,6 +43,42 @@ rt_err_t rt_ufs_dme_set(struct rt_ufs_host *ufs, rt_uint32_t attr_sel, rt_uint32 return RT_EOK; } +rt_err_t rt_ufs_dme_reset(struct rt_ufs_host *ufs) +{ + rt_err_t err; + rt_uint32_t arg2 = 0; + + if ((err = rt_ufs_uic_cmd_send(ufs, RT_UFS_CMDOP_DME_RESET, 0, &arg2, 0))) + { + return err; + } + + if ((arg2 & RT_UFS_CMDRES_MASK) != RT_UFS_CMDRES_SUCCESS) + { + return -RT_ERROR; + } + + return RT_EOK; +} + +rt_err_t rt_ufs_dme_enable(struct rt_ufs_host *ufs) +{ + rt_err_t err; + rt_uint32_t arg2 = 0; + + if ((err = rt_ufs_uic_cmd_send(ufs, RT_UFS_CMDOP_DME_ENABLE, 0, &arg2, 0))) + { + return err; + } + + if ((arg2 & RT_UFS_CMDRES_MASK) != RT_UFS_CMDRES_SUCCESS) + { + return -RT_ERROR; + } + + return RT_EOK; +} + rt_err_t rt_ufs_dme_get(struct rt_ufs_host *ufs, rt_uint32_t attr_sel, rt_uint32_t *value) { rt_uint32_t arg2 = 0;