From d6926f5c7ee4c3f9dda78762a3f59a5afa867963 Mon Sep 17 00:00:00 2001 From: Jianquan Lin Date: Tue, 9 Dec 2025 09:56:40 +0800 Subject: [PATCH 1/4] ub:hisi-ubus: Fix ue reg/unreg without lock bug drivers inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ID700V CVE: NA ------------------------------------------------------------ Currently, UE registration and deregistration are not performed under the protection of the MUE device lock. When the MUE performs a reset, there is a risk of concurrent resource conflicts. Fixes: 86fec00cb73a ("ub:hisi-ubus: Support UBUS vdm entity enable message") Signed-off-by: Junlong Zheng Signed-off-by: Jianquan Lin --- drivers/ub/ubus/vendor/hisilicon/vdm.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/ub/ubus/vendor/hisilicon/vdm.c b/drivers/ub/ubus/vendor/hisilicon/vdm.c index f95da0843e26..4a19e0fb8d57 100644 --- a/drivers/ub/ubus/vendor/hisilicon/vdm.c +++ b/drivers/ub/ubus/vendor/hisilicon/vdm.c @@ -14,8 +14,6 @@ #include "hisi-ubus.h" #include "vdm.h" -static DEFINE_SPINLOCK(ub_vdm_lock); - struct opcode_func_map { u16 sub_opcode; u16 idev_pkt_size; @@ -274,6 +272,7 @@ static u8 ub_idevice_ue_add_handler(struct ub_bus_controller *ubc, struct vdm_ms struct ub_entity *pue, *alloc_dev = NULL; u16 ue_entity_idx = pld->ue_entity_idx; int start_idx, end_idx, ret; + int lock = 0; u8 status; /* check whether pue is registered. */ @@ -306,10 +305,13 @@ static u8 ub_idevice_ue_add_handler(struct ub_bus_controller *ubc, struct vdm_ms goto ue_reg_rsp; } - spin_lock(&ub_vdm_lock); - ret = ub_idevice_enable_handle(pue, ue_entity_idx, 0, NULL, &alloc_dev); - spin_unlock(&ub_vdm_lock); + lock = device_trylock(&pue->dev); + if (!lock) { + status = UB_MSG_RSP_EXEC_EBUSY; + goto ue_reg_rsp; + } + ret = ub_idevice_enable_handle(pue, ue_entity_idx, 0, NULL, &alloc_dev); if (ret == 0) { alloc_dev->user_eid = pld->user_eid[0]; ub_info(pue, "enable idev ue succeeded, user_eid=0x%x\n", @@ -331,6 +333,9 @@ static u8 ub_idevice_ue_add_handler(struct ub_bus_controller *ubc, struct vdm_ms pue->num_ues += 1; } + if (lock) + device_unlock(&pue->dev); + return status; } @@ -346,6 +351,7 @@ static u8 ub_idevice_ue_rls_handler(struct ub_bus_controller *ubc, struct vdm_ms struct ub_entity *pue, *vd_dev, *tmp; u16 ue_entity_idx = pld->ue_entity_idx; u16 start_idx, end_idx; + int lock = 0; u8 status; /* search for pue with guid. Return an error if pue does not exist */ @@ -372,6 +378,12 @@ static u8 ub_idevice_ue_rls_handler(struct ub_bus_controller *ubc, struct vdm_ms "The pue of this vdm ue to be disabled is normal\n"); } + lock = device_trylock(&pue->dev); + if (!lock) { + status = UB_MSG_RSP_EXEC_EBUSY; + goto ue_rls_rsp; + } + status = UB_MSG_RSP_EXEC_ENODEV; /* otherwise, delete this ue with ue idx in message payload */ list_for_each_entry_safe(vd_dev, tmp, &pue->ue_list, node) @@ -389,6 +401,9 @@ static u8 ub_idevice_ue_rls_handler(struct ub_bus_controller *ubc, struct vdm_ms pue->num_ues -= 1; } + if (lock) + device_unlock(&pue->dev); + return status; } -- Gitee From 3ee6b2906e902998d3bcb476bd812e9d4db8c738 Mon Sep 17 00:00:00 2001 From: Jianquan Lin Date: Tue, 9 Dec 2025 10:29:25 +0800 Subject: [PATCH 2/4] ub:ubus: Delete ubc cfg0 config during cluster mode drivers inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ID700V CVE: NA ----------------------------------------------------------- In cluster mode, the management authority of UBC is primarily held by UBFM. Ubus cannot configure the configuration space of cfg0 except for the vport configuration space. Fixes: 280895301d3b ("ub:ubus: Support Ubus read/write configuration functions") Signed-off-by: Junlong Zheng Signed-off-by: Jianquan Lin --- drivers/ub/ubus/enum.c | 4 +++ drivers/ub/ubus/eu.c | 5 +++- drivers/ub/ubus/instance.c | 12 +++++---- drivers/ub/ubus/pool.c | 7 +++++ drivers/ub/ubus/port.c | 4 +++ drivers/ub/ubus/services/gucd.c | 29 ++++----------------- drivers/ub/ubus/ubus_entity.c | 22 +++++++++------- drivers/ub/ubus/vendor/hisilicon/eu-table.c | 6 +++++ include/uapi/ub/ubus/ubus_regs.h | 5 ---- 9 files changed, 49 insertions(+), 45 deletions(-) diff --git a/drivers/ub/ubus/enum.c b/drivers/ub/ubus/enum.c index 48c37e30ca31..67a87f9f23aa 100644 --- a/drivers/ub/ubus/enum.c +++ b/drivers/ub/ubus/enum.c @@ -1430,6 +1430,10 @@ int ub_enum_entities_active(struct list_head *dev_list) list_del(&uent->node); ub_entity_add(uent, uent->ubc); + + if (is_ibus_controller(uent) && uent->ubc->cluster) + continue; + ub_start_ent(uent); } diff --git a/drivers/ub/ubus/eu.c b/drivers/ub/ubus/eu.c index 97e040eadd5e..5c99d44918e5 100644 --- a/drivers/ub/ubus/eu.c +++ b/drivers/ub/ubus/eu.c @@ -93,7 +93,7 @@ void ub_eu_table_init(struct ub_entity *uent) struct ub_bus_controller *ubc = uent->ubc; int ret; - if (!is_ibus_controller(uent)) + if (!is_ibus_controller(uent) || ubc->cluster) return; ret = ub_eu_table_init_common(uent); @@ -137,6 +137,9 @@ int ub_cfg_eu_table(struct ub_bus_controller *ubc, bool flag, u32 eid, u16 upi) struct ub_bus_controller_ops *ops = ubc->ops; int ret; + if (ubc->cluster) + return 0; + if (!ops || !ops->eu_cfg) return -ENODEV; diff --git a/drivers/ub/ubus/instance.c b/drivers/ub/ubus/instance.c index 8c49c04388e3..342fc9960ef2 100644 --- a/drivers/ub/ubus/instance.c +++ b/drivers/ub/ubus/instance.c @@ -915,15 +915,17 @@ int ub_ioctl_bus_instance_unbind(void __user *uptr) int ub_default_bus_instance_init(struct ub_entity *uent) { - bool m_idev = is_p_idevice(uent); - bool fad = is_p_device(uent); struct ub_bus_instance *bi; + bool use_cluster; int ret; if (is_switch(uent)) return 0; - if (fad || m_idev) { + use_cluster = is_p_device(uent) || is_p_idevice(uent) || + (is_ibus_controller(uent) && uent->ubc->cluster); + + if (use_cluster) { mutex_lock(&dynamic_mutex); bi = ub_find_bus_instance(eid_match, &uent->user_eid); } else { @@ -931,7 +933,7 @@ int ub_default_bus_instance_init(struct ub_entity *uent) } if (!bi) { - if (fad || m_idev) + if (use_cluster) mutex_unlock(&dynamic_mutex); ub_err(uent, "get default bi NULL\n"); return -EINVAL; @@ -941,7 +943,7 @@ int ub_default_bus_instance_init(struct ub_entity *uent) ret = ub_bind_bus_instance(uent, bi); mutex_unlock(&uent->instance_lock); - if (fad || m_idev) { + if (use_cluster) { ub_bus_instance_put(bi); mutex_unlock(&dynamic_mutex); } diff --git a/drivers/ub/ubus/pool.c b/drivers/ub/ubus/pool.c index 414e9dba0c20..4fdd9aca922d 100644 --- a/drivers/ub/ubus/pool.c +++ b/drivers/ub/ubus/pool.c @@ -533,7 +533,14 @@ static void ub_cfg_cpl_notify_handler(struct ub_bus_controller *ubc, void *msg, if (ret) { dev_err(&ubc->dev, "handle notify bi failed, ret=%d\n", ret); rsp_status = err_to_msg_rsp(ret); + goto rsp; + } + + if (!ub_entity_test_priv_flag(ubc->uent, UB_ENTITY_START)) { + ubc->uent->user_eid = notify->eid[0]; + ub_start_ent(ubc->uent); } + rsp: header->msgetah.rsp_status = rsp_status; ub_cfg_cpl_notify_msg_rsp(ubc, header); diff --git a/drivers/ub/ubus/port.c b/drivers/ub/ubus/port.c index a8a238df8cc4..f2ec6e8b9f47 100644 --- a/drivers/ub/ubus/port.c +++ b/drivers/ub/ubus/port.c @@ -353,10 +353,14 @@ static umode_t ub_port_qdlws_is_visible(struct kobject *kobj, struct attribute *a, int n) { struct ub_port *port = to_ub_port(kobj); + struct ub_entity *uent = port->uent; if (port->type == VIRTUAL) return 0; + if (is_ibus_controller(uent) && uent->ubc->cluster) + return 0; + if (test_bit(UB_PORT_CAP15_QDLWS, port->cap_map)) return a->mode; diff --git a/drivers/ub/ubus/services/gucd.c b/drivers/ub/ubus/services/gucd.c index ca5f0a3578e8..a7796bcce6aa 100644 --- a/drivers/ub/ubus/services/gucd.c +++ b/drivers/ub/ubus/services/gucd.c @@ -71,6 +71,9 @@ static int ub_component_service_register(struct ub_entity *uent) int capabilities; int i; + if (is_ibus_controller(uent) && uent->ubc->cluster) + return 0; + /* Get and check component services */ capabilities = get_component_service_capability(uent); if (!capabilities) @@ -91,36 +94,15 @@ static int ub_component_service_register(struct ub_entity *uent) return 0; } -static void ub_enable_err_msq_ctrl(struct ub_entity *uent) -{ - int ret; - - ret = ub_cfg_write_dword(uent, EMQ_CAP_START + UB_CAP_ERR_MSG_QUE_CTL, - UB_CAP_INTERRUPT_GEN_ENA); - if (ret) - ub_err(uent, "enable error msq controller failed\n"); -} - -static void ub_disable_err_msq_ctrl(struct ub_entity *uent) -{ - int ret; - - ret = ub_cfg_write_dword(uent, EMQ_CAP_START + UB_CAP_ERR_MSG_QUE_CTL, - 0x0); - if (ret) - ub_err(uent, "disable error msq controller failed\n"); -} - static void ub_setup_bus_controller(struct ub_entity *uent) { u32 vec_num_max; int usi_count; - if (ub_cc_supported(uent)) + if (ub_cc_supported(uent) && !uent->ubc->cluster) ub_cc_enable(uent); ub_set_user_info(uent); - ub_enable_err_msq_ctrl(uent); vec_num_max = ub_int_type1_vec_count(uent); usi_count = ub_alloc_irq_vectors(uent, vec_num_max, vec_num_max); if (usi_count < 0) { @@ -143,10 +125,9 @@ static void ub_unset_bus_controller(struct ub_entity *uent) ub_mem_uninit_usi(uent); ub_uninit_decoder_usi(uent); ub_disable_intr(uent); - ub_disable_err_msq_ctrl(uent); ub_unset_user_info(uent); - if (ub_cc_supported(uent)) + if (ub_cc_supported(uent) && !uent->ubc->cluster) ub_cc_disable(uent); } diff --git a/drivers/ub/ubus/ubus_entity.c b/drivers/ub/ubus/ubus_entity.c index 4fa1a8533e71..b43d682ba3d8 100644 --- a/drivers/ub/ubus/ubus_entity.c +++ b/drivers/ub/ubus/ubus_entity.c @@ -421,6 +421,11 @@ void ub_entity_add(struct ub_entity *uent, void *ctx) ret = ub_ports_add(uent); WARN_ON(ret); } + + if (is_ibus_controller(uent)) { + ret = ub_static_bus_instance_init(uent->ubc); + WARN_ON(ret); + } } EXPORT_SYMBOL_GPL(ub_entity_add); @@ -432,11 +437,6 @@ void ub_start_ent(struct ub_entity *uent) if (!uent) return; - if (is_ibus_controller(uent)) { - ret = ub_static_bus_instance_init(uent->ubc); - WARN_ON(ret); - } - ret = ub_default_bus_instance_init(uent); WARN_ON(ret); @@ -507,9 +507,6 @@ void ub_stop_ent(struct ub_entity *uent) ub_remove_sysfs_ent_files(uent); ub_default_bus_instance_uninit(uent); - - if (is_ibus_controller(uent)) - ub_static_bus_instance_uninit(uent->ubc); } EXPORT_SYMBOL_GPL(ub_stop_ent); @@ -527,6 +524,9 @@ void ub_remove_ent(struct ub_entity *uent) list_for_each_entry_safe_reverse(ent, tmp, &uent->mue_list, node) ub_remove_ent(ent); + if (is_ibus_controller(uent)) + ub_static_bus_instance_uninit(uent->ubc); + if (is_primary(uent)) ub_ports_del(uent); @@ -1008,7 +1008,8 @@ int ub_set_user_info(struct ub_entity *uent) u32 eid = uent->ubc->uent->eid; - if (is_p_device(uent)) + if (is_p_device(uent) || + (uent->ubc->cluster && is_ibus_controller(uent))) goto cfg1; /* set dsteid to device */ @@ -1033,7 +1034,8 @@ void ub_unset_user_info(struct ub_entity *uent) if (!uent) return; - if (is_p_device(uent)) + if (is_p_device(uent) || + (uent->ubc->cluster && is_ibus_controller(uent))) goto cfg1; ub_cfg_write_dword(uent, UB_UCNA, 0); diff --git a/drivers/ub/ubus/vendor/hisilicon/eu-table.c b/drivers/ub/ubus/vendor/hisilicon/eu-table.c index 6bbdfb0e0bf7..3004093b52d8 100644 --- a/drivers/ub/ubus/vendor/hisilicon/eu-table.c +++ b/drivers/ub/ubus/vendor/hisilicon/eu-table.c @@ -165,12 +165,18 @@ static const struct file_operations hi_eu_table_info_ops = { static void hi_eu_table_debugfs_init(struct ub_bus_controller *ubc) { + if (ubc->cluster) + return; + debugfs_create_file("eu_table", 0600, ubc->debug_root, ubc, &hi_eu_table_info_ops); } static void hi_eu_table_debugfs_uninit(struct ub_bus_controller *ubc) { + if (ubc->cluster) + return; + debugfs_lookup_and_remove("eu_table", ubc->debug_root); } diff --git a/include/uapi/ub/ubus/ubus_regs.h b/include/uapi/ub/ubus/ubus_regs.h index 9eed901fd205..a4fe600f5459 100644 --- a/include/uapi/ub/ubus/ubus_regs.h +++ b/include/uapi/ub/ubus/ubus_regs.h @@ -271,9 +271,4 @@ enum ub_port_cap_id { #define QDLWS_EXEC_STATUS_MASK GENMASK(2, 0) #define QDLWS_EXEC_STATUS_MAX 4 -/* Error Message Queue Capability */ -#define EMQ_CAP_START 0x00001400 -#define UB_CAP_ERR_MSG_QUE_CTL 0x8 -#define UB_CAP_INTERRUPT_GEN_ENA 0x100 - #endif /* _UAPI_UB_UBUS_UBUS_REGS_H_ */ -- Gitee From 68ce3e1d69c339382cf0b8aa95a7e0957c9ce22d Mon Sep 17 00:00:00 2001 From: Yuhao Xiang Date: Tue, 9 Dec 2025 14:31:20 +0800 Subject: [PATCH 3/4] ub:ubus: Matt and MMIO judgments are not performed in cluster drivers inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ID700V CVE: NA ----------------------------------------------------------- Rollback after setting the decoder register fails. Matt and MMIO judgments are not performed in cluster true Fixes: abc591c50df5 ("ub:ubus: Supports decoder event processing") Signed-off-by: Yuhao Xiang --- drivers/ub/ubus/decoder.c | 153 +++++++++++++++++++++++++++----------- drivers/ub/ubus/decoder.h | 1 + 2 files changed, 109 insertions(+), 45 deletions(-) diff --git a/drivers/ub/ubus/decoder.c b/drivers/ub/ubus/decoder.c index 288e33a96038..dbd6191b693a 100644 --- a/drivers/ub/ubus/decoder.c +++ b/drivers/ub/ubus/decoder.c @@ -75,28 +75,68 @@ static int ub_decoder_init_queue(struct ub_bus_controller *ubc, static u32 set_mmio_base_reg(struct ub_decoder *decoder) { - u32 ret; + u32 mmio_high = upper_32_bits(decoder->mmio_base_addr); + u32 mmio_low = lower_32_bits(decoder->mmio_base_addr); + struct ub_entity *ent = decoder->uent; + u32 low_bit, high_bit, ret; + + if (!ent->ubc->cluster) { + ret = (u32)ub_cfg_write_dword(ent, DECODER_MMIO_BA0, + 0xffffffff); + ret |= (u32)ub_cfg_write_dword(ent, DECODER_MMIO_BA1, + 0xffffffff); + ret |= (u32)ub_cfg_read_dword(ent, DECODER_MMIO_BA0, &low_bit); + ret |= (u32)ub_cfg_read_dword(ent, DECODER_MMIO_BA1, &high_bit); + if (ret) { + ub_err(ent, "Failed to access decoder MMIO BA\n"); + return ret; + } + + if ((low_bit | mmio_low) != low_bit || + (high_bit | mmio_high) != high_bit) { + ub_err(ent, "decoder MMIO address does not match HW reg\n"); + return -EINVAL; + } + } ret = (u32)ub_cfg_write_dword(decoder->uent, DECODER_MMIO_BA0, lower_32_bits(decoder->mmio_base_addr)); ret |= (u32)ub_cfg_write_dword(decoder->uent, DECODER_MMIO_BA1, upper_32_bits(decoder->mmio_base_addr)); - if (ret) - ub_err(decoder->uent, "set decoder mmio base failed\n"); return ret; } static u32 set_page_table_reg(struct ub_decoder *decoder) { - u32 ret; + u32 matt_high = upper_32_bits(decoder->pgtlb.pgtlb_dma); + u32 matt_low = lower_32_bits(decoder->pgtlb.pgtlb_dma); + struct ub_entity *ent = decoder->uent; + u32 low_bit, high_bit, ret; + + if (!ent->ubc->cluster) { + ret = (u32)ub_cfg_write_dword(ent, DECODER_MATT_BA0, + 0xffffffff); + ret |= (u32)ub_cfg_write_dword(ent, DECODER_MATT_BA1, + 0xffffffff); + ret |= (u32)ub_cfg_read_dword(ent, DECODER_MATT_BA0, &low_bit); + ret |= (u32)ub_cfg_read_dword(ent, DECODER_MATT_BA1, &high_bit); + if (ret) { + ub_err(ent, "Failed to access decoder MATT BA\n"); + return ret; + } + + if ((low_bit | matt_low) != low_bit || + (high_bit | matt_high) != high_bit) { + ub_err(ent, "decoder MATT address does not match HW reg\n"); + return -EINVAL; + } + } ret = (u32)ub_cfg_write_dword(decoder->uent, DECODER_MATT_BA0, lower_32_bits(decoder->pgtlb.pgtlb_dma)); ret |= (u32)ub_cfg_write_dword(decoder->uent, DECODER_MATT_BA1, upper_32_bits(decoder->pgtlb.pgtlb_dma)); - if (ret) - ub_err(decoder->uent, "set decoder page table reg failed\n"); return ret; } @@ -145,6 +185,25 @@ static u32 set_queue_reg(struct ub_decoder *decoder) return ret; } +static void unset_queue_reg(struct ub_decoder *decoder) +{ + struct ub_entity *uent = decoder->uent; + u32 ret; + + ret = (u32)ub_cfg_write_dword(uent, DECODER_CMDQ_CFG, + decoder->vals.cmdq_cfg_val); + ret |= (u32)ub_cfg_write_dword(uent, DECODER_EVENTQ_CFG, + decoder->vals.evtq_cfg_val); + + ret |= (u32)ub_cfg_write_dword(uent, DECODER_CMDQ_BASE_ADDR0, 0); + ret |= (u32)ub_cfg_write_dword(uent, DECODER_CMDQ_BASE_ADDR1, 0); + + ret |= (u32)ub_cfg_write_dword(uent, DECODER_EVENTQ_BASE_ADDR0, 0); + ret |= (u32)ub_cfg_write_dword(uent, DECODER_EVENTQ_BASE_ADDR1, 0); + if (ret) + ub_err(uent, "unset queue reg fail\n"); +} + static u32 set_decoder_enable(struct ub_decoder *decoder) { u32 ret = (u32)ub_cfg_write_dword(decoder->uent, DECODER_CTRL, 1); @@ -155,6 +214,14 @@ static u32 set_decoder_enable(struct ub_decoder *decoder) return ret; } +static void unset_decoder_enable(struct ub_decoder *decoder) +{ + struct ub_entity *uent = decoder->uent; + + if (ub_cfg_write_dword(uent, DECODER_CTRL, 0)) + ub_err(uent, "unset decoder enable fail\n"); +} + static u32 ub_decoder_device_set(struct ub_decoder *decoder) { u32 ret; @@ -164,6 +231,11 @@ static u32 ub_decoder_device_set(struct ub_decoder *decoder) ret |= set_queue_reg(decoder); ret |= set_decoder_enable(decoder); + if (ret) { + unset_decoder_enable(decoder); + unset_queue_reg(decoder); + } + return ret; } @@ -186,22 +258,26 @@ static void ub_decoder_free_page_table(struct ub_bus_controller *ubc, ub_err(decoder->uent, "ub bus controller can't free decoder table\n"); } - -static void ub_get_decoder_mmio_base(struct ub_bus_controller *ubc, +static int ub_get_decoder_mmio_base(struct ub_bus_controller *ubc, struct ub_decoder *decoder) { struct resource_entry *entry; - decoder->mmio_base_addr = -1; resource_list_for_each_entry(entry, &ubc->resources) { if (entry->res->flags == IORESOURCE_MEM && - strstr(entry->res->name, "UB_BUS_CTL") && - entry->res->start < decoder->mmio_base_addr) + strstr(entry->res->name, "UB_BUS_CTL")) { decoder->mmio_base_addr = entry->res->start; + decoder->mmio_end_addr = entry->res->end; + break; + } } - ub_info(decoder->uent, "decoder mmio base is %#llx\n", - decoder->mmio_base_addr); + if (decoder->mmio_base_addr == 0) { + ub_err(decoder->uent, "get decoder mmio base failed\n"); + return -EINVAL; + } + + return 0; } static const char * const mmio_size_desc[] = { @@ -209,15 +285,21 @@ static const char * const mmio_size_desc[] = { "2Tbyte", "4Tbyte", "8Tbyte", "16Tbyte" }; +static const u64 mmio_size[] = { + 128ULL * SZ_1G, 256ULL * SZ_1G, 512ULL * SZ_1G, SZ_1T, + 2 * SZ_1T, 4 * SZ_1T, 8 * SZ_1T, 16 * SZ_1T +}; + static int ub_get_decoder_cap(struct ub_decoder *decoder) { struct ub_entity *uent = decoder->uent; + u64 size; u32 val; int ret; ret = ub_cfg_read_dword(uent, DECODER_CAP, &val); if (ret) { - ub_err(uent, "read decoder cap failed\n"); + ub_err(uent, "read decoder cap fail\n"); return ret; } @@ -225,9 +307,15 @@ static int ub_get_decoder_cap(struct ub_decoder *decoder) decoder->cmdq.qs = (val & CMDQ_SIZE_MASK) >> CMDQ_SIZE_OFFSET; decoder->evtq.qs = (val & EVTQ_SIZE_MASK) >> EVTQ_SIZE_OFFSET; - ub_dbg(uent, "cmdq_queue_size=%u, evtq_queue_size=%u, mmio_size=%s\n", - decoder->cmdq.qs, decoder->evtq.qs, - mmio_size_desc[decoder->mmio_size_sup]); + size = decoder->mmio_end_addr - decoder->mmio_base_addr + 1; + if (size > mmio_size[decoder->mmio_size_sup]) + decoder->mmio_end_addr = decoder->mmio_base_addr + + mmio_size[decoder->mmio_size_sup] - 1; + + ub_info(uent, "decoder mmio_addr[%#llx-%#llx], cmdq_queue_size=%u, evtq_queue_size=%u, mmio_size_sup=%s\n", + decoder->mmio_base_addr, decoder->mmio_end_addr, + decoder->cmdq.qs, decoder->evtq.qs, + mmio_size_desc[decoder->mmio_size_sup]); return 0; } @@ -245,7 +333,9 @@ static int ub_create_decoder(struct ub_bus_controller *ubc) decoder->uent = uent; mutex_init(&decoder->table_lock); - ub_get_decoder_mmio_base(ubc, decoder); + ret = ub_get_decoder_mmio_base(ubc, decoder); + if (ret) + goto release_decoder; ret = ub_get_decoder_cap(decoder); if (ret) @@ -293,25 +383,6 @@ static void unset_mmio_base_reg(struct ub_decoder *decoder) ub_err(uent, "unset mmio base reg failed\n"); } -static void unset_queue_reg(struct ub_decoder *decoder) -{ - struct ub_entity *uent = decoder->uent; - u32 ret; - - ret = (u32)ub_cfg_write_dword(uent, DECODER_CMDQ_CFG, - decoder->vals.cmdq_cfg_val); - ret |= (u32)ub_cfg_write_dword(uent, DECODER_EVENTQ_CFG, - decoder->vals.evtq_cfg_val); - - ret |= (u32)ub_cfg_write_dword(uent, DECODER_CMDQ_BASE_ADDR0, 0); - ret |= (u32)ub_cfg_write_dword(uent, DECODER_CMDQ_BASE_ADDR1, 0); - - ret |= (u32)ub_cfg_write_dword(uent, DECODER_EVENTQ_BASE_ADDR0, 0); - ret |= (u32)ub_cfg_write_dword(uent, DECODER_EVENTQ_BASE_ADDR1, 0); - if (ret) - ub_err(uent, "unset queue reg failed\n"); -} - static void unset_page_table_reg(struct ub_decoder *decoder) { struct ub_entity *uent = decoder->uent; @@ -323,14 +394,6 @@ static void unset_page_table_reg(struct ub_decoder *decoder) ub_err(uent, "unset page table reg failed\n"); } -static void unset_decoder_enable(struct ub_decoder *decoder) -{ - struct ub_entity *uent = decoder->uent; - - if (ub_cfg_write_dword(uent, DECODER_CTRL, 0)) - ub_err(uent, "unset decoder enable failed\n"); -} - static void ub_decoder_device_unset(struct ub_decoder *decoder) { unset_decoder_enable(decoder); diff --git a/drivers/ub/ubus/decoder.h b/drivers/ub/ubus/decoder.h index 37d628dc45e2..6667d07e9219 100644 --- a/drivers/ub/ubus/decoder.h +++ b/drivers/ub/ubus/decoder.h @@ -72,6 +72,7 @@ struct ub_decoder { struct device *dev; struct ub_entity *uent; phys_addr_t mmio_base_addr; + phys_addr_t mmio_end_addr; u32 mmio_size_sup; u64 rg_size; struct ub_decoder_queue cmdq; -- Gitee From b41f79594e18b9628b1d8d4e50ac1687c9679ecf Mon Sep 17 00:00:00 2001 From: Yuhao Xiang Date: Tue, 9 Dec 2025 20:44:11 +0800 Subject: [PATCH 4/4] ub:ubfi: Fix UBFI memory leak issue drivers inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ID700V CVE: NA ----------------------------------------------------------- UBFI in abnormal branch memory leakage issues and redundant branches Fixes: 312a6b7fabe9 ("ub:ubfi: ubfi driver parse ubc information from ubrt") Signed-off-by: Yuhao Xiang --- drivers/ub/ubfi/ub_fi.c | 42 ++++++++++++------------ drivers/ub/ubfi/ub_fi.h | 7 ++-- drivers/ub/ubfi/ubc.c | 35 ++++++++++---------- drivers/ub/ubfi/ubrt.c | 72 +++++++++++++++++++++++++++-------------- drivers/ub/ubfi/ubrt.h | 4 --- 5 files changed, 89 insertions(+), 71 deletions(-) diff --git a/drivers/ub/ubfi/ub_fi.c b/drivers/ub/ubfi/ub_fi.c index 50b359e52b7b..aa8b69f39dd8 100644 --- a/drivers/ub/ubfi/ub_fi.c +++ b/drivers/ub/ubfi/ub_fi.c @@ -15,16 +15,16 @@ #define ACPI_SIG_UBRT "UBRT" /* UB Root Table */ #define UBIOS_INFO_TABLE "linux,ubios-information-table" -enum bios_report_mode bios_mode = UNKNOWN; +enum firmware_report_mode firmware_mode = UNKNOWN; -static void ub_bios_mode_init(void) +static void ub_firmware_mode_init(void) { if (acpi_disabled) - bios_mode = DTS; + firmware_mode = DTS; else - bios_mode = ACPI; + firmware_mode = ACPI; - pr_info("Starting with mode: %d\n", bios_mode); + pr_info("Starting with mode: %d\n", firmware_mode); } static int ubfi_get_acpi_ubrt(void) @@ -34,14 +34,13 @@ static int ubfi_get_acpi_ubrt(void) status = acpi_get_table(ACPI_SIG_UBRT, 0, &header); if (ACPI_FAILURE(status)) { - pr_err("ACPI failed to get UBRT.\n"); if (status != AE_NOT_FOUND) pr_err("ACPI failed msg: %s\n", acpi_format_exception(status)); return -ENODEV; } acpi_table = (struct acpi_table_ubrt *)header; - pr_info("get ubrt by acpi success\n"); + pr_debug("get ubrt by acpi success\n"); return 0; } @@ -65,35 +64,32 @@ static int ubfi_get_dts_ubrt(void) if (!ubios_table) return -ENOMEM; - pr_info("ubfi get ubrt by device tree success\n"); + pr_debug("ubfi get ubrt by device tree success\n"); return 0; } static int ubfi_get_ubrt(void) { - if (bios_mode == ACPI) + if (firmware_mode == ACPI) return ubfi_get_acpi_ubrt(); - else if (bios_mode == DTS) + else return ubfi_get_dts_ubrt(); - return -EINVAL; } static int handle_ubrt(void) { - if (bios_mode == ACPI) + if (firmware_mode == ACPI) return handle_acpi_ubrt(); - else if (bios_mode == DTS) + else return handle_dts_ubrt(); - - return -EINVAL; } static void ubfi_put_ubrt(void) { - if (bios_mode == ACPI) { + if (firmware_mode == ACPI) { acpi_put_table((struct acpi_table_header *)acpi_table); acpi_table = NULL; - } else if (bios_mode == DTS) { + } else { ub_table_put(ubios_table); ubios_table = NULL; } @@ -103,15 +99,21 @@ static int __init ubfi_init(void) { int ret; - ub_bios_mode_init(); + ub_firmware_mode_init(); ret = ubfi_get_ubrt(); if (ret) { - pr_warn("can't get ub information from bios, ret=%d\n", ret); + pr_warn("can't get ub information from firmware, ret=%d\n", ret); return 0; } - return handle_ubrt(); + ret = handle_ubrt(); + if (ret) { + pr_err("failed to handle ubrt, ret=%d\n", ret); + ubfi_put_ubrt(); + } + + return ret; } static void __exit ubfi_exit(void) diff --git a/drivers/ub/ubfi/ub_fi.h b/drivers/ub/ubfi/ub_fi.h index 3edf8dd6de4e..9d36c308cede 100644 --- a/drivers/ub/ubfi/ub_fi.h +++ b/drivers/ub/ubfi/ub_fi.h @@ -6,12 +6,11 @@ #ifndef __UB_FI_H__ #define __UB_FI_H__ -enum bios_report_mode { +enum firmware_report_mode { ACPI = 0, DTS = 1, - UBIOS = 3, - UNKNOWN = 4, + UNKNOWN = 2 }; -extern enum bios_report_mode bios_mode; +extern enum firmware_report_mode firmware_mode; #endif /* __UB_FI_H__ */ diff --git a/drivers/ub/ubfi/ubc.c b/drivers/ub/ubfi/ubc.c index a3f7bab8863f..3a160643f075 100644 --- a/drivers/ub/ubfi/ubc.c +++ b/drivers/ub/ubfi/ubc.c @@ -212,7 +212,7 @@ static int ubc_dev_new_resource_entry(struct resource *res, return 0; } -static int dts_register_irq(u32 ctl_no, int irq_type, const char *name, +static int dts_register_irq(u32 ctl_no, int irq_idx, const char *name, struct resource *res) { struct device_node *np; @@ -228,16 +228,16 @@ static int dts_register_irq(u32 ctl_no, int irq_type, const char *name, if (ctl_no != index) continue; - irq = irq_of_parse_and_map(np, irq_type); + irq = irq_of_parse_and_map(np, irq_idx); if (!irq) continue; } if (!irq) { - pr_err("irq_type %d parse and map fail\n", irq_type); + pr_err("irq_idx %d parse and map failed\n", irq_idx); return -EINVAL; } - pr_info("irq_type[%d] register success, irq=%u\n", irq_type, irq); + pr_info("irq_idx %d register successfully, irq=%u\n", irq_idx, irq); res->name = name; res->start = irq; @@ -258,9 +258,9 @@ static void remove_ubc_resource(struct ub_bus_controller *ubc) if ((res->flags & IORESOURCE_IRQ) && !strcmp(res->name, "UBUS") && !ubc->ctl_no) { - if (bios_mode == ACPI) + if (firmware_mode == ACPI) ubrt_unregister_gsi(ubc->attr.msg_int); - else if (bios_mode == DTS) + else irq_dispose_mapping(ubc->queue_virq); } } @@ -296,12 +296,10 @@ static int add_ubc_irq_resource(struct ubc_node *node, trigger = !!(ubc->attr.msg_int_attr & UB_MSGQ_INT_TRIGGER_MASK); polarity = !!(ubc->attr.msg_int_attr & UB_MSGQ_INT_POLARITY_MASK); - if (bios_mode == ACPI) + if (firmware_mode == ACPI) ret = ubrt_register_gsi(hwirq, trigger, polarity, "UBUS", &res); - else if (bios_mode == DTS) - ret = dts_register_irq(ubc->ctl_no, 0, "UBUS", &res); else - ret = -EINVAL; + ret = dts_register_irq(ubc->ctl_no, 0, "UBUS", &res); if (ret) { pr_err("register irq fail, ret=%d\n", ret); @@ -318,9 +316,9 @@ static int add_ubc_irq_resource(struct ubc_node *node, return 0; out: - if (bios_mode == ACPI) + if (firmware_mode == ACPI) ubrt_unregister_gsi(hwirq); - else if (bios_mode == DTS) + else irq_dispose_mapping(res.start); return ret; @@ -333,7 +331,7 @@ static void ub_release_ubc_dev(struct device *dev) pr_info("%s release ub bus controller device.\n", ubc->name); - if (bios_mode == DTS) { + if (firmware_mode == DTS) { usi_np = irq_domain_get_of_node(dev->msi.domain); if (usi_np) of_node_put(usi_np); @@ -509,7 +507,7 @@ static int create_ubc(struct ubc_node *node, u32 ctl_no) if (ret) goto free_resource; - /* after init_ubc, ubc resources will be released in the dev->release */ + /* after init_ubc, if failed, ubc resources will be released in the dev->release */ ret = init_ubc(ubc); if (ret) return ret; @@ -551,9 +549,10 @@ static int parse_ubc_table(void *info_node) pr_info("cna_start=%u, cna_end=%u\n", ubc_cna_start, ubc_cna_end); pr_info("eid_start=%u, eid_end=%u\n", ubc_eid_start, ubc_eid_end); - pr_info("ubc_count=%u, bios_cluster_mode=%u, feature=%u\n", count, + pr_info("ubc_count=%u, firmware_cluster_mode=%u, feature=%u\n", count, cluster_mode, ubc_feature); - if (ubc_cna_start > ubc_cna_end || ubc_eid_start > ubc_eid_end) { + if (ubc_cna_start > ubc_cna_end || ubc_eid_start > ubc_eid_end || + ubc_cna_start == 0 || ubc_eid_start == 0) { pr_err("eid or cna range is incorrect\n"); return -EINVAL; } @@ -597,9 +596,9 @@ int handle_ubc_table(u64 pointer) if (ret) goto err_handle; - pr_info("Update msi domain for ub bus controller\n"); + pr_debug("Update msi domain for ub bus controller\n"); /* Update msi domain for ub bus controller */ - if (bios_mode == ACPI) + if (firmware_mode == ACPI) ret = acpi_update_ubc_msi_domain(); else ret = dts_update_ubc_msi_domain(); diff --git a/drivers/ub/ubfi/ubrt.c b/drivers/ub/ubfi/ubrt.c index 8908b2ae8edd..ecf975526e72 100644 --- a/drivers/ub/ubfi/ubrt.c +++ b/drivers/ub/ubfi/ubrt.c @@ -21,10 +21,13 @@ struct acpi_table_ubrt *acpi_table; struct ubios_root_table *ubios_table; /* - * ummu max count is 32, max size is 40 + 32 * 128 = 4640 - * ubc max count is 32, max size is 40 + 88 + 32 * 256 + 32 * 4 = 8448 + * ubios max sub table count is 256, max size is 40 + 8 * 256 = 2088 + * ummu max count is 32, max size is 32 + 8 + 32 * 160 = 5160 + * ubc max count is 32, max size is 32 + 24 + 32 * 384 = 12344 + * Choose the largest one as the maximum value for the ubios table. */ -#define UBIOS_TABLE_TOTLE_SIZE_MAX 8448 +#define UBIOS_TABLE_TOTAL_SIZE_MAX (sizeof(struct ubrt_ubc_table) + \ + 32 * sizeof(struct ubc_node)) /* remember to use ub_table_put to release memory alloced by ub_table_get */ void *ub_table_get(u64 pa) @@ -44,8 +47,9 @@ void *ub_table_get(u64 pa) total_size = readl(va + UB_TABLE_HEADER_NAME_LEN); pr_debug("ub table size is[0x%x]\n", total_size); - if (total_size == 0 || total_size > UBIOS_TABLE_TOTLE_SIZE_MAX) { - pr_err("ubios table size is invalid\n"); + if (total_size == 0 || total_size > UBIOS_TABLE_TOTAL_SIZE_MAX) { + pr_err("ubios table size is invalid, total_size=0x%x\n", + total_size); iounmap(va); return NULL; } @@ -81,6 +85,7 @@ void uninit_ub_nodes(void) int handle_acpi_ubrt(void) { + bool ubc_done = false, ummu_done = false; struct ubrt_sub_table *sub_table; int ret = 0; u32 i; @@ -89,16 +94,14 @@ int handle_acpi_ubrt(void) for (i = 0; i < acpi_table->count; i++) { sub_table = &acpi_table->sub_table[i]; - switch (sub_table->type) { - case UB_BUS_CONTROLLER_TABLE: + if (sub_table->type == UB_BUS_CONTROLLER_TABLE && !ubc_done) { ret = handle_ubc_table(sub_table->pointer); - break; - case UMMU_TABLE: + ubc_done = true; + } else if (sub_table->type == UMMU_TABLE && !ummu_done) { ret = handle_ummu_table(sub_table->pointer); - break; - default: + ummu_done = true; + } else { pr_warn("Ignore sub table: type %u\n", sub_table->type); - break; } if (ret) { pr_err("parse ubrt sub table type %u failed\n", @@ -112,10 +115,25 @@ int handle_acpi_ubrt(void) return ret; } +static int get_ubrt_table_name(char *name, u64 sub_table) +{ + void __iomem *va; + + va = ioremap(sub_table, sizeof(struct ub_table_header)); + if (!va) { + pr_err("ioremap ub table header failed\n"); + return -ENOMEM; + } + + memcpy_fromio(name, va, UB_TABLE_HEADER_NAME_LEN - 1); + iounmap(va); + return 0; +} + int handle_dts_ubrt(void) { - char name[UB_TABLE_HEADER_NAME_LEN] = {}; - struct ub_table_header *header; + bool ubc_done = false, ummu_done = false; + char name[UB_TABLE_HEADER_NAME_LEN]; int ret = 0, i; if (ubios_table->count == 0) { @@ -125,24 +143,28 @@ int handle_dts_ubrt(void) pr_info("ubios sub table count is %u\n", ubios_table->count); for (i = 0; i < ubios_table->count; i++) { - header = (struct ub_table_header *)ub_table_get( - ubios_table->sub_tables[i]); - if (!header) + memset(name, 0, UB_TABLE_HEADER_NAME_LEN); + ret = get_ubrt_table_name(name, ubios_table->sub_tables[i]); + if (ret) + goto out; + if (name[0] == '\0') continue; - - memcpy(name, header->name, UB_TABLE_HEADER_NAME_LEN - 1); pr_info("ubrt sub table name is %s\n", name); - ub_table_put(header); - if (!strncmp(name, UBIOS_SIG_UBC, strlen(UBIOS_SIG_UBC))) - ret = handle_ubc_table(ubios_table->sub_tables[i]); - else if (!strncmp(name, UBIOS_SIG_UMMU, strlen(UBIOS_SIG_UMMU))) + if (!strncmp(name, UBIOS_SIG_UMMU, strlen(UBIOS_SIG_UMMU)) && + !ummu_done) { ret = handle_ummu_table(ubios_table->sub_tables[i]); - else + ummu_done = true; + } else if (!strncmp(name, UBIOS_SIG_UBC, strlen(UBIOS_SIG_UBC)) && + !ubc_done) { + ret = handle_ubc_table(ubios_table->sub_tables[i]); + ubc_done = true; + } else { pr_warn("Ignore sub table: %s\n", name); + } if (ret) { - pr_err("Create %s device ret=%d\n", name, ret); + pr_err("Create %s failed, ret=%d\n", name, ret); goto out; } } diff --git a/drivers/ub/ubfi/ubrt.h b/drivers/ub/ubfi/ubrt.h index 0cbc5fe82368..1f15f0ce76c9 100644 --- a/drivers/ub/ubfi/ubrt.h +++ b/drivers/ub/ubfi/ubrt.h @@ -43,10 +43,6 @@ enum ubrt_sub_table_type { UB_BUS_CONTROLLER_TABLE = 0, UMMU_TABLE = 1, UB_RESERVED_MEMORY_TABLE = 2, - VIRTUAL_BUS_TABLE = 3, - CALL_ID_SERVICE_TABLE = 4, - UB_ENTITY_TABLE = 5, - UB_TOPOLOGY_TABLE = 6, }; extern struct acpi_table_ubrt *acpi_table; -- Gitee