Merge tag 'LA.UM.8.3.c25-09700-sdm845.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.9 into android13-4.9-sdm845

"LA.UM.8.3.c25-09700-sdm845.0"

* tag 'LA.UM.8.3.c25-09700-sdm845.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.9:
  securemsm-kernel: Fixed multiple listener registration on same fd
  msm: kgsl: Fix error handling during drawctxt switch
  msm: kgsl: Update the protect register list
  msm: kgsl: Do not release dma and anon buffers if unmap fails
  soc: qcom: smem: Add boundary checks for partitions
  msm: kgsl: Do not free sharedmem if it cannot be unmapped

 Conflicts:
	drivers/gpu/msm/kgsl_mmu.c

Change-Id: I62a1cc70492f769d35a9e91e140b1cb987269224
This commit is contained in:
Michael Bestas 2024-10-10 16:46:34 +03:00
commit 2cb72020b2
No known key found for this signature in database
GPG key ID: CC95044519BE6669
5 changed files with 82 additions and 22 deletions

View file

@ -1,4 +1,5 @@
/* Copyright (c) 2002,2007-2018,2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -629,8 +630,6 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
if (drawctxt != NULL && kgsl_context_detached(&drawctxt->base))
return -ENOENT;
trace_adreno_drawctxt_switch(rb, drawctxt);
/* Get a refcount to the new instance */
if (drawctxt) {
if (!_kgsl_context_get(&drawctxt->base))
@ -643,7 +642,7 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
}
ret = adreno_ringbuffer_set_pt_ctx(rb, new_pt, drawctxt, flags);
if (ret)
return ret;
goto err;
if (rb->drawctxt_active) {
/* Wait for the timestamp to expire */
@ -654,6 +653,13 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
}
}
trace_adreno_drawctxt_switch(rb, drawctxt);
rb->drawctxt_active = drawctxt;
return 0;
err:
if (drawctxt)
kgsl_context_put(&drawctxt->base);
return ret;
}

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -964,5 +964,17 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
else
result = _set_ctxt_gpu(rb, drawctxt);
/*
* In case ctxt switch fails, revert the pagetable back to the
* original. Not reverting the pagetable will lead to incorrect
* hardware state in the ringbuffer.
*/
if (result && (new_pt != cur_pt)) {
if (cpu_path)
result = _set_pagetable_cpu(rb, cur_pt);
else
result = _set_pagetable_gpu(rb, cur_pt);
}
return result;
}

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2002,2007-2017,2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and

View file

