diff options
author | Will McVicker <willmcvicker@google.com> | 2022-06-02 09:40:14 -0700 |
---|---|---|
committer | Will McVicker <willmcvicker@google.com> | 2022-06-02 09:43:50 -0700 |
commit | 7f6a736b208c7fb78f0902ca0b793b885115ac95 (patch) | |
tree | 8e8c22cd1b4430df6bc1267d8fae32eacce14207 | |
parent | bcfd429733db3c4e01a9ef07e7c4826c52b8049e (diff) | |
parent | 28826da1deae49f5a942bb7b4621944360933440 (diff) | |
download | trusty-7f6a736b208c7fb78f0902ca0b793b885115ac95.tar.gz |
Merge 'android13-gs-pixel-5.15-gs101' into 'android13-gs-pixel-5.15'
* commit '5ff74e8ea23b6027946af60b485db4d45bf975b6': (494 commits)
Slider: Add cfg80211 & mac80211 as vendor modules.
soc: google: hardlockup-debug: Print Mem-Info when WDT
kleaf: update dt-bindings to be generic
kleaf: update the readme commands
Revert "usb: typec: tcpci_max77759: stub for tcpm_is_debouncing()"
Revert "slider_gki: enable CONFIG_VH_SCHED"
Revert "Revert "scsi: ufs: ufs-exynos: update hba suspend vops""
Revert "drivers: thermal: update milliwatts references"
Revert "scsi: ufs: ufs-exynos: update hba suspend vops"
Revert "scsi: ufs: update to new wrapped key api"
Revert "usb: dwc3: remove duplicated definitions"
Revert "cpufreq: acme: flag updates to cpufreq_policy"
Revert "iommu/samsung: drop IOVA cookie management"
Revert "cpufreq: acme: fix thermal API for 5.17-rc2"
Revert "Revert "tty: serial: exynos_tty: remove duplicated definitions""
Revert "soc/google/cpif: replace PDE_DATA as pde_data"
Revert "ANDROID: Fixup spi_driver remove functions"
Revert "media: mfc/smfc: Fix depends on VIDEO_V4L2"
Revert "dma-buf-map: Rename to iosys-map"
Revert "usb: dwc3: remove duplicate DWC3_GFLADJ_REFCLK_FLADJ_MASK"
Revert "google/debug: update path to debug_kinfo.h"
Revert "serial: exynos: update exynos_serial_console_putchar"
Revert "iommu/samsung:remove aux-domain interfaces usage"
Revert "dts/google: tpu: disable ssmt"
Revert "Revert "dma-buf: Fix build for shrinker controlled page pool""
Revert "Revert "Revert "ANDROID: dma-buf: heaps: Add a shrinker controlled page pool"""
Revert "Revert "dma-buf: Fix build for deferred-free-helper.h""
Revert "Revert "Revert "ANDROID: dma-buf: heaps: Add deferred-free-helper library code"""
Revert "ANDROID: dma-buf: heaps: fix dma-buf heap pool pages stat"
kleaf: Add kleaf tests for kernel_images
kleaf: Move SLIDER_DTBOS to a global variable.
kleaf: Move SLIDER_DTBOS to a global variable.
kleaf: build abi for slider
vendor_hook: sched: Add control for reduce_prefer_idle
usb: dwc3: cancel gadget retry during device reboot
arm64/dts: devfreq: add boot_info
google/debug: ehld: handle hrtimers correctly in CPUHP and CPUPM
Revert "google/debug: ehld: stop and restart hrtimer at CPU PM"
google/debug: ehld: fix exynos_ehld_stop_cpu()
devfreq: add sysfs node "cancel_boot_freq"
aoc/alsa: dts: change the name for immersive playback
aoc/alsa: dt-bindings: change the name for immersive playback
arm64/dts: Add board_id and board_rev to aoc
pcie: exynos: Skip PHY isloation on hot reset test
Revert "vendor_hook: sched: Implement vendor group util"
Revert "vendor_hook: sched: Check if cfs_rq->curr is a task"
gvotable: export run_election API with force_callback parameter
usb: have gvotable callback return an error code
gvotable: have callback return an error code
arm64/dts: enable battery pairing feature
vendor_hook: sched: Add trace for compute_energy
vh: sched: rt: prefer to overutilized CPU from unfit CPU
soc/google/cpif: Keep DIT downstream netdev until removeDownstream
vendor_hook: sched: revert back to use most_spare_cap_cpu
media: mfc: move the mfc_alloc_codec_buffers()
usb: dwc3: move the operation for burst mode setting
arm64/dts: set bhi algo_ver and threshold
vendor_hook: sched: Change the uclamp max of low prio tasks
usb: phy: limit the string length in phy attribute
google/debug: eat: use polling api for channel operations
google/debug: eat: fix mbox ipc race condition
media: mfc: fix KASAN use-after-free case
misc: logbuffer: Fix a deadlock
arm64/dts: gs101: Update default target_load for ALT DVFS
ANDROID: trusty: add a toggle for running trusty work in higher priority
Revert "trusty: add a toggle for using high prio WQ"
pogo_transport: Configure USB_MUX_POGO_SEL
Revert "vendor_hook: sched: Refine vendor group uclamp update"
vendor_hook: sched: Refine RT util check
usb: dwc3: disable INCR undefined length burst mode
kleaf: build abi for slider
tcpci_max77759: Reset the OVP if Vbus times out
build.config.gs101: enable kunit kernel arg
kleaf: Add log=info to slider.
kleaf: Add log=info to slider.
kleaf: Explicitly set build_initramfs.
kleaf: Explicitly set build_initramfs.
Add dw3000-core-tests.ko to the blocklist
kleaf: re-enable the vendor_dlkm blocklist
kleaf: add missing pixel_em.ko
kleaf: Add slider_unstripped_modules_archive.
kleaf: Move definitions to slider.bzl.
kleaf: Add slider_unstripped_modules_archive.
kleaf: Move definitions to slider.bzl.
iommu/samsung: add missing unmap_pages op
kleaf: update build command in README.md
kleaf: Fix KCONFIG_EXT_MODULES_PREFIX for kleaf --config=local builds.
Rename merge-from-mainline.sh
build.config.gs101: drop the boot ramdisk
PRE_DEFCONFIG_CMDS does not write to source tree.
PRE_DEFCONFIG_CMDS does not write to source tree.
merge-from-mainline: update the script to
soc: google: bcm_dbg: check copy_to_user return value
drivers: thermal: update milliwatts references
google/debug: ehld: stop and restart hrtimer at CPU PM
usb: dwc3: wait for pm suspend for USB host
usb: dwc3: remove conditional operator
usb: dwc3: release the lock if device is suspended
usb: dwc3: wait for pm suspend when cable is plug-in
vendor_hook: sched: Support RT task util
...
Change-Id: I6f1ffd50ee4379247eef9319d1ff27dfe6599260
Signed-off-by: Will McVicker <willmcvicker@google.com>
-rw-r--r-- | drivers/trusty/Kconfig | 13 | ||||
-rw-r--r-- | drivers/trusty/trusty-ipc.c | 137 | ||||
-rw-r--r-- | drivers/trusty/trusty-log.c | 219 | ||||
-rw-r--r-- | drivers/trusty/trusty-virtio.c | 19 | ||||
-rw-r--r-- | drivers/trusty/trusty.c | 43 | ||||
-rw-r--r-- | include/linux/trusty/trusty.h | 27 | ||||
-rw-r--r-- | include/uapi/linux/trusty/ipc.h | 23 |
7 files changed, 386 insertions, 95 deletions
diff --git a/drivers/trusty/Kconfig b/drivers/trusty/Kconfig index 2f0e30c..fcde7f0 100644 --- a/drivers/trusty/Kconfig +++ b/drivers/trusty/Kconfig @@ -88,6 +88,19 @@ config TRUSTY_DMA_BUF_FFA_TAG If set to N, a default implementation which returns 0 will be used. +config TRUSTY_DMA_BUF_SHARED_MEM_ID + bool "Availability of trusty_dma_buf_get_shared_mem_id" + default n + help + Whether trusty_dma_buf_get_shared_mem_id is provided on this platform. + Providing this function allows the platform to manage memory + transaction life cycle of DMA bufs independently of Trusty IPC driver. + The latter can query trusty_shared_mem_id_t value allocated for a + given DMA buf using trusty_dma_buf_get_shared_mem_id interface. + + If set to N, a default implementation which does not allocate any IDs + will be used. + config TRUSTY_CRASH_IS_PANIC bool "When trusty panics, then panic the kernel" help diff --git a/drivers/trusty/trusty-ipc.c b/drivers/trusty/trusty-ipc.c index 7ac586e..a30e02a 100644 --- a/drivers/trusty/trusty-ipc.c +++ b/drivers/trusty/trusty-ipc.c @@ -165,10 +165,14 @@ struct tipc_shared_handle { struct rb_node node; struct tipc_shm tipc; struct tipc_virtio_dev *vds; - struct sg_table *sgt; - struct dma_buf_attachment *attach; struct dma_buf *dma_buf; bool shared; + /* + * Following fields are only used if dma_buf does not own a + * trusty_shared_mem_id_t. + */ + struct dma_buf_attachment *attach; + struct sg_table *sgt; }; static struct class *tipc_class; @@ -288,7 +292,13 @@ static void _free_vds(struct kref *kref) { struct tipc_virtio_dev *vds = container_of(kref, struct tipc_virtio_dev, refcount); - /* If this WARN triggers, we're leaking remote memory references. */ + /* + * If this WARN triggers, we're leaking remote memory references. + * + * No need to lock shared_handles_lock. All references to this lock + * should already be gone by this point, since we are freeing it in this + * function. + */ WARN_ON(!RB_EMPTY_ROOT(&vds->shared_handles)); kfree(vds); } @@ -550,22 +560,51 @@ static struct device *tipc_shared_handle_dev(struct tipc_shared_handle return shared_handle->vds->vdev->dev.parent->parent; } +static bool is_same_memory_region(struct tipc_shared_handle *h1, + struct tipc_shared_handle *h2) +{ + return h1->tipc.obj_id == h2->tipc.obj_id && + h1->tipc.size == h2->tipc.size && + h1->tipc.tag == h2->tipc.tag && + h1->dma_buf == h2->dma_buf && + h1->shared == h2->shared; +} + +static bool dma_buf_owns_shared_mem_id(struct tipc_shared_handle *h) +{ + /* h->shared is true only if dma_buf did not own an shared memory ID */ + return !h->shared; +} + static void tipc_shared_handle_register(struct tipc_shared_handle *new_handle) { struct tipc_virtio_dev *vds = new_handle->vds; - struct rb_node **new = &vds->shared_handles.rb_node; + struct rb_node **new; struct rb_node *parent = NULL; mutex_lock(&vds->shared_handles_lock); + new = &vds->shared_handles.rb_node; while (*new) { struct tipc_shared_handle *handle = rb_entry(*new, struct tipc_shared_handle, node); parent = *new; - /* The handle is already registered? */ - if (WARN_ON(handle->tipc.obj_id == new_handle->tipc.obj_id)) - goto already_registered; + /* + * An obj_id can be registered multiple times if it's owned by a + * dma_buf, because in this case we use the same obj_id across + * multiple memory transfer operations. + */ + if (handle->tipc.obj_id == new_handle->tipc.obj_id) { + if (dma_buf_owns_shared_mem_id(new_handle)) { + WARN_ON(!is_same_memory_region(handle, + new_handle)); + } else { + WARN(1, "This handle is already registered"); + goto already_registered; + } + } + if (handle->tipc.obj_id > new_handle->tipc.obj_id) new = &((*new)->rb_left); else @@ -584,11 +623,12 @@ static struct tipc_shared_handle *tipc_shared_handle_take(struct tipc_virtio_dev trusty_shared_mem_id_t obj_id) { - struct rb_node *node = vds->shared_handles.rb_node; + struct rb_node *node; struct tipc_shared_handle *out = NULL; mutex_lock(&vds->shared_handles_lock); + node = vds->shared_handles.rb_node; while (node) { struct tipc_shared_handle *handle = rb_entry(node, struct tipc_shared_handle, node); @@ -614,18 +654,23 @@ static int tipc_shared_handle_drop(struct tipc_shared_handle *shared_handle) struct tipc_virtio_dev *vds = shared_handle->vds; struct device *dev = tipc_shared_handle_dev(shared_handle); - /* - * If this warning fires, it means this shared handle was still in - * the set of active handles. This shouldn't happen (calling code - * should ensure it is out if the tree) but this serves as an extra - * check before it is released. - * - * However, the take itself should clean this incorrect state up by - * removing the handle from the tree. - */ - WARN_ON(tipc_shared_handle_take(vds, shared_handle->tipc.obj_id)); - if (shared_handle->shared) { + /* + * If this warning fires, it means this shared handle was still + * in the set of active handles. This shouldn't happen (calling + * code should ensure it is out if the tree) but this serves as + * an extra check before it is released. + * + * However, the take itself should clean this incorrect state up + * by removing the handle from the tree. + * + * This warning is only applicable when registering a handle + * multiple times is not allowed, i.e. when dma_buf doesn't own + * the handle. + */ + WARN_ON(tipc_shared_handle_take(vds, + shared_handle->tipc.obj_id)); + ret = trusty_reclaim_memory(dev, shared_handle->tipc.obj_id, shared_handle->sgt->sgl, @@ -1098,7 +1143,7 @@ static int dn_connect_ioctl(struct tipc_dn_chan *dn, char __user *usr_name) } static int dn_share_fd(struct tipc_dn_chan *dn, int fd, - bool lend, + enum transfer_kind transfer_kind, struct tipc_shared_handle **out) { int ret = 0; @@ -1108,6 +1153,8 @@ static int dn_share_fd(struct tipc_dn_chan *dn, int fd, bool writable = false; pgprot_t prot; u64 tag = 0; + trusty_shared_mem_id_t mem_id; + bool lend; if (dn->state != TIPC_CONNECTED) { dev_dbg(dev, "Tried to share fd while not connected\n"); @@ -1143,6 +1190,35 @@ static int dn_share_fd(struct tipc_dn_chan *dn, int fd, goto cleanup_handle; } + tag = trusty_dma_buf_get_ffa_tag(shared_handle->dma_buf); + ret = trusty_dma_buf_get_shared_mem_id(shared_handle->dma_buf, &mem_id); + /* + * Buffers with a preallocated mem_id should only be sent to Trusty + * using TRUSTY_SEND_SECURE. And conversely, TRUSTY_SEND_SECURE should + * only be used to send buffers with preallocated mem_id. + */ + if (!ret) { + /* Use shared memory ID owned by dma_buf */ + if (transfer_kind != TRUSTY_SEND_SECURE) { + dev_err(dev, "transfer_kind: %d, must be TRUSTY_SEND_SECURE\n", + transfer_kind); + ret = -EINVAL; + goto cleanup_handle; + } + goto mem_id_allocated; + } + + if (ret != -ENODATA) { + dev_err(dev, "dma_buf can't be transferred (%d)\n", ret); + goto cleanup_handle; + } + + if (transfer_kind == TRUSTY_SEND_SECURE) { + dev_err(dev, "No mem ID for TRUSTY_SEND_SECURE\n"); + goto cleanup_handle; + } + lend = (transfer_kind == TRUSTY_LEND); + shared_handle->attach = dma_buf_attach(shared_handle->dma_buf, dev); if (IS_ERR(shared_handle->attach)) { ret = PTR_ERR(shared_handle->attach); @@ -1160,13 +1236,10 @@ static int dn_share_fd(struct tipc_dn_chan *dn, int fd, goto cleanup_handle; } - tag = trusty_dma_buf_get_ffa_tag(shared_handle->dma_buf); - ret = trusty_transfer_memory(tipc_shared_handle_dev(shared_handle), - &shared_handle->tipc.obj_id, - shared_handle->sgt->sgl, - shared_handle->sgt->orig_nents, prot, - tag, lend); + &mem_id, shared_handle->sgt->sgl, + shared_handle->sgt->orig_nents, prot, tag, + lend); if (ret < 0) { dev_dbg(dev, "Transferring memory failed: %d\n", ret); @@ -1177,6 +1250,9 @@ static int dn_share_fd(struct tipc_dn_chan *dn, int fd, goto cleanup_handle; } shared_handle->shared = true; + +mem_id_allocated: + shared_handle->tipc.obj_id = mem_id; shared_handle->tipc.size = shared_handle->dma_buf->size; shared_handle->tipc.tag = tag; *out = shared_handle; @@ -1249,7 +1325,6 @@ static long filp_send_ioctl(struct file *filp, long ret = 0; ssize_t data_len = 0; ssize_t shm_len = 0; - bool lend = false; if (copy_from_user(&req, arg, sizeof(req))) return -EFAULT; @@ -1284,18 +1359,15 @@ static long filp_send_ioctl(struct file *filp, for (shm_idx = 0; shm_idx < req.shm_cnt; shm_idx++) { switch (shm[shm_idx].transfer) { case TRUSTY_SHARE: - lend = false; - break; case TRUSTY_LEND: - lend = true; + case TRUSTY_SEND_SECURE: break; default: dev_err(dev, "Unknown transfer type: 0x%x\n", shm[shm_idx].transfer); goto shm_share_failed; } - ret = dn_share_fd(dn, shm[shm_idx].fd, - lend, + ret = dn_share_fd(dn, shm[shm_idx].fd, shm[shm_idx].transfer, &shm_handles[shm_idx]); if (ret) { dev_dbg(dev, "Forwarding memory failed\n" @@ -2186,4 +2258,5 @@ module_exit(tipc_exit); MODULE_DEVICE_TABLE(tipc, tipc_virtio_id_table); MODULE_DESCRIPTION("Trusty IPC driver"); +MODULE_IMPORT_NS(DMA_BUF); MODULE_LICENSE("GPL v2"); diff --git a/drivers/trusty/trusty-log.c b/drivers/trusty/trusty-log.c index 878e589..944d5b0 100644 --- a/drivers/trusty/trusty-log.c +++ b/drivers/trusty/trusty-log.c @@ -11,25 +11,57 @@ #include <linux/mm.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/log2.h> #include <linux/miscdevice.h> +#include <linux/poll.h> #include <linux/seq_file.h> #include <linux/panic_notifier.h> #include <asm/page.h> #include "trusty-log.h" /* - * Rationale for the chosen log buffer size: - * - the log buffer shall contain unthrottled trusty crash dump. - * Testing identifies that the logbuffer size shall be - * (~96Bytes * 100) i.e. ~2^13 - * - specifying twice as much as the crash dump minimum allows to have - * ~100 lines of context prior to the crash. - * - conclusion: logbuffer = 2^14 is comfortable, half is minimal. + * Rationale for the chosen default log buffer size: + * - the log buffer shall contain unthrottled Trusty crash dump. + * - the register list portion of a crash dump is about 1KB + * - the memory-around-registers portion of a crash dump can be up to 12 KB + * - an average size backtrace is about 1 KB + * - average length of non-crash trusty logs during boot is about 85 characters + * - a crash dump with 50 lines of context therefore requires up to 18 KB + * - buffer size needs to be power-of-two number of bytes + * - rounding up to power of two from 18 KB gives 32 KB + * The log size can be adjusted by setting the "trusty_log.log_size" parameter + * on the kernel command line. The specified value will be adjusted as needed. */ -#define TRUSTY_LOG_SIZE (PAGE_SIZE * 5) -#define TRUSTY_LINE_BUFFER_SIZE 256 +#define TRUSTY_LOG_DEFAULT_SIZE (32768) +#define TRUSTY_LOG_MIN_SIZE (PAGE_SIZE / 2) +#define TRUSTY_LOG_MAX_SIZE (1 * 1024 * 1024 * 1024) +#define TRUSTY_LINE_BUFFER_SIZE (256) + +static size_t log_size_param = TRUSTY_LOG_DEFAULT_SIZE; + +static int trusty_log_size_set(const char *val, const struct kernel_param *kp) +{ + unsigned long long requested = memparse(val, NULL); + + if (requested < TRUSTY_LOG_MIN_SIZE) + requested = TRUSTY_LOG_MIN_SIZE; + if (requested > TRUSTY_LOG_MAX_SIZE) + requested = TRUSTY_LOG_MAX_SIZE; + requested = rounddown_pow_of_two(requested); + log_size_param = requested; + return 0; +} + +static int trusty_log_size_get(char *buffer, const struct kernel_param *kp) +{ + sprintf(buffer, "%zu", log_size_param); + return strlen(buffer); +} + +module_param_call(log_size, trusty_log_size_set, trusty_log_size_get, NULL, + 0644); /* * If we log too much and a UART or other slow source is connected, we can stall * out another thread which is doing printk. @@ -44,13 +76,11 @@ static struct ratelimit_state trusty_log_rate_limit = * struct trusty_log_sfile - trusty log misc device state * * @misc: misc device created for the trusty log virtual file - * @sfile: seq_file created when opening the misc device * @device_name: misc device name following the convention * "trusty-<name><id>" */ struct trusty_log_sfile { struct miscdevice misc; - struct seq_file sfile; char device_name[64]; }; @@ -58,8 +88,6 @@ struct trusty_log_sfile { * struct trusty_log_sink_state - trusty log sink state * * @get: current read unwrapped index - * @last_successful_next: - * index for the next line after the last successful get * @trusty_panicked: trusty panic status at the start of the sink interation * (only used for kernel log sink) * @sfile: seq_file used for sinking to a virtual file (misc device); @@ -76,7 +104,6 @@ struct trusty_log_sfile { */ struct trusty_log_sink_state { u32 get; - u32 last_successful_next; bool trusty_panicked; /* virtual file sink specific attributes */ @@ -89,21 +116,20 @@ struct trusty_log_state { struct device *trusty_dev; struct trusty_log_sfile log_sfile; - /* - * This lock is here to ensure only one consumer will read - * from the log ring buffer at a time. - */ - spinlock_t lock; struct log_rb *log; struct trusty_log_sink_state klog_sink; - struct page *log_pages; - struct scatterlist sg; + u32 log_num_pages; + struct scatterlist *sg; trusty_shared_mem_id_t log_pages_shared_mem_id; struct notifier_block call_notifier; struct notifier_block panic_notifier; char line_buffer[TRUSTY_LINE_BUFFER_SIZE]; + wait_queue_head_t poll_waiters; + /* this lock protects access to wake_put */ + spinlock_t wake_up_lock; + u32 last_wake_put; }; static inline u32 u32_add_overflow(u32 a, u32 b) @@ -258,13 +284,10 @@ static void trusty_log_show(struct trusty_log_state *s, sink->ignore_overflow = false; if (sink->sfile) { seq_printf(sink->sfile, "%s", s->line_buffer); - sink->last_successful_next = sink->get; } else { if (sink->trusty_panicked || __ratelimit(&trusty_log_rate_limit)) { dev_info(s->dev, "%s", s->line_buffer); - /* next line after last successful get */ - sink->last_successful_next = sink->get; } } } @@ -408,18 +431,13 @@ static int trusty_log_seq_show(struct seq_file *sfile, void *v) static void trusty_dump_logs(struct trusty_log_state *s) { - u32 start; int rc; /* - * note: klopg_sink.get and last_successful_next - * initialized to zero by kzalloc + * note: klog_sink.get initialized to zero by kzalloc */ s->klog_sink.trusty_panicked = trusty_get_panic_status(s->trusty_dev); - start = s->klog_sink.trusty_panicked ? - s->klog_sink.last_successful_next : - s->klog_sink.get; - rc = trusty_log_start(s, &s->klog_sink, start); + rc = trusty_log_start(s, &s->klog_sink, s->klog_sink.get); if (rc < 0) return; @@ -432,14 +450,19 @@ static int trusty_log_call_notify(struct notifier_block *nb, { struct trusty_log_state *s; unsigned long flags; + u32 cur_put; if (action != TRUSTY_CALL_RETURNED) return NOTIFY_DONE; s = container_of(nb, struct trusty_log_state, call_notifier); - spin_lock_irqsave(&s->lock, flags); - trusty_dump_logs(s); - spin_unlock_irqrestore(&s->lock, flags); + spin_lock_irqsave(&s->wake_up_lock, flags); + cur_put = s->log->put; + if (cur_put != s->last_wake_put) { + s->last_wake_put = cur_put; + wake_up_all(&s->poll_waiters); + } + spin_unlock_irqrestore(&s->wake_up_lock, flags); return NOTIFY_OK; } @@ -472,11 +495,19 @@ static int trusty_log_sfile_dev_open(struct inode *inode, struct file *file) struct seq_file *sfile; int rc; + /* + * file->private_data contains a pointer to the misc_device struct + * passed to misc_register() + */ if (WARN_ON(!file->private_data)) return -EINVAL; ls = container_of(file->private_data, struct trusty_log_sfile, misc); + /* + * seq_open uses file->private_data to store the seq_file associated + * with the struct file, but it must be NULL when seq_open is called + */ file->private_data = NULL; rc = seq_open(file, &trusty_log_seq_ops); if (rc < 0) @@ -490,9 +521,44 @@ static int trusty_log_sfile_dev_open(struct inode *inode, struct file *file) return 0; } +static unsigned int trusty_log_sfile_dev_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct seq_file *sfile; + struct trusty_log_sfile *lb; + struct trusty_log_state *s; + struct log_rb *log; + + /* + * trusty_log_sfile_dev_open() pointed filp->private_data to a + * seq_file, and that seq_file->private to the trusty_log_sfile + * field of a trusty_log_state + */ + sfile = filp->private_data; + lb = sfile->private; + s = container_of(lb, struct trusty_log_state, log_sfile); + poll_wait(filp, &s->poll_waiters, wait); + log = s->log; + + /* + * Userspace has read up to filp->f_pos so far. Update klog_sink + * to indicate that, so that we don't end up dumping the entire + * Trusty log in case of panic. + */ + s->klog_sink.get = (u32)filp->f_pos; + + if (log->put != (u32)filp->f_pos) { + /* data ready to read */ + return EPOLLIN | EPOLLRDNORM; + } + /* no data available, go to sleep */ + return 0; +} + static const struct file_operations log_sfile_dev_operations = { .owner = THIS_MODULE, .open = trusty_log_sfile_dev_open, + .poll = trusty_log_sfile_dev_poll, .read = seq_read, .release = seq_release, }; @@ -558,14 +624,15 @@ static bool trusty_supports_logging(struct device *device) return true; } -static int trusty_log_probe(struct platform_device *pdev) +static int trusty_log_init(struct platform_device *pdev) { struct trusty_log_state *s; + struct scatterlist *sg; + unsigned char *mem; + int i; int result; trusty_shared_mem_id_t mem_id; - - if (!trusty_supports_logging(pdev->dev.parent)) - return -ENXIO; + int log_size; s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) { @@ -573,20 +640,46 @@ static int trusty_log_probe(struct platform_device *pdev) goto error_alloc_state; } - spin_lock_init(&s->lock); s->dev = &pdev->dev; s->trusty_dev = s->dev->parent; - s->log_pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, - get_order(TRUSTY_LOG_SIZE)); - if (!s->log_pages) { + + s->log_num_pages = DIV_ROUND_UP(log_size_param + sizeof(struct log_rb), + PAGE_SIZE); + s->sg = kcalloc(s->log_num_pages, sizeof(*s->sg), GFP_KERNEL); + if (!s->sg) { + result = -ENOMEM; + goto error_alloc_sg; + } + + log_size = s->log_num_pages * PAGE_SIZE; + mem = vzalloc(log_size); + if (!mem) { result = -ENOMEM; goto error_alloc_log; } - s->log = page_address(s->log_pages); - sg_init_one(&s->sg, s->log, TRUSTY_LOG_SIZE); - result = trusty_share_memory_compat(s->trusty_dev, &mem_id, &s->sg, 1, - PAGE_KERNEL); + s->log = (struct log_rb *)mem; + + sg_init_table(s->sg, s->log_num_pages); + for_each_sg(s->sg, sg, s->log_num_pages, i) { + struct page *pg = vmalloc_to_page(mem + (i * PAGE_SIZE)); + + if (!pg) { + result = -ENOMEM; + goto err_share_memory; + } + sg_set_page(sg, pg, PAGE_SIZE, 0); + } + /* + * This will fail for Trusty api version < TRUSTY_API_VERSION_MEM_OBJ + * if s->log_num_pages > 1 + * Use trusty_share_memory_compat instead of trusty_share_memory in case + * s->log_num_pages == 1 and api version < TRUSTY_API_VERSION_MEM_OBJ, + * In that case SMC_SC_SHARED_LOG_ADD expects a different value than + * what trusty_share_memory returns + */ + result = trusty_share_memory_compat(s->trusty_dev, &mem_id, s->sg, + s->log_num_pages, PAGE_KERNEL); if (result) { dev_err(s->dev, "trusty_share_memory failed: %d\n", result); goto err_share_memory; @@ -596,7 +689,7 @@ static int trusty_log_probe(struct platform_device *pdev) result = trusty_std_call32(s->trusty_dev, SMC_SC_SHARED_LOG_ADD, (u32)(mem_id), (u32)(mem_id >> 32), - TRUSTY_LOG_SIZE); + log_size); if (result < 0) { dev_err(s->dev, "trusty std call (SMC_SC_SHARED_LOG_ADD) failed: %d 0x%llx\n", @@ -604,6 +697,9 @@ static int trusty_log_probe(struct platform_device *pdev) goto error_std_call; } + init_waitqueue_head(&s->poll_waiters); + spin_lock_init(&s->wake_up_lock); + s->call_notifier.notifier_call = trusty_log_call_notify; result = trusty_call_notifier_register(s->trusty_dev, &s->call_notifier); @@ -641,7 +737,8 @@ error_call_notifier: trusty_std_call32(s->trusty_dev, SMC_SC_SHARED_LOG_RM, (u32)mem_id, (u32)(mem_id >> 32), 0); error_std_call: - if (WARN_ON(trusty_reclaim_memory(s->trusty_dev, mem_id, &s->sg, 1))) { + if (WARN_ON(trusty_reclaim_memory(s->trusty_dev, mem_id, s->sg, + s->log_num_pages))) { dev_err(&pdev->dev, "trusty_revoke_memory failed: %d 0x%llx\n", result, mem_id); /* @@ -650,14 +747,32 @@ error_std_call: */ } else { err_share_memory: - __free_pages(s->log_pages, get_order(TRUSTY_LOG_SIZE)); + vfree(s->log); } error_alloc_log: + kfree(s->sg); +error_alloc_sg: kfree(s); error_alloc_state: return result; } +static int trusty_log_probe(struct platform_device *pdev) +{ + int rc; + + if (!trusty_supports_logging(pdev->dev.parent)) + return -ENXIO; + + rc = trusty_log_init(pdev); + if (rc && log_size_param > TRUSTY_LOG_MIN_SIZE) { + dev_warn(&pdev->dev, "init failed, retrying with 1-page log\n"); + log_size_param = TRUSTY_LOG_MIN_SIZE; + rc = trusty_log_init(pdev); + } + return rc; +} + static int trusty_log_remove(struct platform_device *pdev) { int result; @@ -676,7 +791,8 @@ static int trusty_log_remove(struct platform_device *pdev) "trusty std call (SMC_SC_SHARED_LOG_RM) failed: %d\n", result); } - result = trusty_reclaim_memory(s->trusty_dev, mem_id, &s->sg, 1); + result = trusty_reclaim_memory(s->trusty_dev, mem_id, s->sg, + s->log_num_pages); if (WARN_ON(result)) { dev_err(&pdev->dev, "trusty failed to remove shared memory: %d\n", result); @@ -685,8 +801,9 @@ static int trusty_log_remove(struct platform_device *pdev) * It is not safe to free this memory if trusty_revoke_memory * fails. Leak it in that case. */ - __free_pages(s->log_pages, get_order(TRUSTY_LOG_SIZE)); + vfree(s->log); } + kfree(s->sg); kfree(s); return 0; diff --git a/drivers/trusty/trusty-virtio.c b/drivers/trusty/trusty-virtio.c index fea59cd..8a7eb69 100644 --- a/drivers/trusty/trusty-virtio.c +++ b/drivers/trusty/trusty-virtio.c @@ -31,6 +31,8 @@ #define RSC_DESCR_VER 1 struct trusty_vdev; +static bool use_high_wq; +module_param(use_high_wq, bool, 0660); struct trusty_ctx { struct device *dev; @@ -45,6 +47,7 @@ struct trusty_ctx { struct mutex mlock; /* protects vdev_list */ struct workqueue_struct *kick_wq; struct workqueue_struct *check_wq; + struct workqueue_struct *check_wq_high; }; struct trusty_vring { @@ -99,7 +102,10 @@ static int trusty_call_notify(struct notifier_block *nb, return NOTIFY_DONE; tctx = container_of(nb, struct trusty_ctx, call_notifier); - queue_work(tctx->check_wq, &tctx->check_vqs); + if (use_high_wq) + queue_work(tctx->check_wq_high, &tctx->check_vqs); + else + queue_work(tctx->check_wq, &tctx->check_vqs); return NOTIFY_OK; } @@ -751,6 +757,14 @@ static int trusty_virtio_probe(struct platform_device *pdev) goto err_create_kick_wq; } + tctx->check_wq_high = alloc_workqueue("trusty-check-wq-high", + WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!tctx->check_wq_high) { + ret = -ENODEV; + dev_err(&pdev->dev, "Failed create trusty-check-wq-high\n"); + goto err_create_check_wq_high; + } + ret = trusty_virtio_add_devices(tctx); if (ret) { dev_err(&pdev->dev, "Failed to add virtio devices\n"); @@ -761,6 +775,8 @@ static int trusty_virtio_probe(struct platform_device *pdev) return 0; err_add_devices: + destroy_workqueue(tctx->check_wq_high); +err_create_check_wq_high: destroy_workqueue(tctx->kick_wq); err_create_kick_wq: destroy_workqueue(tctx->check_wq); @@ -786,6 +802,7 @@ static int trusty_virtio_remove(struct platform_device *pdev) /* destroy workqueues */ destroy_workqueue(tctx->kick_wq); destroy_workqueue(tctx->check_wq); + destroy_workqueue(tctx->check_wq_high); /* notify remote that shared area goes away */ trusty_virtio_stop(tctx, tctx->shared_id, tctx->shared_sz); diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c index 265eab5..c773beb 100644 --- a/drivers/trusty/trusty.c +++ b/drivers/trusty/trusty.c @@ -24,6 +24,9 @@ struct trusty_state; static struct platform_driver trusty_driver; +static bool use_high_wq; +module_param(use_high_wq, bool, 0660); + struct trusty_work { struct trusty_state *ts; struct work_struct work; @@ -38,6 +41,7 @@ struct trusty_state { bool trusty_panicked; struct device *dev; struct workqueue_struct *nop_wq; + struct workqueue_struct *nop_wq_high; struct trusty_work __percpu *nop_works; struct list_head nop_queue; spinlock_t nop_lock; /* protects nop_queue */ @@ -753,9 +757,26 @@ static void nop_work_func(struct work_struct *work) u32 last_arg0; struct trusty_work *tw = container_of(work, struct trusty_work, work); struct trusty_state *s = tw->ts; + int old_nice = task_nice(current); + bool nice_changed = false; dequeue_nop(s, args); do { + /* + * In case use_high_wq flaged when trusty is not idle, + * change the work's prio directly. + */ + if (!WARN_ON(current->policy != SCHED_NORMAL)) { + if (use_high_wq && task_nice(current) != MIN_NICE) { + nice_changed = true; + set_user_nice(current, MIN_NICE); + } else if (!use_high_wq && + task_nice(current) == MIN_NICE) { + nice_changed = true; + set_user_nice(current, 0); + } + } + dev_dbg(s->dev, "%s: %x %x %x\n", __func__, args[0], args[1], args[2]); @@ -779,7 +800,11 @@ static void nop_work_func(struct work_struct *work) } } } while (next); - + /* + * Restore nice if even changed. + */ + if (nice_changed) + set_user_nice(current, old_nice); dev_dbg(s->dev, "%s: done\n", __func__); } @@ -799,7 +824,10 @@ void trusty_enqueue_nop(struct device *dev, struct trusty_nop *nop) list_add_tail(&nop->node, &s->nop_queue); spin_unlock_irqrestore(&s->nop_lock, flags); } - queue_work(s->nop_wq, &tw->work); + if (use_high_wq) + queue_work(s->nop_wq_high, &tw->work); + else + queue_work(s->nop_wq, &tw->work); preempt_enable(); } EXPORT_SYMBOL(trusty_enqueue_nop); @@ -873,6 +901,14 @@ static int trusty_probe(struct platform_device *pdev) goto err_create_nop_wq; } + s->nop_wq_high = alloc_workqueue("trusty-nop-wq-high", WQ_HIGHPRI | + WQ_CPU_INTENSIVE, 0); + if (!s->nop_wq_high) { + ret = -ENODEV; + dev_err(&pdev->dev, "Failed create trusty-nop-wq-high\n"); + goto err_create_nop_wq_high; + } + s->nop_works = alloc_percpu(struct trusty_work); if (!s->nop_works) { ret = -ENOMEM; @@ -908,6 +944,8 @@ err_add_children: } free_percpu(s->nop_works); err_alloc_works: + destroy_workqueue(s->nop_wq_high); +err_create_nop_wq_high: destroy_workqueue(s->nop_wq); err_create_nop_wq: trusty_free_msg_buf(s, &pdev->dev); @@ -937,6 +975,7 @@ static int trusty_remove(struct platform_device *pdev) } free_percpu(s->nop_works); destroy_workqueue(s->nop_wq); + destroy_workqueue(s->nop_wq_high); mutex_destroy(&s->share_memory_msg_lock); mutex_destroy(&s->smc_lock); diff --git a/include/linux/trusty/trusty.h b/include/linux/trusty/trusty.h index ec53eb2..efbb369 100644 --- a/include/linux/trusty/trusty.h +++ b/include/linux/trusty/trusty.h @@ -85,6 +85,33 @@ static inline u64 trusty_dma_buf_get_ffa_tag(struct dma_buf *dma_buf) } #endif +/* Invalid handle value is defined by FF-A spec */ +#ifdef CONFIG_TRUSTY_DMA_BUF_SHARED_MEM_ID +/** + * trusty_dma_buf_get_shared_mem_id() - Get memory ID corresponding to a dma_buf + * @dma_buf: DMA buffer + * @id: Pointer to output trusty_shared_mem_id_t + * + * Sets @id to trusty_shared_mem_id_t corresponding to the given @dma_buf. + * @dma_buf "owns" the ID, i.e. is responsible for allocating/releasing it. + * @dma_buf with an allocated @id must be in secure memory and should only be + * sent to Trusty using TRUSTY_SEND_SECURE. + * + * Return: + * * 0 - success + * * -ENODATA - @dma_buf does not own a trusty_shared_mem_id_t + * * ... - @dma_buf should not be lent or shared + */ +int trusty_dma_buf_get_shared_mem_id(struct dma_buf *dma_buf, + trusty_shared_mem_id_t *id); +#else +static inline int trusty_dma_buf_get_shared_mem_id(struct dma_buf *dma_buf, + trusty_shared_mem_id_t *id) +{ + return -ENODATA; +} +#endif + struct trusty_nop { struct list_head node; u32 args[3]; diff --git a/include/uapi/linux/trusty/ipc.h b/include/uapi/linux/trusty/ipc.h index 20cdd90..af91035 100644 --- a/include/uapi/linux/trusty/ipc.h +++ b/include/uapi/linux/trusty/ipc.h @@ -9,15 +9,19 @@ /** * enum transfer_kind - How to send an fd to Trusty - * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it will - * be mapped as nonsecure. Suitable for shared memory. The paired - * fd must be a "memfd". - * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will be - * transitioned to "Secure" memory if Trusty is in TrustZone. - * This transfer kind is suitable for donating video buffers or - * other similar resources. The paired fd may need to come from a - * platform-specific allocator for memory that may be - * transitioned to "Secure". + * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it + * will be mapped as nonsecure. Suitable for shared memory. + * The paired fd must be a "dma_buf". + * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will + * be transitioned to "Secure" memory if Trusty is in + * TrustZone. This transfer kind is suitable for donating + * video buffers or other similar resources. The paired fd + * may need to come from a platform-specific allocator for + * memory that may be transitioned to "Secure". + * @TRUSTY_SEND_SECURE: Send memory that is already "Secure". Memory will be + * accessible only to Trusty. The paired fd may need to + * come from a platform-specific allocator that returns + * "Secure" buffers. * * Describes how the user would like the resource in question to be sent to * Trusty. Options may be valid only for certain kinds of fds. @@ -25,6 +29,7 @@ enum transfer_kind { TRUSTY_SHARE = 0, TRUSTY_LEND = 1, + TRUSTY_SEND_SECURE = 2, }; /** |