diff options
| author | William Palacek <William.Palacek@amd.com> | 2026-10-19 15:41:15 -0400 |
|---|---|---|
| committer | Alex Deucher <alexander.deucher@amd.com> | 2026-10-27 13:50:56 -0400 |
| commit | 92249023caee17bfc6f29c71d6aaa5f2298cf507 (patch) | |
| tree | 7aa6e1024fd0ca7c4103eec61ffb3ac037117483 | |
| parent | 1ac3b84e10d23f4cd47150f55323896f4cc5a4d2 (diff) | |
| download | linux-next-92249023caee17bfc6f29c71d6aaa5f2298cf507.tar.gz linux-next-92249023caee17bfc6f29c71d6aaa5f2298cf507.zip | |
drm/amdkfd: Validate the control stack of a restored queue
kfd_criu_restore_queue() takes the control stack size from the
checkpoint image without the topology check create-queue does in
kfd_queue_acquire_buffers(), which restore stopped calling in
commit 1cafa8b29e02 ("drm/amdkfd: Don't acquire buffers
during CRIU queue restore."). An image size of 0x300000 is accepted and
sizes the MQD allocation, and 0xFFFFFFFF trips a page allocator warning
in kmalloc().
restore_mqd() also keeps the image's cp_hqd_cntl_stack_size,
cp_hqd_cntl_stack_offset and cp_hqd_wg_state_offset. With offset > size
or wave state offset < size, get_wave_state() returns wrapped sizes.
Take the per-XCC size from topology, 0 for queues without a control
stack, and reject larger images. In restore_mqd(), set the size to it
and bound both offsets as init_mqd() does.
Fixes: 626f7b3190b4 ("drm/amdkfd: CRIU add queues support")
Fixes: 42c6c48214b7 ("drm/amdkfd: CRIU checkpoint and restore queue mqds")
Signed-off-by: William Palacek <William.Palacek@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
8 files changed, 42 insertions, 9 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h index 38b46b696243..d63f7e9fae30 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h @@ -138,6 +138,15 @@ struct mqd_manager { uint32_t ctl_stack_size; }; +/* Keep offset <= size <= wave state offset, as init_mqd() and CP do */ +static inline void kfd_mqd_restore_ctl_stack(u32 *size, u32 *offset, u32 *wg_offset, + u32 ctl_stack_size) +{ + *size = ctl_stack_size; + *offset = min(*offset, ctl_stack_size); + *wg_offset = max(*wg_offset, ctl_stack_size); +} + struct mqd_user_context_save_area_header { /* Byte offset from start of user context * save area to the last saved top (lowest diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 25f5a2cf02ff..922615b713a9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -305,6 +305,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, addr = mqd_mem_obj->gpu_addr; memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); *mqd = m; if (gart_addr) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index a1eecdf63b0c..62c3023152a5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -340,6 +340,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, addr = mqd_mem_obj->gpu_addr; memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); *mqd = m; if (gart_addr) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c index e0574fa325c4..1d9b4890909f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c @@ -394,6 +394,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size)); memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); /* Update MQD base address to the newly allocated location */ m->cp_mqd_base_addr_lo = lower_32_bits(addr); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c index 04e1575dfe76..e34103067fa0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c @@ -693,6 +693,8 @@ static void restore_mqd_v12_1(struct mqd_manager *mm, void **mqd, memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size) * NUM_XCC(mm->dev->xcc_mask)); memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); /* Update MQD base address to the newly allocated location */ m->cp_mqd_base_addr_lo = lower_32_bits(addr); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 80df86f7c4d5..e18c86c87d1c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -462,6 +462,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, addr = mqd_mem_obj->gpu_addr; memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); *mqd = m; if (gart_addr) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 029572548c14..5ead0d5613b6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -317,6 +317,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, addr = mqd_mem_obj->gpu_addr; memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); *mqd = m; if (gart_addr) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index a15a826519ad..78ab759ad854 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -26,6 +26,7 @@ #include <linux/list.h> #include "kfd_device_queue_manager.h" #include "kfd_priv.h" +#include "kfd_topology.h" #include "kfd_kernel_queue.h" #include "amdgpu_amdkfd.h" #include "amdgpu_reset.h" @@ -983,7 +984,7 @@ int kfd_criu_checkpoint_queues(struct kfd_process *p, } static void set_queue_properties_from_criu(struct queue_properties *qp, - struct kfd_criu_queue_priv_data *q_data, uint32_t num_xcc) + struct kfd_criu_queue_priv_data *q_data) { qp->is_interop = false; qp->queue_percent = q_data->q_percent; @@ -996,11 +997,6 @@ static void set_queue_properties_from_criu(struct queue_properties *qp, qp->eop_ring_buffer_size = q_data->eop_ring_buffer_size; qp->ctx_save_restore_area_address = q_data->ctx_save_restore_area_address; qp->ctx_save_restore_area_size = q_data->ctx_save_restore_area_size; - if (q_data->type == KFD_QUEUE_TYPE_COMPUTE) - qp->ctl_stack_size = q_data->ctl_stack_size / num_xcc; - else - qp->ctl_stack_size = q_data->ctl_stack_size; - qp->type = q_data->type; qp->format = q_data->format; } @@ -1012,6 +1008,7 @@ int kfd_criu_restore_queue(struct kfd_process *p, { uint8_t *mqd, *ctl_stack, *q_extra_data = NULL; struct kfd_criu_queue_priv_data *q_data; + struct kfd_topology_device *topo_dev; struct kfd_process_device *pdd; uint64_t q_extra_data_size; struct queue_properties qp; @@ -1048,6 +1045,24 @@ int kfd_criu_restore_queue(struct kfd_process *p, goto exit; } + memset(&qp, 0, sizeof(qp)); + set_queue_properties_from_criu(&qp, q_data); + + /* Per-XCC control stack size from topology, as create-queue requires */ + if (qp.type == KFD_QUEUE_TYPE_COMPUTE && pdd->dev->kfd->cwsr_enabled) { + topo_dev = kfd_topology_device_by_id(pdd->dev->id); + if (!topo_dev) { + ret = -EINVAL; + goto exit; + } + qp.ctl_stack_size = topo_dev->node_props.ctl_stack_size; + } + + if (q_data->ctl_stack_size > (u64)qp.ctl_stack_size * NUM_XCC(pdd->dev->xcc_mask)) { + ret = -EINVAL; + goto exit; + } + *priv_data_offset += sizeof(*q_data); q_extra_data_size = (uint64_t)q_data->ctl_stack_size + q_data->mqd_size; @@ -1077,9 +1092,6 @@ int kfd_criu_restore_queue(struct kfd_process *p, mqd = q_extra_data; ctl_stack = mqd + q_data->mqd_size; - memset(&qp, 0, sizeof(qp)); - set_queue_properties_from_criu(&qp, q_data, NUM_XCC(pdd->dev->xcc_mask)); - print_queue_properties(&qp); ret = pqm_create_queue(&p->pqm, pdd->dev, &qp, &queue_id, q_data, mqd, ctl_stack, NULL); |