@ -353,7 +353,7 @@ struct qseecom_client_handle {
struct qseecom_listener_handle {
u32 id;
bool unregister_pending;
bool register_pending;
bool release_called;
};
@ -1233,6 +1233,11 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
struct qseecom_registered_listener_list *new_entry;
struct qseecom_registered_listener_list *ptr_svc;
if (data->listener.register_pending) {
pr_err("Already a listner registration is in process on this FD\n");
return -EINVAL;
}
ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
if (ret) {
pr_err("copy_from_user failed\n");
@ -1242,6 +1247,13 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
rcvd_lstnr.sb_size))
return -EFAULT;
ptr_svc = __qseecom_find_svc(data->listener.id);
if (ptr_svc) {
pr_err("Already a listener registered on this data: lid=%d\n",
data->listener.id);
return -EINVAL;
}
ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id);
if (ptr_svc) {
if (ptr_svc->unregister_pending == false) {
@ -1276,12 +1288,15 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
new_entry->svc.listener_id = rcvd_lstnr.listener_id;
new_entry->sb_length = rcvd_lstnr.sb_size;
new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
data->listener.register_pending = true;
if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
pr_err("qseecom_set_sb_memory failed for listener %d, size %d\n",
rcvd_lstnr.listener_id, rcvd_lstnr.sb_size);
kzfree(new_entry);
data->listener.register_pending = false;
return -ENOMEM;
}
data->listener.register_pending = false;
init_waitqueue_head(&new_entry->rcv_req_wq);
init_waitqueue_head(&new_entry->listener_block_app_wq);

View file

@ -85,6 +85,17 @@
/* Max number of processors/hosts in a system */
#define SMEM_HOST_COUNT 9
/* Entry range check
* ptr >= start : Checks if ptr is greater than the start of access region
* ptr + size >= ptr: Check for integer overflow (On 32bit system where ptr
* and size are 32bits, ptr + size can wrap around to be a small integer)
* ptr + size <= end: Checks if ptr+size is less than the end of access region
*/
#define IN_PARTITION_RANGE(ptr, size, start, end) \
(((void *)(ptr) >= (void *)(start)) && \
(((void *)(ptr) + (size)) >= (void *)(ptr)) && \
(((void *)(ptr) + (size)) <= (void *)(end)))
/**
* struct smem_proc_comm - proc_comm communication struct (legacy)
* @command: current command to be executed
@ -301,6 +312,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
size_t size)
{
struct smem_private_entry *hdr, *end;
struct smem_private_entry *next_hdr;
struct smem_partition_header *phdr;
size_t alloc_size;
void *cached;
@ -313,10 +325,11 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
end = phdr_to_last_private_entry(phdr);
cached = phdr_to_first_cached_entry(phdr);
if (WARN_ON((void *)end > p_end || (void *)cached > p_end))
if (WARN_ON(!IN_PARTITION_RANGE(end, 0, phdr, cached) ||
cached > p_end))
return -EINVAL;
while (hdr < end) {
while ((hdr < end) && ((hdr + 1) < end)) {
if (hdr->canary != SMEM_PRIVATE_CANARY) {
dev_err(smem->dev,
"Found invalid canary in host %d:%d partition\n",
@ -327,9 +340,15 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
if (le16_to_cpu(hdr->item) == item)
return -EEXIST;
hdr = private_entry_next(hdr);
next_hdr = private_entry_next(hdr);
if (WARN_ON(next_hdr <= hdr))
return -EINVAL;
hdr = next_hdr;
}
if (WARN_ON((void *)hdr > p_end))
if (WARN_ON((void *)hdr > (void *)end))
return -EINVAL;
/* Check that we don't grow into the cached region */
@ -484,7 +503,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
{
struct smem_partition_header *phdr;
struct smem_private_entry *e, *end;
struct smem_private_entry *next_e;
void *item_ptr, *p_end;
size_t entry_size = 0;
u32 partition_size;
u32 padding_data;
u32 e_size;
@ -499,7 +520,7 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
if (WARN_ON((void *)end > p_end))
return ERR_PTR(-EINVAL);
while (e < end) {
while ((e < end) && ((e + 1) < end)) {
if (e->canary != SMEM_PRIVATE_CANARY) {
dev_err(smem->dev,
"Found invalid canary in host %d:%d partition\n",
@ -508,25 +529,31 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
}
if (le16_to_cpu(e->item) == item) {
if (size != NULL) {
e_size = le32_to_cpu(e->size);
padding_data = le16_to_cpu(e->padding_data);
e_size = le32_to_cpu(e->size);
padding_data = le16_to_cpu(e->padding_data);
if (e_size < partition_size
&& padding_data < e_size)
*size = e_size - padding_data;
else
return ERR_PTR(-EINVAL);
}
if (e_size < partition_size && padding_data < e_size)
entry_size = e_size - padding_data;
else
return ERR_PTR(-EINVAL);
item_ptr = entry_to_item(e);
if (WARN_ON(item_ptr > p_end))
if (WARN_ON(!IN_PARTITION_RANGE(item_ptr, entry_size,
e, end)))
return ERR_PTR(-EINVAL);
if (size != NULL)
*size = entry_size;
return item_ptr;
}
e = private_entry_next(e);
next_e = private_entry_next(e);
if (WARN_ON(next_e <= e))
return ERR_PTR(-EINVAL);
e = next_e;
}
if (WARN_ON((void *)e > p_end))
return ERR_PTR(-EINVAL);