diff options
author | Steve Pfetsch <spfetsch@google.com> | 2017-10-12 19:41:38 -0700 |
---|---|---|
committer | Steve Pfetsch <spfetsch@google.com> | 2017-10-12 19:41:38 -0700 |
commit | 33ace82f84ba203ceb58b2c28a0f2e3389870030 (patch) | |
tree | 2fe60ab39b8266a3de8b4feabd47490d6d7bd56f | |
parent | 6ba119257516c87a577993487c0b5aaa1ab0c0a1 (diff) | |
parent | e40328e12f0eee2436cdfa83aa519e3c490daf62 (diff) |
Merge branch 'android-msm-angler-3.10-oc' into android-msm-angler-3.10android-o-mr1-preview-2_r0.1android-8.1.0_r0.1
December 2017.1
Bug: 67749245
Change-Id: I3cc87859f6679d5c91a622d101a172f2a0598520
73 files changed, 997 insertions, 8726 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 69c7c1c99fbf..7cee566fad87 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -172,8 +172,6 @@ source "drivers/irqchip/Kconfig" source "drivers/ipack/Kconfig" -source "drivers/gud/Kconfig" - source "drivers/reset/Kconfig" source "drivers/coresight/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 1e45a0a5cafa..3f56ff9e6fbf 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -159,9 +159,6 @@ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_IPACK_BUS) += ipack/ obj-$(CONFIG_NTB) += ntb/ -#MobiCore -obj-$(CONFIG_MOBICORE_SUPPORT) += gud/ - obj-$(CONFIG_CORESIGHT) += coresight/ obj-$(CONFIG_ESOC) += esoc/ diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 80a46020c5bf..c5c7b4325991 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017 The Linux Foundation. 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 @@ -342,6 +342,7 @@ void diag_dci_wakeup_clients() struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; + mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); @@ -357,6 +358,7 @@ void diag_dci_wakeup_clients() DCI_DATA_TYPE); } } + mutex_unlock(&driver->dci_mutex); } void dci_data_drain_work_fn(struct work_struct *work) @@ -367,6 +369,7 @@ void dci_data_drain_work_fn(struct work_struct *work) struct diag_dci_buf_peripheral_t *proc_buf = NULL; struct diag_dci_buffer_t *buf_temp = NULL; + mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); for (i = 0; i < entry->num_buffers; i++) { @@ -396,6 +399,7 @@ void dci_data_drain_work_fn(struct work_struct *work) DCI_DATA_TYPE); } } + mutex_unlock(&driver->dci_mutex); dci_timer_in_progress = 0; } @@ -561,6 +565,8 @@ start: buf += header_len + dci_pkt_len; /* advance to next DCI pkt */ } end: + if (err) + return err; /* wake up all sleeping DCI clients which have some data */ diag_dci_wakeup_clients(); dci_check_drain_timer(); @@ -621,6 +627,8 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, buf += 5 + dci_pkt_len; /* advance to next DCI pkt */ } + if (err) + return err; /* wake up all sleeping DCI clients which have some data */ diag_dci_wakeup_clients(); dci_check_drain_timer(); @@ -967,9 +975,11 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, return; } + mutex_lock(&driver->dci_mutex); req_entry = diag_dci_get_request_entry(tag); if (!req_entry) { - pr_err("diag: No matching client for DCI data\n"); + pr_err_ratelimited("diag: No matching client for DCI data\n"); + mutex_unlock(&driver->dci_mutex); return; } @@ -977,18 +987,17 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, if (!entry) { pr_err("diag: In %s, couldn't find client entry, id:%d\n", __func__, req_entry->client_id); + mutex_unlock(&driver->dci_mutex); return; } save_req_uid = req_entry->uid; /* Remove the headers and send only the response to this function */ - mutex_lock(&driver->dci_mutex); delete_flag = diag_dci_remove_req_entry(temp, rsp_len, req_entry); if (delete_flag < 0) { mutex_unlock(&driver->dci_mutex); return; } - mutex_unlock(&driver->dci_mutex); rsp_buf = entry->buffers[data_source].buf_cmd; @@ -1006,6 +1015,7 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, if (!temp_buf) { pr_err("diag: DCI realloc failed\n"); mutex_unlock(&rsp_buf->data_mutex); + mutex_unlock(&driver->dci_mutex); return; } else { rsp_buf->data = temp_buf; @@ -1041,6 +1051,7 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, * for log and event buffers to be full */ dci_add_buffer_to_list(entry, rsp_buf); + mutex_unlock(&driver->dci_mutex); } static void copy_dci_event(unsigned char *buf, int len, @@ -1176,6 +1187,7 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) the event data */ total_event_len = 2 + 10 + payload_len_field + payload_len; /* parse through event mask tbl of each client and check mask */ + mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); @@ -1187,6 +1199,7 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) entry, data_source); } } + mutex_unlock(&driver->dci_mutex); } } @@ -1278,6 +1291,7 @@ void extract_dci_log(unsigned char *buf, int len, int data_source, int token) } /* parse through log mask table of each client and check mask */ + mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); if (entry->client_info.token != token) @@ -1289,6 +1303,7 @@ void extract_dci_log(unsigned char *buf, int len, int data_source, int token) copy_dci_log(buf, len, entry, data_source); } } + mutex_unlock(&driver->dci_mutex); } void diag_update_smd_dci_work_fn(struct work_struct *work) @@ -1312,6 +1327,7 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) * which log entries in the cumulative logs that need * to be updated on the peripheral. */ + mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); if (entry->client_info.token != DCI_LOCAL_PROC) @@ -1323,6 +1339,7 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) client_log_mask_ptr += 514; } } + mutex_unlock(&driver->dci_mutex); mutex_lock(&dci_log_mask_mutex); /* Update the appropriate dirty bits in the cumulative mask */ @@ -2971,13 +2988,12 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) return DIAG_DCI_NOT_SUPPORTED; token = entry->client_info.token; - - mutex_lock(&driver->dci_mutex); /* * Remove the entry from the list before freeing the buffers * to ensure that we don't have any invalid access. */ - list_del(&entry->track); + if (!list_empty(&entry->track)) + list_del(&entry->track); driver->num_dci_client--; /* * Clear the client's log and event masks, update the cumulative @@ -3006,7 +3022,8 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) req_entry = list_entry(start, struct dci_pkt_req_entry_t, track); if (req_entry->client_id == entry->client_info.client_id) { - list_del(&req_entry->track); + if (!list_empty(&req_entry->track)) + list_del(&req_entry->track); kfree(req_entry); } } @@ -3015,7 +3032,8 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) mutex_lock(&entry->write_buf_mutex); list_for_each_entry_safe(buf_entry, temp, &entry->list_write_buf, buf_track) { - list_del(&buf_entry->buf_track); + if (!list_empty(&buf_entry->buf_track)) + list_del(&buf_entry->buf_track); if (buf_entry->buf_type == DCI_BUF_SECONDARY) { mutex_lock(&buf_entry->data_mutex); diagmem_free(driver, buf_entry->data, POOL_TYPE_DCI); @@ -3084,8 +3102,6 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) } queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work); - mutex_unlock(&driver->dci_mutex); - return DIAG_DCI_NO_ERROR; } diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index d510af49f503..c9461d65d7e6 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -348,9 +348,11 @@ static int diagchar_close(struct inode *inode, struct file *file) * This will specially help in case of ungraceful exit of any DCI client * This call will remove any pending registrations of such client */ + mutex_lock(&driver->dci_mutex); dci_entry = dci_lookup_client_entry_pid(current->pid); if (dci_entry) diag_dci_deinit_client(dci_entry); + mutex_unlock(&driver->dci_mutex); /* If the exiting process is the socket process */ mutex_lock(&driver->diagchar_mutex); if (driver->socket_process && @@ -1250,37 +1252,57 @@ long diagchar_compat_ioctl(struct file *filp, result = diag_ioctl_dci_reg(ioarg); break; case DIAG_IOCTL_DCI_DEINIT: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } dci_client = diag_dci_get_client_entry(client_id); - if (!dci_client) + if (!dci_client) { + mutex_unlock(&driver->dci_mutex); return DIAG_DCI_NOT_SUPPORTED; + } result = diag_dci_deinit_client(dci_client); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_SUPPORT: result = diag_ioctl_dci_support(ioarg); break; case DIAG_IOCTL_DCI_HEALTH_STATS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_health_stats(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_LOG_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_log_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_EVENT_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_event_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_LOGS: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_log_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_EVENTS: + mutex_lock(&driver->dci_mutex); if (copy_from_user(&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_event_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_LSM_DEINIT: result = diag_ioctl_lsm_deinit(); @@ -1300,7 +1322,9 @@ long diagchar_compat_ioctl(struct file *filp, result = 1; break; case DIAG_IOCTL_VOTE_REAL_TIME: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_vote_real_time(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_GET_REAL_TIME: result = diag_ioctl_get_real_time(ioarg); @@ -1347,37 +1371,57 @@ long diagchar_ioctl(struct file *filp, result = diag_ioctl_dci_reg(ioarg); break; case DIAG_IOCTL_DCI_DEINIT: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } dci_client = diag_dci_get_client_entry(client_id); - if (!dci_client) + if (!dci_client) { + mutex_unlock(&driver->dci_mutex); return DIAG_DCI_NOT_SUPPORTED; + } result = diag_dci_deinit_client(dci_client); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_SUPPORT: result = diag_ioctl_dci_support(ioarg); break; case DIAG_IOCTL_DCI_HEALTH_STATS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_health_stats(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_LOG_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_log_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_EVENT_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_event_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_LOGS: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_log_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_EVENTS: + mutex_lock(&driver->dci_mutex); if (copy_from_user(&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_event_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_LSM_DEINIT: result = diag_ioctl_lsm_deinit(); @@ -1397,7 +1441,9 @@ long diagchar_ioctl(struct file *filp, result = 1; break; case DIAG_IOCTL_VOTE_REAL_TIME: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_vote_real_time(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_GET_REAL_TIME: result = diag_ioctl_get_real_time(ioarg); @@ -1540,7 +1586,10 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, goto exit; } +exit: + mutex_unlock(&driver->diagchar_mutex); if (driver->data_ready[index] & DCI_DATA_TYPE) { + mutex_lock(&driver->dci_mutex); /* Copy the type of data being passed */ data_type = driver->data_ready[index] & DCI_DATA_TYPE; list_for_each_safe(start, temp, &driver->dci_client_list) { @@ -1550,16 +1599,28 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, continue; if (!entry->in_service) continue; - COPY_USER_SPACE_OR_EXIT(buf + ret, data_type, - sizeof(int)); - COPY_USER_SPACE_OR_EXIT(buf + ret, - entry->client_info.token, sizeof(int)); + if (copy_to_user(buf + ret, &data_type, sizeof(int))) { + mutex_unlock(&driver->dci_mutex); + goto end; + } + ret += sizeof(int); + if (copy_to_user(buf + ret, &entry->client_info.token, + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); + goto end; + } + ret += sizeof(int); copy_dci_data = 1; exit_stat = diag_copy_dci(buf, count, entry, &ret); + mutex_lock(&driver->diagchar_mutex); driver->data_ready[index] ^= DCI_DATA_TYPE; - if (exit_stat == 1) - goto exit; + mutex_unlock(&driver->diagchar_mutex); + if (exit_stat == 1) { + mutex_unlock(&driver->dci_mutex); + goto end; + } } + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) { if (driver->smd_dci[i].ch) { queue_work(driver->diag_dci_wq, @@ -1577,10 +1638,11 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, } } } - goto exit; + mutex_unlock(&driver->diagchar_mutex); + mutex_unlock(&driver->dci_mutex); + goto end; } -exit: - mutex_unlock(&driver->diagchar_mutex); +end: /* * Flush any read that is currently pending on DCI data and * command channnels. This will ensure that the next read is not diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c index 18208698cd09..a15acd12084a 100644 --- a/drivers/coresight/coresight-tmc.c +++ b/drivers/coresight/coresight-tmc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. 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 @@ -846,6 +846,14 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) return ret; mutex_lock(&drvdata->usb_lock); + spin_lock_irqsave(&drvdata->spinlock, flags); + if (drvdata->reading) { + ret = -EBUSY; + spin_unlock_irqrestore(&drvdata->spinlock, flags); + goto err0; + } + spin_unlock_irqrestore(&drvdata->spinlock, flags); + if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { coresight_cti_map_trigout(drvdata->cti_flush, 1, 0); coresight_cti_map_trigin(drvdata->cti_reset, 2, 0); @@ -892,10 +900,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) } spin_lock_irqsave(&drvdata->spinlock, flags); - if (drvdata->reading) { - ret = -EBUSY; - goto err1; - } if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { __tmc_etb_enable(drvdata); @@ -920,11 +924,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) dev_info(drvdata->dev, "TMC enabled\n"); return 0; -err1: - spin_unlock_irqrestore(&drvdata->spinlock, flags); - if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) - if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) - usb_qdss_close(drvdata->usbch); err0: mutex_unlock(&drvdata->usb_lock); clk_disable_unprepare(drvdata->clk); @@ -1317,6 +1316,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) unsigned long flags; enum tmc_mode mode; + mutex_lock(&drvdata->usb_lock); spin_lock_irqsave(&drvdata->spinlock, flags); if (!drvdata->sticky_enable) { dev_err(drvdata->dev, "enable tmc once before reading\n"); @@ -1347,11 +1347,13 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) out: drvdata->reading = true; spin_unlock_irqrestore(&drvdata->spinlock, flags); + mutex_unlock(&drvdata->usb_lock); dev_info(drvdata->dev, "TMC read start\n"); return 0; err: spin_unlock_irqrestore(&drvdata->spinlock, flags); + mutex_unlock(&drvdata->usb_lock); return ret; } @@ -1533,8 +1535,12 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, { struct tmc_drvdata *drvdata = container_of(file->private_data, struct tmc_drvdata, miscdev); - char *bufp = drvdata->buf + *ppos; - char *end = (char *)(drvdata->vaddr + drvdata->size); + char *bufp, *end; + + mutex_lock(&drvdata->usb_lock); + + bufp = drvdata->buf + *ppos; + end = (char *)(drvdata->vaddr + drvdata->size); if (*ppos + len > drvdata->size) len = drvdata->size - *ppos; @@ -1561,6 +1567,7 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, if (copy_to_user(data, bufp, len)) { dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__); + mutex_unlock(&drvdata->usb_lock); return -EFAULT; } @@ -1568,6 +1575,8 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, out: dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", __func__, len, (int) (drvdata->size - *ppos)); + + mutex_unlock(&drvdata->usb_lock); return len; } diff --git a/drivers/gud/Kconfig b/drivers/gud/Kconfig deleted file mode 100644 index d643ab8fcd58..000000000000 --- a/drivers/gud/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -# -# MobiCore configuration -# -config MOBICORE_SUPPORT - tristate "Linux MobiCore Support" - depends on ARCH_MSM - ---help--- - Enable Linux Kernel MobiCore Support - -config MOBICORE_DEBUG - bool "MobiCore Module debug mode" - depends on MOBICORE_SUPPORT - ---help--- - Enable Debug mode in the MobiCore Driver. - It enables printing information about MobiCore operations - -config MOBICORE_VERBOSE - bool "MobiCore Module verbose debug mode" - depends on MOBICORE_DEBUG - ---help--- - Enable Verbose Debug mode in the MobiCore Driver. - It enables printing extra information about MobiCore operations - Beware: this is only useful for debuging deep in the driver because - it prints too much logs - - -config MOBICORE_API - tristate "Linux MobiCore API" - depends on MOBICORE_SUPPORT - ---help--- - Enable Linux Kernel MobiCore API diff --git a/drivers/gud/Makefile b/drivers/gud/Makefile deleted file mode 100644 index 69d88ec40b60..000000000000 --- a/drivers/gud/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# -# Makefile for the kernel mobicore drivers -# -GUD_ROOT_FOLDER := drivers/gud -# add our modules to kernel. -obj-$(CONFIG_MOBICORE_API) += mcKernelApi.o -obj-$(CONFIG_MOBICORE_SUPPORT) += mcDrvModule.o - -mcDrvModule-objs := MobiCoreDriver/logging.o \ - MobiCoreDriver/ops.o \ - MobiCoreDriver/mem.o \ - MobiCoreDriver/api.o \ - MobiCoreDriver/pm.o \ - MobiCoreDriver/main.o - -mcKernelApi-objs := MobiCoreKernelApi/main.o \ - MobiCoreKernelApi/clientlib.o \ - MobiCoreKernelApi/device.o \ - MobiCoreKernelApi/session.o \ - MobiCoreKernelApi/connection.o - -# Release mode by default -ccflags-y := -DNDEBUG -I$(GUD_ROOT_FOLDER) -ccflags-y += -Wno-declaration-after-statement - -#Netlink changed arguments number -ccflags-y += -DMC_NETLINK_COMPAT_V37 - -ccflags-$(CONFIG_MOBICORE_DEBUG) += -DDEBUG -ccflags-$(CONFIG_MOBICORE_VERBOSE) += -DDEBUG_VERBOSE - -# Choose one platform from the folder -MOBICORE_PLATFORM := $(shell (ls -1 $(srctree)/$(GUD_ROOT_FOLDER)/MobiCoreDriver/platforms | tail -1) ) -# Use the available platform folder -ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/platforms/$(MOBICORE_PLATFORM) -# MobiCore Driver includes -ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/public -# MobiCore KernelApi required incldes -ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/include -ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/public diff --git a/drivers/gud/MobiCoreDriver/Makefile b/drivers/gud/MobiCoreDriver/Makefile deleted file mode 100644 index c97c0d7d50a1..000000000000 --- a/drivers/gud/MobiCoreDriver/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# this makefile is called from the kernel make system. Thus we basically -# add things to "obj-m" here. - -ifeq ($(MODE),release) - ccflags-y = -O2 -DNDEBUG -else - ccflags-y = -DDEBUG -endif # DEBUG/RELEASE - -# CFLAG for testable mode -ifeq ($(IS_TESTABLE),yes) - ccflags-y = -DTEST -endif - -# CFLAGS from the build script -ifdef MOBICORE_CFLAGS - ccflags-y += $(MOBICORE_CFLAGS) -endif -#EXTRA_CFLAGS+=-DDEBUG_VERBOSE - -ccflags-y += -Wall -D__$(PLATFORM)__ -# add our module to kernel. -obj-m += mcDrvModule.o - -mcDrvModule-objs :=logging.o ops.o mem.o api.o pm.o main.o - -clean: - rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \ - Module.markers Module.symvers modules.order - diff --git a/drivers/gud/MobiCoreDriver/api.c b/drivers/gud/MobiCoreDriver/api.c deleted file mode 100644 index 755f80b39d26..000000000000 --- a/drivers/gud/MobiCoreDriver/api.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include <linux/module.h> - -#include "main.h" -#include "mem.h" -#include "debug.h" - -int mobicore_map_vmem(struct mc_instance *instance, void *addr, - uint32_t len, uint32_t *handle) -{ - phys_addr_t phys; - return mc_register_wsm_mmu(instance, addr, len, - handle, &phys); -} -EXPORT_SYMBOL(mobicore_map_vmem); - -/* - * Unmap a virtual memory buffer from mobicore - * @param instance - * @param handle - * - * @return 0 if no error - * - */ -int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle) -{ - return mc_unregister_wsm_mmu(instance, handle); -} -EXPORT_SYMBOL(mobicore_unmap_vmem); - -/* - * Free a WSM buffer allocated with mobicore_allocate_wsm - * @param instance - * @param handle handle of the buffer - * - * @return 0 if no error - * - */ -int mobicore_free_wsm(struct mc_instance *instance, uint32_t handle) -{ - return mc_free_buffer(instance, handle); -} -EXPORT_SYMBOL(mobicore_free_wsm); - - -/* - * Allocate WSM for given instance - * - * @param instance instance - * @param requested_size size of the WSM - * @param handle pointer where the handle will be saved - * @param virt_kernel_addr pointer for the kernel virtual address - * - * @return error code or 0 for success - */ -int mobicore_allocate_wsm(struct mc_instance *instance, - unsigned long requested_size, uint32_t *handle, void **virt_kernel_addr) -{ - struct mc_buffer *buffer = NULL; - - /* Setup the WSM buffer structure! */ - if (mc_get_buffer(instance, &buffer, requested_size)) - return -EFAULT; - - *handle = buffer->handle; - *virt_kernel_addr = buffer->addr; - return 0; -} -EXPORT_SYMBOL(mobicore_allocate_wsm); - -/* - * Initialize a new mobicore API instance object - * - * @return Instance or NULL if no allocation was possible. - */ -struct mc_instance *mobicore_open(void) -{ - struct mc_instance *instance = mc_alloc_instance(); - if(instance) { - instance->admin = true; - } - return instance; -} -EXPORT_SYMBOL(mobicore_open); - -/* - * Release a mobicore instance object and all objects related to it - * @param instance instance - * @return 0 if Ok or -E ERROR - */ -int mobicore_release(struct mc_instance *instance) -{ - return mc_release_instance(instance); -} -EXPORT_SYMBOL(mobicore_release); - -/* - * Test if mobicore can sleep - * - * @return true if mobicore can sleep, false if it can't sleep - */ -bool mobicore_sleep_ready(void) -{ - return mc_sleep_ready(); -} -EXPORT_SYMBOL(mobicore_sleep_ready); - diff --git a/drivers/gud/MobiCoreDriver/arm.h b/drivers/gud/MobiCoreDriver/arm.h deleted file mode 100644 index 8c9fc37eee22..000000000000 --- a/drivers/gud/MobiCoreDriver/arm.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_ARM_H_ -#define _MC_ARM_H_ - -#include "debug.h" - -#ifdef CONFIG_ARM64 -inline bool has_security_extensions(void) -{ - return true; -} - -inline bool is_secure_mode(void) -{ - return false; -} -#else -/* - * ARM Trustzone specific masks and modes - * Vanilla Linux is unaware of TrustZone extension. - * I.e. arch/arm/include/asm/ptrace.h does not define monitor mode. - * Also TZ bits in cpuid are not defined, ARM port uses magic numbers, - * see arch/arm/kernel/setup.c - */ -#define ARM_MONITOR_MODE (0x16) /*(0b10110)*/ -#define ARM_SECURITY_EXTENSION_MASK (0x30) - -/* check if CPU supports the ARM TrustZone Security Extensions */ -inline bool has_security_extensions(void) -{ - u32 fea = 0; - asm volatile( - "mrc p15, 0, %[fea], cr0, cr1, 0" : - [fea]"=r" (fea)); - - MCDRV_DBG_VERBOSE(mcd, "CPU Features: 0x%X", fea); - - /* - * If the CPU features ID has 0 for security features then the CPU - * doesn't support TrustZone at all! - */ - if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0) - return false; - - return true; -} - -/* check if running in secure mode */ -inline bool is_secure_mode(void) -{ - u32 cpsr = 0; - u32 nsacr = 0; - - asm volatile( - "mrc p15, 0, %[nsacr], cr1, cr1, 2\n" - "mrs %[cpsr], cpsr\n" : - [nsacr]"=r" (nsacr), - [cpsr]"=r"(cpsr)); - - MCDRV_DBG_VERBOSE(mcd, "CPRS.M = set to 0x%X\n", cpsr & MODE_MASK); - MCDRV_DBG_VERBOSE(mcd, "SCR.NS = set to 0x%X\n", nsacr); - - /* - * If the NSACR contains the reset value(=0) then most likely we are - * running in Secure MODE. - * If the cpsr mode is set to monitor mode then we cannot load! - */ - if (nsacr == 0 || ((cpsr & MODE_MASK) == ARM_MONITOR_MODE)) - return true; - - return false; -} -#endif - -#endif /* _MC_ARM_H_ */ diff --git a/drivers/gud/MobiCoreDriver/build.sh b/drivers/gud/MobiCoreDriver/build.sh deleted file mode 100644 index db8410c39629..000000000000 --- a/drivers/gud/MobiCoreDriver/build.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -# source the setup script -if [ -z $COMP_PATH_ROOT ]; then - echo "The build environment is not set!" - echo "Trying to source setupDrivers.sh automatically!" - source ../setupDrivers.sh || exit 1 -fi - -ROOT_PATH=$(dirname $(readlink -f $0)) -# These folders need to be relative to the kernel dir or absolute! -PLATFORM=EXYNOS_5410_STD -CODE_INCLUDE=$(readlink -f $ROOT_PATH/Locals/Code) -PLATFORM_INCLUDE="$CODE_INCLUDE/platforms/$PLATFORM" -MOBICORE_DAEMON=$COMP_PATH_MobiCoreDriverLib/Public - -MOBICORE_CFLAGS="-I$MOBICORE_DRIVER/Public -I$MOBICORE_DAEMON -I$COMP_PATH_MobiCore/inc/Mci -I$COMP_PATH_MobiCore/inc -I${PLATFORM_INCLUDE}" - -# Clean first -make -C $CODE_INCLUDE clean - -make -C $LINUX_PATH \ - MODE=$MODE \ - ARCH=arm \ - CROSS_COMPILE=$CROSS_COMPILE \ - M=$CODE_INCLUDE \ - "MOBICORE_CFLAGS=$MOBICORE_CFLAGS" \ - modules diff --git a/drivers/gud/MobiCoreDriver/debug.h b/drivers/gud/MobiCoreDriver/debug.h deleted file mode 100644 index 52362b346552..000000000000 --- a/drivers/gud/MobiCoreDriver/debug.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_DEBUG_H_ -#define _MC_DEBUG_H_ -/* Found in main.c */ -extern struct device *mcd; - -#define MCDRV_DBG_ERROR(dev, txt, ...) \ - dev_err(dev, "MobiCore %s() ### ERROR: " txt "\n", \ - __func__, \ - ##__VA_ARGS__) - -/* dummy function helper macro. */ -#define DUMMY_FUNCTION() do {} while (0) - -#if defined(DEBUG) - -/* #define DEBUG_VERBOSE */ -#if defined(DEBUG_VERBOSE) -#define MCDRV_DBG_VERBOSE MCDRV_DBG -#else -#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() -#endif - -#define MCDRV_DBG(dev, txt, ...) \ - dev_info(dev, "MobiCore %s(): " txt "\n", \ - __func__, \ - ##__VA_ARGS__) - -#define MCDRV_DBG_WARN(dev, txt, ...) \ - dev_warn(dev, "MobiCore %s() WARNING: " txt "\n", \ - __func__, \ - ##__VA_ARGS__) - -#define MCDRV_ASSERT(cond) \ - do { \ - if (unlikely(!(cond))) { \ - panic("Assertion failed: %s:%d\n", \ - __FILE__, __LINE__); \ - } \ - } while (0) - -#else - -#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() -#define MCDRV_DBG(...) DUMMY_FUNCTION() -#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION() - -#define MCDRV_ASSERT(...) DUMMY_FUNCTION() - -#endif /* [not] defined(DEBUG) */ - -#endif /* _MC_DEBUG_H_ */ diff --git a/drivers/gud/MobiCoreDriver/fastcall.h b/drivers/gud/MobiCoreDriver/fastcall.h deleted file mode 100644 index 1b2e2a67d8fc..000000000000 --- a/drivers/gud/MobiCoreDriver/fastcall.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_FASTCALL_H_ -#define _MC_FASTCALL_H_ - -#include "debug.h" -#include "platform.h" - -/* Use the arch_extension sec pseudo op before switching to secure world */ -#if defined(__GNUC__) && \ - defined(__GNUC_MINOR__) && \ - defined(__GNUC_PATCHLEVEL__) && \ - ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)) \ - >= 40502 -#ifndef CONFIG_ARM64 -#define MC_ARCH_EXTENSION_SEC -#endif -#endif - -/* - * MobiCore SMCs - */ -#define MC_SMC_N_YIELD 0x3 /* Yield to switch from NWd to SWd. */ -#define MC_SMC_N_SIQ 0x4 /* SIQ to switch from NWd to SWd. */ - -/* - * MobiCore fast calls. See MCI documentation - */ -#ifdef MC_AARCH32_FC - -#define MC_FC_STD64_BASE ((uint32_t)0xFF000000) -/**< Initializing FastCall. */ -#define MC_FC_INIT (MC_FC_STD64_BASE+1) -/**< Info FastCall. */ -#define MC_FC_INFO (MC_FC_STD64_BASE+2) -/**< Enable SWd tracing via memory */ -#define MC_FC_NWD_TRACE (MC_FC_STD64_BASE+10) -#ifdef TBASE_CORE_SWITCHER -/**< Core switching fastcall */ -#define MC_FC_SWITCH_CORE (MC_FC_STD64_BASE+54) -#endif - -#else - -#define MC_FC_INIT -1 -#define MC_FC_INFO -2 -#define MC_FC_NWD_TRACE -31 -#ifdef TBASE_CORE_SWITCHER -#define MC_FC_SWITCH_CORE 0x84000005 -#endif -#endif - -/* - * return code for fast calls - */ -#define MC_FC_RET_OK 0 -#define MC_FC_RET_ERR_INVALID 1 -#define MC_FC_RET_ERR_ALREADY_INITIALIZED 5 - - -/* structure wrappers for specific fastcalls */ - -/* generic fast call parameters */ -union fc_generic { - struct { - uint32_t cmd; - uint32_t param[3]; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t param[2]; - } as_out; -}; - -/* fast call init */ -union mc_fc_init { - union fc_generic as_generic; - struct { - uint32_t cmd; - uint32_t base; - uint32_t nq_info; - uint32_t mcp_info; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t rfu[2]; - } as_out; -}; - -/* fast call info parameters */ -union mc_fc_info { - union fc_generic as_generic; - struct { - uint32_t cmd; - uint32_t ext_info_id; - uint32_t rfu[2]; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t state; - uint32_t ext_info; - } as_out; -}; - -#ifdef TBASE_CORE_SWITCHER -/* fast call switch Core parameters */ -union mc_fc_swich_core { - union fc_generic as_generic; - struct { - uint32_t cmd; - uint32_t core_id; - uint32_t rfu[2]; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t state; - uint32_t ext_info; - } as_out; -}; -#endif -/* - * _smc() - fast call to MobiCore - * - * @data: pointer to fast call data - */ -#ifdef CONFIG_ARM64 -static inline long _smc(void *data) -{ - int ret = 0; - - if (data == NULL) - return -EPERM; - - #ifdef MC_SMC_FASTCALL - { - ret = smc_fastcall(data, sizeof(union fc_generic)); - } - #else - { - union fc_generic *fc_generic = data; - /* SMC expect values in x0-x3 */ - register u64 reg0 __asm__("x0") = fc_generic->as_in.cmd; - register u64 reg1 __asm__("x1") = fc_generic->as_in.param[0]; - register u64 reg2 __asm__("x2") = fc_generic->as_in.param[1]; - register u64 reg3 __asm__("x3") = fc_generic->as_in.param[2]; - - __asm__ volatile ( - "smc #0\n" - : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3) - ); - - /* set response */ - fc_generic->as_out.resp = reg0; - fc_generic->as_out.ret = reg1; - fc_generic->as_out.param[0] = reg2; - fc_generic->as_out.param[1] = reg3; - } - #endif - return ret; -} - -#else -static inline long _smc(void *data) -{ - int ret = 0; - - if (data == NULL) - return -EPERM; - - #ifdef MC_SMC_FASTCALL - { - ret = smc_fastcall(data, sizeof(union fc_generic)); - } - #else - { - union fc_generic *fc_generic = data; - /* SMC expect values in r0-r3 */ - register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd; - register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0]; - register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1]; - register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2]; - - __asm__ volatile ( -#ifdef MC_ARCH_EXTENSION_SEC - /* This pseudo op is supported and required from - * binutils 2.21 on */ - ".arch_extension sec\n" -#endif - "smc #0\n" - : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3) - ); - - -#ifdef __ARM_VE_A9X4_QEMU__ - /* Qemu does not return to the address following the SMC - * instruction so we have to insert several nop instructions to - * workaround this Qemu bug. */ - __asm__ volatile ( - "nop\n" - "nop\n" - "nop\n" - "nop" - ); -#endif - - /* set response */ - fc_generic->as_out.resp = reg0; - fc_generic->as_out.ret = reg1; - fc_generic->as_out.param[0] = reg2; - fc_generic->as_out.param[1] = reg3; - } - #endif - return ret; -} -#endif - -/* - * convert fast call return code to linux driver module error code - */ -static inline int convert_fc_ret(uint32_t sret) -{ - int ret = -EFAULT; - - switch (sret) { - case MC_FC_RET_OK: - ret = 0; - break; - case MC_FC_RET_ERR_INVALID: - ret = -EINVAL; - break; - case MC_FC_RET_ERR_ALREADY_INITIALIZED: - ret = -EBUSY; - break; - default: - break; - } - return ret; -} - -#endif /* _MC_FASTCALL_H_ */ diff --git a/drivers/gud/MobiCoreDriver/logging.c b/drivers/gud/MobiCoreDriver/logging.c deleted file mode 100644 index 044e297dfcbd..000000000000 --- a/drivers/gud/MobiCoreDriver/logging.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * MobiCore Driver Logging Subsystem. - * - * The logging subsystem provides the interface between the Mobicore trace - * buffer and the Linux log - */ -#include <linux/miscdevice.h> -#include <linux/moduleparam.h> -#include <linux/kthread.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/device.h> - -#include "main.h" -#include "debug.h" -#include "ops.h" -#include "logging.h" - -/* Default length of the log ring buffer 256KB*/ -#define LOG_BUF_SIZE (64 * PAGE_SIZE) - -/* Max Len of a log line for printing */ -#define LOG_LINE_SIZE 256 - -static uint32_t log_size = LOG_BUF_SIZE; - -module_param(log_size, uint, 0); -MODULE_PARM_DESC(log_size, "Size of the MobiCore log ringbuffer(256KB def)"); - -/* Definitions for log version 2 */ -#define LOG_TYPE_MASK (0x0007) -#define LOG_TYPE_CHAR 0 -#define LOG_TYPE_INTEGER 1 -/* Field length */ -#define LOG_LENGTH_MASK (0x00F8) -#define LOG_LENGTH_SHIFT 3 -/* Extra attributes */ -#define LOG_EOL (0x0100) -#define LOG_INTEGER_DECIMAL (0x0200) -#define LOG_INTEGER_SIGNED (0x0400) - -struct logmsg_struct { - uint16_t ctrl; /* Type and format of data */ - uint16_t source; /* Unique value for each event source */ - uint32_t log_data; /* Value, if any */ -}; - -static uint16_t prev_source; /* Previous Log source */ -static uint32_t log_pos; /* MobiCore log previous position */ -static struct mc_trace_buf *log_buf; /* MobiCore log buffer structure */ -struct task_struct *log_thread; /* Log Thread task structure */ -static char *log_line; /* Log Line buffer */ -static uint32_t log_line_len; /* Log Line buffer current length */ -static int thread_err; - -static void log_eol(uint16_t source) -{ - if (!strnlen(log_line, LOG_LINE_SIZE)) { - /* In case a TA tries to print a 0x0 */ - log_line_len = 0; - return; - } - /* MobiCore Userspace */ - if (prev_source) - dev_info(mcd, "%03x|%s\n", prev_source, log_line); - /* MobiCore kernel */ - else - dev_info(mcd, "%s\n", log_line); - - log_line_len = 0; - log_line[0] = 0; -} - -/* - * Collect chars in log_line buffer and output the buffer when it is full. - * No locking needed because only "mobicore_log" thread updates this buffer. - */ -static void log_char(char ch, uint16_t source) -{ - if (ch == '\n' || ch == '\r') { - log_eol(source); - return; - } - - if (log_line_len >= LOG_LINE_SIZE - 1 || source != prev_source) - log_eol(source); - - - log_line[log_line_len] = ch; - log_line[log_line_len + 1] = 0; - log_line_len++; - prev_source = source; -} - -static const uint8_t HEX2ASCII[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - -static void dbg_raw_nro(uint32_t format, uint32_t value, uint16_t source) -{ - int digits = 1; - uint32_t base = (format & LOG_INTEGER_DECIMAL) ? 10 : 16; - int width = (format & LOG_LENGTH_MASK) >> LOG_LENGTH_SHIFT; - int negative = 0; - uint32_t digit_base = 1; - - if ((format & LOG_INTEGER_SIGNED) != 0 && ((signed int)value) < 0) { - negative = 1; - value = (uint32_t)(-(signed int)value); - width--; - } - - /* Find length and divider to get largest digit */ - while (value / digit_base >= base) { - digit_base *= base; - digits++; - } - - if (width > digits) { - char ch = (base == 10) ? ' ' : '0'; - while (width > digits) { - log_char(ch, source); - width--; - } - } - - if (negative) - log_char('-', source); - - while (digits-- > 0) { - uint32_t d = value / digit_base; - log_char(HEX2ASCII[d], source); - value = value - d * digit_base; - digit_base /= base; - } -} - -static void log_msg(struct logmsg_struct *msg) -{ - switch (msg->ctrl & LOG_TYPE_MASK) { - case LOG_TYPE_CHAR: { - uint32_t ch; - ch = msg->log_data; - while (ch != 0) { - log_char(ch & 0xFF, msg->source); - ch >>= 8; - } - break; - } - case LOG_TYPE_INTEGER: { - dbg_raw_nro(msg->ctrl, msg->log_data, msg->source); - break; - } - default: - break; - } - if (msg->ctrl & LOG_EOL) - log_eol(msg->source); -} - -static uint32_t process_log(void) -{ - char *last_msg = log_buf->buff + log_buf->write_pos; - char *buff = log_buf->buff + log_pos; - - while (buff != last_msg) { - log_msg((struct logmsg_struct *)buff); - buff += sizeof(struct logmsg_struct); - /* Wrap around */ - if ((buff + sizeof(struct logmsg_struct)) > - ((char *)log_buf + log_size)) - buff = log_buf->buff; - } - return buff - log_buf->buff; -} - -static void log_exit(void) -{ - union fc_generic fc_log; - - memset(&fc_log, 0, sizeof(fc_log)); - fc_log.as_in.cmd = MC_FC_NWD_TRACE; - - MCDRV_DBG(mcd, "Unregister the trace buffer"); - mc_fastcall(&fc_log); - MCDRV_DBG(mcd, "fc_log out ret=0x%08x", fc_log.as_out.ret); - - if (fc_log.as_out.ret == 0) { - free_pages((unsigned long)log_buf, get_order(log_size)); - log_buf = NULL; - } -} - -/* log_worker() - Worker thread processing the log_buf buffer. */ -static int log_worker(void *p) -{ - int ret = 0; - if (log_buf == NULL) { - ret = -EFAULT; - goto err_kthread; - } - - while (!kthread_should_stop()) { - if (log_buf->write_pos == log_pos) - schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); - - switch (log_buf->version) { - case 2: - log_pos = process_log(); - break; - default: - MCDRV_DBG_ERROR(mcd, "Unknown Mobicore log data"); - log_pos = log_buf->write_pos; - /* - * Stop the thread as we have no idea what - * happens next - */ - ret = -EFAULT; - goto err_kthread; - } - } -err_kthread: - MCDRV_DBG(mcd, "Logging thread stopped!"); - thread_err = ret; - /* Wait until the next kthread_stop() is called, if it was already - * called we just slip through, if there is an error signal it and - * wait to get the signal */ - set_current_state(TASK_INTERRUPTIBLE); - while (!kthread_should_stop()) { - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - set_current_state(TASK_RUNNING); - - log_exit(); - - return ret; -} - -/* - * Wake up the log reader thread - * This should be called from the places where calls into MobiCore have - * generated some logs(eg, yield, SIQ...) - */ -void mobicore_log_read(void) -{ - if (log_thread == NULL || IS_ERR(log_thread)) - return; - - /* The thread itself is in some error condition so just get - * rid of it */ - if (thread_err != 0) { - kthread_stop(log_thread); - log_thread = NULL; - return; - } - - wake_up_process(log_thread); -} - -/* - * Setup MobiCore kernel log. It assumes it's running on CORE 0! - * The fastcall will complain is that is not the case! - */ -long mobicore_log_setup(void) -{ - phys_addr_t phys_log_buf; - union fc_generic fc_log; - struct sched_param param = { .sched_priority = 1 }; - - long ret; - log_pos = 0; - log_buf = NULL; - log_thread = NULL; - log_line = NULL; - log_line_len = 0; - prev_source = 0; - thread_err = 0; - - /* Sanity check for the log size */ - if (log_size < PAGE_SIZE) - return -EFAULT; - else - log_size = PAGE_ALIGN(log_size); - - log_line = kzalloc(LOG_LINE_SIZE, GFP_KERNEL); - if (IS_ERR(log_line)) { - MCDRV_DBG_ERROR(mcd, "failed to allocate log line!"); - return -ENOMEM; - } - - log_thread = kthread_create(log_worker, NULL, "mc_log"); - if (IS_ERR(log_thread)) { - MCDRV_DBG_ERROR(mcd, "MobiCore log thread creation failed!"); - ret = -EFAULT; - goto err_free_line; - } - - sched_setscheduler(log_thread, SCHED_IDLE, ¶m); - /* - * We are going to map this buffer into virtual address space in SWd. - * To reduce complexity there, we use a contiguous buffer. - */ - log_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(log_size)); - if (!log_buf) { - MCDRV_DBG_ERROR(mcd, "Failed to get page for logger!"); - ret = -ENOMEM; - goto err_stop_kthread; - } - phys_log_buf = virt_to_phys(log_buf); - - memset(&fc_log, 0, sizeof(fc_log)); - fc_log.as_in.cmd = MC_FC_NWD_TRACE; - fc_log.as_in.param[0] = (uint32_t)phys_log_buf; -#ifdef CONFIG_PHYS_ADDR_T_64BIT - fc_log.as_in.param[1] = (uint32_t)(phys_log_buf >> 32); -#endif - fc_log.as_in.param[2] = log_size; - - MCDRV_DBG(mcd, "fc_log virt=%p phys=0x%llX", - log_buf, (u64)phys_log_buf); - mc_fastcall(&fc_log); - MCDRV_DBG(mcd, "fc_log out ret=0x%08x", fc_log.as_out.ret); - - /* If the setup failed we must free the memory allocated */ - if (fc_log.as_out.ret) { - MCDRV_DBG_ERROR(mcd, "MobiCore shared traces setup failed!"); - free_pages((unsigned long)log_buf, get_order(log_size)); - log_buf = NULL; - ret = -EIO; - goto err_stop_kthread; - } - - set_task_state(log_thread, TASK_INTERRUPTIBLE); - - MCDRV_DBG(mcd, "fc_log Logger version %u", log_buf->version); - return 0; - -err_stop_kthread: - kthread_stop(log_thread); - log_thread = NULL; -err_free_line: - kfree(log_line); - log_line = NULL; - return ret; -} - -/* - * Free kernel log components. - * ATTN: We can't free the log buffer because it's also in use by MobiCore and - * even if the module is unloaded MobiCore is still running. - */ -void mobicore_log_free(void) -{ - if (log_thread && !IS_ERR(log_thread)) { - /* We don't really care what the thread returns for exit */ - kthread_stop(log_thread); - } - - kfree(log_line); -} diff --git a/drivers/gud/MobiCoreDriver/logging.h b/drivers/gud/MobiCoreDriver/logging.h deleted file mode 100644 index a3cbca21c8e7..000000000000 --- a/drivers/gud/MobiCoreDriver/logging.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_LOGGING_H_ -#define _MC_LOGGING_H_ - -/* MobiCore internal trace buffer structure. */ -struct mc_trace_buf { - uint32_t version; /* version of trace buffer */ - uint32_t length; /* length of allocated buffer(includes header) */ - uint32_t write_pos; /* last write position */ - char buff[1]; /* start of the log buffer */ -}; - -/* MobiCore internal trace log setup. */ -void mobicore_log_read(void); -long mobicore_log_setup(void); -void mobicore_log_free(void); - -#endif /* _MC_LOGGING_H_ */ diff --git a/drivers/gud/MobiCoreDriver/main.c b/drivers/gud/MobiCoreDriver/main.c deleted file mode 100644 index f1ebaad22815..000000000000 --- a/drivers/gud/MobiCoreDriver/main.c +++ /dev/null @@ -1,1595 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * MobiCore Driver Kernel Module. - * - * This driver represents the command proxy on the lowest layer, from the - * secure world to the non secure world, and vice versa. - - * This driver offers IOCTL commands, for access to the secure world, and has - * the interface from the secure world to the normal world. - * The access to the driver is possible with a file descriptor, - * which has to be created by the fd = open(/dev/mobicore) command or - * fd = open(/dev/mobicore-user) - */ -#include <linux/miscdevice.h> -#include <linux/interrupt.h> -#include <linux/highmem.h> -#include <linux/slab.h> -#include <linux/kthread.h> -#include <linux/device.h> -#include <linux/module.h> -#include <linux/ioctl.h> -#include <linux/mm.h> -#include <linux/mman.h> -#include <linux/completion.h> -#include <linux/fdtable.h> -#include <linux/cdev.h> -#include <net/net_namespace.h> -#include <net/sock.h> -#include <net/tcp_states.h> -#include <net/af_unix.h> - - -#include "main.h" -#include "fastcall.h" - -#include "arm.h" -#include "mem.h" -#include "ops.h" -#include "pm.h" -#include "debug.h" -#include "logging.h" -#include "build_tag.h" - -#if defined(MC_CRYPTO_CLOCK_MANAGEMENT) && defined(MC_USE_DEVICE_TREE) -#include <linux/platform_device.h> -#endif - -/* Define a MobiCore device structure for use with dev_debug() etc */ -struct device_driver mcd_debug_name = { - .name = "MobiCore" -}; - -struct device mcd_debug_subname = { - .driver = &mcd_debug_name -}; - -struct device *mcd = &mcd_debug_subname; - -/* We need 2 devices for admin and user interface*/ -#define MC_DEV_MAX 2 - -/* Need to discover a chrdev region for the driver */ -static dev_t mc_dev_admin, mc_dev_user; -struct cdev mc_admin_cdev, mc_user_cdev; -/* Device class for the driver assigned major */ -static struct class *mc_device_class; - -#ifndef FMODE_PATH - #define FMODE_PATH 0x0 -#endif - -static struct sock *__get_socket(struct file *filp) -{ - struct sock *u_sock = NULL; - struct inode *inode = filp->f_path.dentry->d_inode; - - /* - * Socket ? - */ - if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { - struct socket *sock = SOCKET_I(inode); - struct sock *s = sock->sk; - - /* - * PF_UNIX ? - */ - if (s && sock->ops && sock->ops->family == PF_UNIX) - u_sock = s; - } - return u_sock; -} - - -/* MobiCore interrupt context data */ -struct mc_context ctx; - -/* Get process context from file pointer */ -static struct mc_instance *get_instance(struct file *file) -{ - return (struct mc_instance *)(file->private_data); -} - -static uint32_t get_new_buffer_handle(void) -{ - uint32_t handle; - struct mc_buffer *buffer; - /* assumption ctx.bufs_lock mutex is locked */ -retry: - handle = atomic_inc_return(&ctx.buffer_counter); - /* The handle must leave 12 bits (PAGE_SHIFT) for the 12 LSBs to be - * zero, as mmap requires the offset to be page-aligned, plus 1 bit for - * the MSB to be 0 too, so mmap does not see the offset as negative - * and fail. - */ - if ((handle << (PAGE_SHIFT+1)) == 0) { - atomic_set(&ctx.buffer_counter, 1); - handle = 1; - } - list_for_each_entry(buffer, &ctx.cont_bufs, list) { - if (buffer->handle == handle) - goto retry; - } - - return handle; -} - -/* Clears the reserved bit of each page and frees the pages */ -static inline void free_continguous_pages(void *addr, unsigned int order) -{ - int i; - struct page *page = virt_to_page(addr); - for (i = 0; i < (1<<order); i++) { - MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p", page); - clear_bit(PG_reserved, &page->flags); - page++; - } - - MCDRV_DBG_VERBOSE(mcd, "freeing addr:%p, order:%x", addr, order); - free_pages((unsigned long)addr, order); -} - -/* Frees the memory associated with a buffer */ -static int free_buffer(struct mc_buffer *buffer) -{ - if (buffer->handle == 0) - return -EINVAL; - - if (buffer->addr == 0) - return -EINVAL; - - MCDRV_DBG_VERBOSE(mcd, - "handle=%u phys_addr=0x%llx, virt_addr=0x%p len=%u", - buffer->handle, (u64)buffer->phys, - buffer->addr, buffer->len); - - if (!atomic_dec_and_test(&buffer->usage)) { - MCDRV_DBG_VERBOSE(mcd, "Could not free %u", buffer->handle); - return 0; - } - - list_del(&buffer->list); - - free_continguous_pages(buffer->addr, buffer->order); - kfree(buffer); - return 0; -} - -static uint32_t mc_find_cont_wsm_addr(struct mc_instance *instance, void *uaddr, - void **addr, uint32_t len) -{ - int ret = 0; - struct mc_buffer *buffer; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - mutex_lock(&instance->lock); - - mutex_lock(&ctx.bufs_lock); - - /* search for the given handle in the buffers list */ - list_for_each_entry(buffer, &ctx.cont_bufs, list) { - if (buffer->uaddr == uaddr && buffer->len == len) { - *addr = buffer->addr; - goto found; - } - } - - /* Coundn't find the buffer */ - ret = -EINVAL; - -found: - mutex_unlock(&ctx.bufs_lock); - mutex_unlock(&instance->lock); - - return ret; -} - -bool mc_check_owner_fd(struct mc_instance *instance, int32_t fd) -{ -#ifndef __ARM_VE_A9X4_STD__ - struct file *fp; - struct sock *s; - struct files_struct *files; - struct task_struct *peer = NULL; - bool ret = false; - - MCDRV_DBG_VERBOSE(mcd, "Finding wsm for fd = %d", fd); - if (!instance) - return false; - - if (is_daemon(instance)) - return true; - - rcu_read_lock(); - fp = fcheck_files(current->files, fd); - if (fp == NULL) - goto out; - s = __get_socket(fp); - if (s) - peer = get_pid_task(s->sk_peer_pid, PIDTYPE_PID); - - if (peer) { - task_lock(peer); - files = peer->files; - if (!files) - goto out; - for (fd = 0; fd < files_fdtable(files)->max_fds; fd++) { - fp = fcheck_files(files, fd); - if (!fp) - continue; - if (fp->private_data == instance) { - ret = true; - break; - } - } - } else { - MCDRV_DBG(mcd, "Owner not found!"); - } -out: - if (peer) - task_unlock(peer); - rcu_read_unlock(); - if (!ret) - MCDRV_DBG(mcd, "Owner not found!"); - return ret; -#else - return true; -#endif -} -static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle, - int32_t fd, phys_addr_t *phys, uint32_t *len) -{ - int ret = 0; - struct mc_buffer *buffer; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (WARN_ON(!is_daemon(instance))) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon"); - return -EPERM; - } - - mutex_lock(&instance->lock); - - mutex_lock(&ctx.bufs_lock); - - /* search for the given handle in the buffers list */ - list_for_each_entry(buffer, &ctx.cont_bufs, list) { - if (buffer->handle == handle) { - if (mc_check_owner_fd(buffer->instance, fd)) { - *phys = buffer->phys; - *len = buffer->len; - goto found; - } else { - break; - } - } - } - - /* Couldn't find the buffer */ - ret = -EINVAL; - -found: - mutex_unlock(&ctx.bufs_lock); - mutex_unlock(&instance->lock); - - return ret; -} - -/* - * __free_buffer - Free a WSM buffer allocated with mobicore_allocate_wsm - * - * @instance - * @handle handle of the buffer - * - * Returns 0 if no error - * - */ -static int __free_buffer(struct mc_instance *instance, uint32_t handle, - bool unlock) -{ - int ret = 0; - struct mc_buffer *buffer; -#ifndef MC_VM_UNMAP - struct mm_struct *mm = current->mm; -#endif - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - mutex_lock(&ctx.bufs_lock); - /* search for the given handle in the buffers list */ - list_for_each_entry(buffer, &ctx.cont_bufs, list) { - if (buffer->handle == handle) - goto found_buffer; - } - ret = -EINVAL; - goto err; -found_buffer: - if (!is_daemon(instance) && buffer->instance != instance) { - ret = -EPERM; - goto err; - } - mutex_unlock(&ctx.bufs_lock); - /* Only unmap if the request is coming from the user space and - * it hasn't already been unmapped */ - if (!unlock && buffer->uaddr != NULL) { -#ifndef MC_VM_UNMAP - /* do_munmap must be done with mm->mmap_sem taken */ - down_write(&mm->mmap_sem); - ret = do_munmap(mm, - (long unsigned int)buffer->uaddr, - buffer->len); - up_write(&mm->mmap_sem); - -#else - ret = vm_munmap((long unsigned int)buffer->uaddr, buffer->len); -#endif - if (ret < 0) { - /* Something is not right if we end up here, better not - * clean the buffer so we just leak memory instead of - * creating security issues */ - MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped"); - return -EINVAL; - } - } - - mutex_lock(&ctx.bufs_lock); - /* search for the given handle in the buffers list */ - list_for_each_entry(buffer, &ctx.cont_bufs, list) { - if (buffer->handle == handle) - goto del_buffer; - } - ret = -EINVAL; - goto err; - -del_buffer: - if (is_daemon(instance) || buffer->instance == instance) - ret = free_buffer(buffer); - else - ret = -EPERM; -err: - mutex_unlock(&ctx.bufs_lock); - return ret; -} - -int mc_free_buffer(struct mc_instance *instance, uint32_t handle) -{ - int ret = 0; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - mutex_lock(&instance->lock); - - ret = __free_buffer(instance, handle, false); - mutex_unlock(&instance->lock); - return ret; -} - - -int mc_get_buffer(struct mc_instance *instance, - struct mc_buffer **buffer, unsigned long len) -{ - struct mc_buffer *cbuffer = NULL; - void *addr = 0; - phys_addr_t phys = 0; - unsigned int order; -#if defined(DEBUG_VERBOSE) - unsigned long allocated_size; -#endif - int ret = 0; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (len == 0) { - MCDRV_DBG_WARN(mcd, "cannot allocate size 0"); - return -ENOMEM; - } - - order = get_order(len); - if (order > MAX_ORDER) { - MCDRV_DBG_WARN(mcd, "Buffer size too large"); - return -ENOMEM; - } -#if defined(DEBUG_VERBOSE) - allocated_size = (1 << order) * PAGE_SIZE; -#endif - - if (mutex_lock_interruptible(&instance->lock)) - return -ERESTARTSYS; - - /* allocate a new buffer. */ - cbuffer = kzalloc(sizeof(*cbuffer), GFP_KERNEL); - - if (cbuffer == NULL) { - MCDRV_DBG_WARN(mcd, - "MMAP_WSM request: could not allocate buffer"); - ret = -ENOMEM; - goto unlock_instance; - } - mutex_lock(&ctx.bufs_lock); - - MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)", - len, order, allocated_size); - - addr = (void *)__get_free_pages(GFP_USER | __GFP_ZERO | __GFP_COMP, - order); - - if (addr == NULL) { - MCDRV_DBG_WARN(mcd, "get_free_pages failed"); - ret = -ENOMEM; - goto err; - } - phys = virt_to_phys(addr); - cbuffer->handle = get_new_buffer_handle(); - cbuffer->phys = phys; - cbuffer->addr = addr; - cbuffer->order = order; - cbuffer->len = len; - cbuffer->instance = instance; - cbuffer->uaddr = 0; - /* Refcount +1 because the TLC is requesting it */ - atomic_set(&cbuffer->usage, 1); - - INIT_LIST_HEAD(&cbuffer->list); - list_add(&cbuffer->list, &ctx.cont_bufs); - - MCDRV_DBG_VERBOSE(mcd, - "allocd phys=0x%llx-0x%llx, size=%ld kvirt=0x%p h=%d", - (u64)phys, - (u64)(phys+allocated_size), - allocated_size, addr, cbuffer->handle); - *buffer = cbuffer; - goto unlock; - -err: - kfree(cbuffer); -unlock: - mutex_unlock(&ctx.bufs_lock); -unlock_instance: - mutex_unlock(&instance->lock); - return ret; -} - -/* - * __lock_buffer() - Locks a contiguous buffer - +1 refcount. - * Assumes the instance lock is already taken! - */ -static int __lock_buffer(struct mc_instance *instance, uint32_t handle) -{ - int ret = 0; - struct mc_buffer *buffer; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (WARN_ON(!is_daemon(instance))) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon"); - return -EPERM; - } - - mutex_lock(&ctx.bufs_lock); - /* search for the given handle in the buffers list */ - list_for_each_entry(buffer, &ctx.cont_bufs, list) { - if (buffer->handle == handle) { - atomic_inc(&buffer->usage); - goto unlock; - } - } - ret = -EINVAL; - -unlock: - mutex_unlock(&ctx.bufs_lock); - return ret; -} - -static phys_addr_t get_mci_base_phys(unsigned int len) -{ - if (ctx.mci_base.phys) { - return ctx.mci_base.phys; - } else { - unsigned int order = get_order(len); - ctx.mcp = NULL; - ctx.mci_base.order = order; - ctx.mci_base.addr = - (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order); - if (ctx.mci_base.addr == NULL) { - MCDRV_DBG_WARN(mcd, "get_free_pages failed"); - memset(&ctx.mci_base, 0, sizeof(ctx.mci_base)); - return 0; - } - ctx.mci_base.phys = virt_to_phys(ctx.mci_base.addr); - return ctx.mci_base.phys; - } -} - -/* - * Create a MMU table from a virtual memory buffer which can be vmalloc - * or user space virtual memory - */ -int mc_register_wsm_mmu(struct mc_instance *instance, - void *buffer, uint32_t len, - uint32_t *handle, phys_addr_t *phys) -{ - int ret = 0; - struct mc_mmu_table *table = NULL; - struct task_struct *task = current; - void *kbuff = NULL; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (len == 0) { - MCDRV_DBG_ERROR(mcd, "len=0 is not supported!"); - return -EINVAL; - } - - MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x", buffer, len); - - if (!mc_find_cont_wsm_addr(instance, buffer, &kbuff, len)) - table = mc_alloc_mmu_table(instance, NULL, kbuff, len); - else - table = mc_alloc_mmu_table(instance, task, buffer, len); - - if (IS_ERR(table)) { - MCDRV_DBG_ERROR(mcd, "mc_alloc_mmu_table() failed"); - return -EINVAL; - } - - /* set response */ - *handle = table->handle; - /* WARNING: daemon shouldn't know this either, but live with it */ - if (is_daemon(instance)) - *phys = table->phys; - else - *phys = 0; - - MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=0x%llX", - *handle, (u64)(*phys)); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret); - - return ret; -} - -int mc_unregister_wsm_mmu(struct mc_instance *instance, uint32_t handle) -{ - int ret = 0; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - /* free table (if no further locks exist) */ - mc_free_mmu_table(instance, handle); - - return ret; -} -/* Lock the object from handle, it could be a WSM MMU table or a cont buffer! */ -static int mc_lock_handle(struct mc_instance *instance, uint32_t handle) -{ - int ret = 0; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (WARN_ON(!is_daemon(instance))) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon"); - return -EPERM; - } - - mutex_lock(&instance->lock); - ret = mc_lock_mmu_table(instance, handle); - - /* Handle was not a MMU table but a cont buffer */ - if (ret == -EINVAL) { - /* Call the non locking variant! */ - ret = __lock_buffer(instance, handle); - } - - mutex_unlock(&instance->lock); - - return ret; -} - -static int mc_unlock_handle(struct mc_instance *instance, uint32_t handle) -{ - int ret = 0; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (WARN_ON(!is_daemon(instance))) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon"); - return -EPERM; - } - - mutex_lock(&instance->lock); - ret = mc_free_mmu_table(instance, handle); - - /* Not a MMU table, then it must be a buffer */ - if (ret == -EINVAL) { - /* Call the non locking variant! */ - ret = __free_buffer(instance, handle, true); - } - mutex_unlock(&instance->lock); - - return ret; -} - -static phys_addr_t mc_find_wsm_mmu(struct mc_instance *instance, - uint32_t handle, int32_t fd) -{ - if (WARN(!instance, "No instance data available")) - return 0; - - if (WARN_ON(!is_daemon(instance))) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon"); - return 0; - } - - return mc_find_mmu_table(handle, fd); -} - -static int mc_clean_wsm_mmu(struct mc_instance *instance) -{ - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (WARN_ON(!is_daemon(instance))) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon"); - return -EPERM; - } - - mc_clean_mmu_tables(); - - return 0; -} - -static int mc_fd_mmap(struct file *file, struct vm_area_struct *vmarea) -{ - struct mc_instance *instance = get_instance(file); - unsigned long len = vmarea->vm_end - vmarea->vm_start; - uint32_t handle = vmarea->vm_pgoff; - struct mc_buffer *buffer = 0; - int ret = 0; - - MCDRV_DBG_VERBOSE(mcd, "start=0x%p, size=%ld, offset=%ld, mci=0x%llX", - (void *)vmarea->vm_start, len, vmarea->vm_pgoff, - (u64)ctx.mci_base.phys); - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (len == 0) { - MCDRV_DBG_ERROR(mcd, "cannot allocate size 0"); - return -ENOMEM; - } - if (handle) { - mutex_lock(&ctx.bufs_lock); - - /* search for the buffer list. */ - list_for_each_entry(buffer, &ctx.cont_bufs, list) { - /* Only allow mapping if the client owns it!*/ - if (buffer->handle == handle && - buffer->instance == instance) { - /* We shouldn't do remap with larger size */ - if (buffer->len > len) - break; - /* We can't allow mapping the buffer twice */ - if (!buffer->uaddr) - goto found; - else - break; - } - } - /* Nothing found return */ - mutex_unlock(&ctx.bufs_lock); - MCDRV_DBG_ERROR(mcd, "handle not found"); - return -EINVAL; - -found: - buffer->uaddr = (void *)vmarea->vm_start; - vmarea->vm_flags |= VM_IO; - /* - * Convert kernel address to user address. Kernel address begins - * at PAGE_OFFSET, user address range is below PAGE_OFFSET. - * Remapping the area is always done, so multiple mappings - * of one region are possible. Now remap kernel address - * space into user space - */ - ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, - page_to_pfn(virt_to_page(buffer->addr)), - buffer->len, vmarea->vm_page_prot); - /* If the remap failed then don't mark this buffer as marked - * since the unmaping will also fail */ - if (ret) - buffer->uaddr = NULL; - mutex_unlock(&ctx.bufs_lock); - } else { - if (!is_daemon(instance)) - return -EPERM; - - if (!ctx.mci_base.addr) - return -EFAULT; - - vmarea->vm_flags |= VM_IO; - /* Convert kernel address to user address. Kernel address begins - * at PAGE_OFFSET, user address range is below PAGE_OFFSET. - * Remapping the area is always done, so multiple mappings - * of one region are possible. Now remap kernel address - * space into user space */ - ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, - page_to_pfn(virt_to_page(ctx.mci_base.addr)), - len, vmarea->vm_page_prot); - } - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret); - - return ret; -} - -static inline int ioctl_check_pointer(unsigned int cmd, int __user *uarg) -{ - int err = 0; - if (_IOC_DIR(cmd) & _IOC_READ) - err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd)); - else if (_IOC_DIR(cmd) & _IOC_WRITE) - err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd)); - if (err) - return -EFAULT; - - return 0; -} - -/* - * mc_fd_user_ioctl() - Will be called from user space as ioctl(..) - * @file pointer to file - * @cmd command - * @arg arguments - * - * Returns 0 for OK and an errno in case of error - */ -static long mc_fd_user_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct mc_instance *instance = get_instance(file); - int __user *uarg = (int __user *)arg; - int ret = -EINVAL; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (ioctl_check_pointer(cmd, uarg)) - return -EFAULT; - - switch (cmd) { - case MC_IO_FREE: - ret = mc_free_buffer(instance, (uint32_t)arg); - break; - - /* 32/64 bit interface compatiblity notice: - * mc_ioctl_reg_wsm has been defined with the buffer parameter - * as void* which means that the size and layout of the structure - * are different between 32 and 64 bit variants. - * However our 64 bit Linux driver must be able to service both - * 32 and 64 bit clients so we have to allow both IOCTLs. Though - * we have a bit of copy paste code we provide maximum backwards - * compatiblity */ - case MC_IO_REG_WSM:{ - struct mc_ioctl_reg_wsm reg; - phys_addr_t phys = 0; - if (copy_from_user(®, uarg, sizeof(reg))) - return -EFAULT; - - ret = mc_register_wsm_mmu(instance, - (void *)(uintptr_t)reg.buffer, - reg.len, ®.handle, &phys); - reg.table_phys = phys; - - if (!ret) { - if (copy_to_user(uarg, ®, sizeof(reg))) { - ret = -EFAULT; - mc_unregister_wsm_mmu(instance, reg.handle); - } - } - break; - } - case MC_COMPAT_REG_WSM:{ - struct mc_compat_ioctl_reg_wsm reg; - phys_addr_t phys = 0; - if (copy_from_user(®, uarg, sizeof(reg))) - return -EFAULT; - - ret = mc_register_wsm_mmu(instance, - (void *)(uintptr_t)reg.buffer, - reg.len, ®.handle, &phys); - reg.table_phys = phys; - - if (!ret) { - if (copy_to_user(uarg, ®, sizeof(reg))) { - ret = -EFAULT; - mc_unregister_wsm_mmu(instance, reg.handle); - } - } - break; - } - case MC_IO_UNREG_WSM: - ret = mc_unregister_wsm_mmu(instance, (uint32_t)arg); - break; - - case MC_IO_VERSION: - ret = put_user(mc_get_version(), uarg); - if (ret) - MCDRV_DBG_ERROR(mcd, - "IOCTL_GET_VERSION failed to put data"); - break; - - case MC_IO_MAP_WSM:{ - struct mc_ioctl_map map; - struct mc_buffer *buffer = 0; - if (copy_from_user(&map, uarg, sizeof(map))) - return -EFAULT; - - /* Setup the WSM buffer structure! */ - if (mc_get_buffer(instance, &buffer, map.len)) - return -EFAULT; - - map.handle = buffer->handle; - /* Trick: to keep the same interface with the user space, store - the handle in the physical address. - It is given back with the offset when mmap() is called. */ - map.phys_addr = buffer->handle << PAGE_SHIFT; - map.reused = 0; - if (copy_to_user(uarg, &map, sizeof(map))) - ret = -EFAULT; - else - ret = 0; - break; - } - default: - MCDRV_DBG_ERROR(mcd, "unsupported cmd=0x%x", cmd); - ret = -ENOIOCTLCMD; - break; - - } /* end switch(cmd) */ - -#ifdef MC_MEM_TRACES - mobicore_log_read(); -#endif - - return (int)ret; -} - -static long mc_fd_admin_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct mc_instance *instance = get_instance(file); - int __user *uarg = (int __user *)arg; - int ret = -EINVAL; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - if (WARN_ON(!is_daemon(instance))) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon"); - return -EPERM; - } - - if (ioctl_check_pointer(cmd, uarg)) - return -EFAULT; - - switch (cmd) { - case MC_IO_INIT: { - struct mc_ioctl_init init; - ctx.mcp = NULL; - if (!ctx.mci_base.phys) { - MCDRV_DBG_ERROR(mcd, - "Cannot init MobiCore without MCI!"); - return -EINVAL; - } - if (copy_from_user(&init, uarg, sizeof(init))) - return -EFAULT; - - ctx.mcp = ctx.mci_base.addr + init.mcp_offset; - ret = mc_init(ctx.mci_base.phys, init.nq_length, - init.mcp_offset, init.mcp_length); - break; - } - case MC_IO_INFO: { - struct mc_ioctl_info info; - if (copy_from_user(&info, uarg, sizeof(info))) - return -EFAULT; - - ret = mc_info(info.ext_info_id, &info.state, - &info.ext_info); - - if (!ret) { - if (copy_to_user(uarg, &info, sizeof(info))) - ret = -EFAULT; - } - break; - } - case MC_IO_YIELD: - ret = mc_yield(); - break; - - case MC_IO_NSIQ: - ret = mc_nsiq(); - break; - - case MC_IO_LOCK_WSM: { - ret = mc_lock_handle(instance, (uint32_t)arg); - break; - } - case MC_IO_UNLOCK_WSM: - ret = mc_unlock_handle(instance, (uint32_t)arg); - break; - case MC_IO_CLEAN_WSM: - ret = mc_clean_wsm_mmu(instance); - break; - case MC_IO_RESOLVE_WSM: { - phys_addr_t phys; - struct mc_ioctl_resolv_wsm wsm; - if (copy_from_user(&wsm, uarg, sizeof(wsm))) - return -EFAULT; - phys = mc_find_wsm_mmu(instance, wsm.handle, wsm.fd); - if (!phys) - return -EINVAL; - - wsm.phys = phys; - if (copy_to_user(uarg, &wsm, sizeof(wsm))) - return -EFAULT; - ret = 0; - break; - } - case MC_IO_RESOLVE_CONT_WSM: { - struct mc_ioctl_resolv_cont_wsm cont_wsm; - phys_addr_t phys = 0; - uint32_t len = 0; - if (copy_from_user(&cont_wsm, uarg, sizeof(cont_wsm))) - return -EFAULT; - ret = mc_find_cont_wsm(instance, cont_wsm.handle, cont_wsm.fd, - &phys, &len); - if (!ret) { - cont_wsm.phys = phys; - cont_wsm.length = len; - if (copy_to_user(uarg, &cont_wsm, sizeof(cont_wsm))) - ret = -EFAULT; - } - break; - } - case MC_IO_MAP_MCI:{ - struct mc_ioctl_map map; - phys_addr_t phys_addr; - if (copy_from_user(&map, uarg, sizeof(map))) - return -EFAULT; - - map.reused = (ctx.mci_base.phys != 0); - phys_addr = get_mci_base_phys(map.len); - if (!phys_addr) { - MCDRV_DBG_ERROR(mcd, "Failed to setup MCI buffer!"); - return -EFAULT; - } - map.phys_addr = 0; - if (copy_to_user(uarg, &map, sizeof(map))) - ret = -EFAULT; - ret = 0; - break; - } - case MC_IO_LOG_SETUP: { -#ifdef MC_MEM_TRACES - ret = mobicore_log_setup(); -#endif - break; - } - - /* The rest is handled commonly by user IOCTL */ - default: - ret = mc_fd_user_ioctl(file, cmd, arg); - } /* end switch(cmd) */ - -#ifdef MC_MEM_TRACES - mobicore_log_read(); -#endif - - return (int)ret; -} - -/* - * mc_fd_read() - This will be called from user space as read(...) - * @file: file pointer - * @buffer: buffer where to copy to(userspace) - * @buffer_len: number of requested data - * @pos: not used - * - * The read function is blocking until a interrupt occurs. In that case the - * event counter is copied into user space and the function is finished. - * - * If OK this function returns the number of copied data otherwise it returns - * errno - */ -static ssize_t mc_fd_read(struct file *file, char *buffer, size_t buffer_len, - loff_t *pos) -{ - int ret = 0, ssiq_counter; - struct mc_instance *instance = get_instance(file); - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - /* avoid debug output on non-error, because this is call quite often */ - MCDRV_DBG_VERBOSE(mcd, "enter"); - - /* only the MobiCore Daemon is allowed to call this function */ - if (WARN_ON(!is_daemon(instance))) { - MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon"); - return -EPERM; - } - - if (buffer_len < sizeof(unsigned int)) { - MCDRV_DBG_ERROR(mcd, "invalid length"); - return -EINVAL; - } - - for (;;) { - if (wait_for_completion_interruptible(&ctx.isr_comp)) { - MCDRV_DBG_VERBOSE(mcd, "read interrupted"); - return -ERESTARTSYS; - } - - ssiq_counter = atomic_read(&ctx.isr_counter); - MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i", - ssiq_counter, ctx.evt_counter); - - if (ssiq_counter != ctx.evt_counter) { - /* read data and exit loop without error */ - ctx.evt_counter = ssiq_counter; - ret = 0; - break; - } - - /* end loop if non-blocking */ - if (file->f_flags & O_NONBLOCK) { - MCDRV_DBG_ERROR(mcd, "non-blocking read"); - return -EAGAIN; - } - - if (signal_pending(current)) { - MCDRV_DBG_VERBOSE(mcd, "received signal."); - return -ERESTARTSYS; - } - } - - /* read data and exit loop */ - ret = copy_to_user(buffer, &ctx.evt_counter, sizeof(unsigned int)); - - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "copy_to_user failed"); - return -EFAULT; - } - - ret = sizeof(unsigned int); - - return (ssize_t)ret; -} - -/* - * Initialize a new mobicore API instance object - * - * @return Instance or NULL if no allocation was possible. - */ -struct mc_instance *mc_alloc_instance(void) -{ - struct mc_instance *instance; - - instance = kzalloc(sizeof(*instance), GFP_KERNEL); - if (instance == NULL) - return NULL; - - /* get a unique ID for this instance (PIDs are not unique) */ - instance->handle = atomic_inc_return(&ctx.instance_counter); - - mutex_init(&instance->lock); - - return instance; -} - -#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG) -static ssize_t mc_fd_write(struct file *file, const char __user *buffer, - size_t buffer_len, loff_t *x) -{ - uint32_t cpu_new; - /* we only consider one digit */ - char buf[2]; - struct mc_instance *instance = get_instance(file); - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - /* Invalid data, nothing to do */ - if (buffer_len < 1) - return -EINVAL; - - /* Invalid data, nothing to do */ - if (copy_from_user(buf, buffer, min(sizeof(buf), buffer_len))) - return -EFAULT; - - if (buf[0] == 'n') { - mc_nsiq(); - /* If it's a digit then switch cores */ - } else if ((buf[0] >= '0') && (buf[0] <= '9')) { - cpu_new = buf[0] - '0'; - if (cpu_new <= 8) { - MCDRV_DBG_VERBOSE(mcd, "Set Active Cpu: %d\n", cpu_new); - mc_switch_core(cpu_new); - } - } else { - return -EINVAL; - } - - return buffer_len; -} -#endif - -/* - * Release a mobicore instance object and all objects related to it - * @instance: instance - * Returns 0 if Ok or -E ERROR - */ -int mc_release_instance(struct mc_instance *instance) -{ - struct mc_buffer *buffer, *tmp; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - mutex_lock(&instance->lock); - mc_clear_mmu_tables(instance); - - mutex_lock(&ctx.bufs_lock); - /* release all mapped data */ - - /* Check if some buffers are orphaned. */ - list_for_each_entry_safe(buffer, tmp, &ctx.cont_bufs, list) { - /* It's safe here to only call free_buffer() without unmapping - * because mmap() takes a refcount to the file's fd so only - * time we end up here is when everything has been unmapped or - * the process called exit() */ - if (buffer->instance == instance) { - buffer->instance = NULL; - free_buffer(buffer); - } - } - mutex_unlock(&ctx.bufs_lock); - - mutex_unlock(&instance->lock); - - /* release instance context */ - kfree(instance); - - return 0; -} - -/* - * mc_fd_user_open() - Will be called from user space as fd = open(...) - * A set of internal instance data are created and initialized. - * - * @inode - * @file - * Returns 0 if OK or -ENOMEM if no allocation was possible. - */ -static int mc_fd_user_open(struct inode *inode, struct file *file) -{ - struct mc_instance *instance; - - MCDRV_DBG_VERBOSE(mcd, "enter"); - - instance = mc_alloc_instance(); - if (instance == NULL) - return -ENOMEM; - - /* store instance data reference */ - file->private_data = instance; - - return 0; -} - -static int mc_fd_admin_open(struct inode *inode, struct file *file) -{ - struct mc_instance *instance; - - /* - * The daemon is already set so we can't allow anybody else to open - * the admin interface. - */ - if (ctx.daemon_inst) { - MCDRV_DBG_ERROR(mcd, "Daemon is already connected"); - return -EPERM; - } - /* Setup the usual variables */ - if (mc_fd_user_open(inode, file)) - return -ENOMEM; - instance = get_instance(file); - - MCDRV_DBG(mcd, "accept this as MobiCore Daemon"); - - ctx.daemon_inst = instance; - ctx.daemon = current; - instance->admin = true; - init_completion(&ctx.isr_comp); - /* init ssiq event counter */ - ctx.evt_counter = atomic_read(&(ctx.isr_counter)); - - return 0; -} - -/* - * mc_fd_release() - This function will be called from user space as close(...) - * The instance data are freed and the associated memory pages are unreserved. - * - * @inode - * @file - * - * Returns 0 - */ -static int mc_fd_release(struct inode *inode, struct file *file) -{ - int ret = 0; - struct mc_instance *instance = get_instance(file); - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - /* check if daemon closes us. */ - if (is_daemon(instance)) { - MCDRV_DBG_WARN(mcd, "MobiCore Daemon died"); - ctx.daemon_inst = NULL; - ctx.daemon = NULL; - } - - ret = mc_release_instance(instance); - - /* - * ret is quite irrelevant here as most apps don't care about the - * return value from close() and it's quite difficult to recover - */ - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret); - - return (int)ret; -} - -/* - * This function represents the interrupt function of the mcDrvModule. - * It signals by incrementing of an event counter and the start of the read - * waiting queue, the read function a interrupt has occurred. - */ -static irqreturn_t mc_ssiq_isr(int intr, void *context) -{ - /* increment interrupt event counter */ - atomic_inc(&(ctx.isr_counter)); - - /* signal the daemon */ - complete(&ctx.isr_comp); -#ifdef MC_MEM_TRACES - mobicore_log_read(); -#endif - return IRQ_HANDLED; -} - -/* function table structure of this device driver. */ -static const struct file_operations mc_admin_fops = { - .owner = THIS_MODULE, - .open = mc_fd_admin_open, - .release = mc_fd_release, - .unlocked_ioctl = mc_fd_admin_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = mc_fd_admin_ioctl, -#endif - .mmap = mc_fd_mmap, - .read = mc_fd_read, -}; - -/* function table structure of this device driver. */ -static const struct file_operations mc_user_fops = { - .owner = THIS_MODULE, - .open = mc_fd_user_open, - .release = mc_fd_release, - .unlocked_ioctl = mc_fd_user_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = mc_fd_user_ioctl, -#endif - .mmap = mc_fd_mmap, -#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG) - .write = mc_fd_write, -#endif -}; - -static int create_devices(void) -{ - int ret = 0; - - cdev_init(&mc_admin_cdev, &mc_admin_fops); - cdev_init(&mc_user_cdev, &mc_user_fops); - - mc_device_class = class_create(THIS_MODULE, "mobicore"); - if (IS_ERR(mc_device_class)) { - MCDRV_DBG_ERROR(mcd, "failed to create device class"); - ret = PTR_ERR(mc_device_class); - goto out; - } - - ret = alloc_chrdev_region(&mc_dev_admin, 0, MC_DEV_MAX, "mobicore"); - if (ret < 0) { - MCDRV_DBG_ERROR(mcd, "failed to allocate char dev region"); - goto error; - } - mc_dev_user = MKDEV(MAJOR(mc_dev_admin), 1); - - MCDRV_DBG_VERBOSE(mcd, "%s: dev %d", "mobicore", MAJOR(mc_dev_admin)); - - /* First the ADMIN node */ - ret = cdev_add(&mc_admin_cdev, mc_dev_admin, 1); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "admin device register failed"); - goto error; - } - mc_admin_cdev.owner = THIS_MODULE; - device_create(mc_device_class, NULL, mc_dev_admin, NULL, - MC_ADMIN_DEVNODE); - - /* Then the user node */ - - ret = cdev_add(&mc_user_cdev, mc_dev_user, 1); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "user device register failed"); - goto error_unregister; - } - mc_user_cdev.owner = THIS_MODULE; - device_create(mc_device_class, NULL, mc_dev_user, NULL, - MC_USER_DEVNODE); - - goto out; -error_unregister: - device_destroy(mc_device_class, mc_dev_admin); - device_destroy(mc_device_class, mc_dev_user); - - cdev_del(&mc_admin_cdev); - cdev_del(&mc_user_cdev); - unregister_chrdev_region(mc_dev_admin, MC_DEV_MAX); -error: - class_destroy(mc_device_class); -out: - return ret; -} - -/* - * This function is called the kernel during startup or by a insmod command. - * This device is installed and registered as cdev, then interrupt and - * queue handling is set up - */ -static int __init mobicore_init(void) -{ - int ret = 0; - dev_set_name(mcd, "mcd"); - - /* Do not remove or change the following trace. - * The string "MobiCore" is used to detect if <t-base is in of the image - */ - dev_info(mcd, "MobiCore Driver, Build: " __TIMESTAMP__ "\n"); - dev_info(mcd, "MobiCore mcDrvModuleApi version is %i.%i\n", - MCDRVMODULEAPI_VERSION_MAJOR, - MCDRVMODULEAPI_VERSION_MINOR); -#ifdef MOBICORE_COMPONENT_BUILD_TAG - dev_info(mcd, "MobiCore %s\n", MOBICORE_COMPONENT_BUILD_TAG); -#endif - /* Hardware does not support ARM TrustZone -> Cannot continue! */ - if (!has_security_extensions()) { - MCDRV_DBG_ERROR(mcd, - "Hardware doesn't support ARM TrustZone!"); - return -ENODEV; - } - - /* Running in secure mode -> Cannot load the driver! */ - if (is_secure_mode()) { - MCDRV_DBG_ERROR(mcd, "Running in secure MODE!"); - return -ENODEV; - } - - ret = mc_fastcall_init(&ctx); - if (ret) - goto error; - - init_completion(&ctx.isr_comp); - - /* initialize event counter for signaling of an IRQ to zero */ - atomic_set(&ctx.isr_counter, 0); - - /* set up S-SIQ interrupt handler ************************/ - ret = request_irq(MC_INTR_SSIQ, mc_ssiq_isr, IRQF_TRIGGER_RISING, - MC_ADMIN_DEVNODE, &ctx); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "interrupt request failed"); - goto err_req_irq; - } - -#ifdef MC_PM_RUNTIME - ret = mc_pm_initialize(&ctx); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "Power Management init failed!"); - goto free_isr; - } -#endif - - ret = create_devices(); - if (ret != 0) - goto free_pm; - - ret = mc_init_mmu_tables(); - -#ifdef MC_CRYPTO_CLOCK_MANAGEMENT - ret = mc_pm_clock_initialize(); -#endif - - /* - * initialize unique number counters which we can use for - * handles. We start with 1 instead of 0. - */ - atomic_set(&ctx.buffer_counter, 1); - atomic_set(&ctx.instance_counter, 1); - - /* init list for contiguous buffers */ - INIT_LIST_HEAD(&ctx.cont_bufs); - - /* init lock for the buffers list */ - mutex_init(&ctx.bufs_lock); - - memset(&ctx.mci_base, 0, sizeof(ctx.mci_base)); - MCDRV_DBG(mcd, "initialized"); - return 0; - -free_pm: -#ifdef MC_PM_RUNTIME - mc_pm_free(); -free_isr: -#endif - free_irq(MC_INTR_SSIQ, &ctx); -err_req_irq: - mc_fastcall_destroy(); -error: - return ret; -} - -/* - * This function removes this device driver from the Linux device manager . - */ -static void __exit mobicore_exit(void) -{ - MCDRV_DBG_VERBOSE(mcd, "enter"); -#ifdef MC_MEM_TRACES - mobicore_log_free(); -#endif - - mc_release_mmu_tables(); - -#ifdef MC_PM_RUNTIME - mc_pm_free(); -#endif - - device_destroy(mc_device_class, mc_dev_admin); - device_destroy(mc_device_class, mc_dev_user); - class_destroy(mc_device_class); - unregister_chrdev_region(mc_dev_admin, MC_DEV_MAX); - - free_irq(MC_INTR_SSIQ, &ctx); - - mc_fastcall_destroy(); - -#ifdef MC_CRYPTO_CLOCK_MANAGEMENT - mc_pm_clock_finalize(); -#endif - - MCDRV_DBG_VERBOSE(mcd, "exit"); -} - -bool mc_sleep_ready(void) -{ -#ifdef MC_PM_RUNTIME - return mc_pm_sleep_ready(); -#else - return true; -#endif -} - -#if defined(MC_CRYPTO_CLOCK_MANAGEMENT) && defined(MC_USE_DEVICE_TREE) -static int mcd_probe(struct platform_device *pdev) -{ - mcd->of_node = pdev->dev.of_node; - mobicore_init(); - return 0; -} - -static int mcd_remove(struct platform_device *pdev) -{ - return 0; -} - -static int mcd_suspend(struct platform_device *pdev, pm_message_t state) -{ - return 0; -} - -static int mcd_resume(struct platform_device *pdev) -{ - return 0; -} - -static struct of_device_id mcd_match[] = { - { - .compatible = "qcom,mcd", - }, - {} -}; - -static struct platform_driver mc_plat_driver = { - .probe = mcd_probe, - .remove = mcd_remove, - .suspend = mcd_suspend, - .resume = mcd_resume, - .driver = { - .name = "mcd", - .owner = THIS_MODULE, - .of_match_table = mcd_match, - }, -}; - -static int mobicore_register(void) -{ - return platform_driver_register(&mc_plat_driver); -} - -static void mobicore_unregister(void) -{ - platform_driver_unregister(&mc_plat_driver); - mobicore_exit(); -} - -module_init(mobicore_register); -module_exit(mobicore_unregister); - -#else - -module_init(mobicore_init); -module_exit(mobicore_exit); - -#endif - -MODULE_AUTHOR("Trustonic Limited"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("MobiCore driver"); diff --git a/drivers/gud/MobiCoreDriver/main.h b/drivers/gud/MobiCoreDriver/main.h deleted file mode 100644 index f8f210714c32..000000000000 --- a/drivers/gud/MobiCoreDriver/main.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_MAIN_H_ -#define _MC_MAIN_H_ - -#include <asm/pgtable.h> -#include <linux/semaphore.h> -#include <linux/completion.h> -#include <linux/mutex.h> - -#include "public/mc_linux.h" -/* Platform specific settings */ -#include "platform.h" - -#define MC_VERSION(major, minor) \ - (((major & 0x0000ffff) << 16) | (minor & 0x0000ffff)) - -/* Instance data for MobiCore Daemon and TLCs. */ -struct mc_instance { - /* lock for the instance */ - struct mutex lock; - /* unique handle */ - unsigned int handle; - bool admin; -}; - -/* - * Contiguous buffer allocated to TLCs. - * These buffers are uses as world shared memory (wsm) and shared with - * secure world. - * The virtual kernel address is added for a simpler search algorithm. - */ -struct mc_buffer { - struct list_head list; - /* unique handle */ - unsigned int handle; - /* Number of references kept to this buffer */ - atomic_t usage; - /* virtual Kernel start address */ - void *addr; - /* virtual Userspace start address */ - void *uaddr; - /* physical start address */ - phys_addr_t phys; - /* order of number of pages */ - unsigned int order; - uint32_t len; - struct mc_instance *instance; -}; - -/* MobiCore Driver Kernel Module context data. */ -struct mc_context { - /* MobiCore MCI information */ - struct mc_buffer mci_base; - /* MobiCore MCP buffer */ - struct mc_mcp_buffer *mcp; - /* event completion */ - struct completion isr_comp; - /* isr event counter */ - unsigned int evt_counter; - atomic_t isr_counter; - /* ever incrementing counters */ - atomic_t buffer_counter; - atomic_t instance_counter; - /* pointer to instance of daemon */ - struct mc_instance *daemon_inst; - /* pointer to instance of daemon */ - struct task_struct *daemon; - /* General list of contiguous buffers allocated by the kernel */ - struct list_head cont_bufs; - /* Lock for the list of contiguous buffers */ - struct mutex bufs_lock; -}; - -struct mc_sleep_mode { - uint16_t sleep_req; - uint16_t ready_to_sleep; -}; - -/* MobiCore is idle. No scheduling required. */ -#define SCHEDULE_IDLE 0 -/* MobiCore is non idle, scheduling is required. */ -#define SCHEDULE_NON_IDLE 1 - -/* MobiCore status flags */ -struct mc_flags { - /* - * Scheduling hint: if <> SCHEDULE_IDLE, MobiCore should - * be scheduled by the NWd - */ - uint32_t schedule; - /* State of sleep protocol */ - struct mc_sleep_mode sleep_mode; - /* Reserved for future use: Must not be interpreted */ - uint32_t rfu[2]; -}; - -/* MCP buffer structure */ -struct mc_mcp_buffer { - /* MobiCore Flags */ - struct mc_flags flags; - uint32_t rfu; /* MCP message buffer - ignore */ -}; - -/* check if caller is MobiCore Daemon */ -static inline bool is_daemon(struct mc_instance *instance) -{ - if (!instance) - return false; - return instance->admin; -} - - -/* Initialize a new mobicore API instance object */ -struct mc_instance *mc_alloc_instance(void); -/* Release a mobicore instance object and all objects related to it */ -int mc_release_instance(struct mc_instance *instance); - -/* - * mc_register_wsm_mmu() - Create a MMU table from a virtual memory buffer which - * can be vmalloc or user space virtual memory - */ -int mc_register_wsm_mmu(struct mc_instance *instance, - void *buffer, uint32_t len, - uint32_t *handle, phys_addr_t *phys); -/* Unregister the buffer mapped above */ -int mc_unregister_wsm_mmu(struct mc_instance *instance, uint32_t handle); - -/* Allocate one mc_buffer of contiguous space */ -int mc_get_buffer(struct mc_instance *instance, - struct mc_buffer **buffer, unsigned long len); -/* Free the buffer allocated above */ -int mc_free_buffer(struct mc_instance *instance, uint32_t handle); - -/* Check if the other end of the fd owns instance */ -bool mc_check_owner_fd(struct mc_instance *instance, int32_t fd); - -/* Test if sleep is possible */ -bool mc_sleep_ready(void); - -#endif /* _MC_MAIN_H_ */ diff --git a/drivers/gud/MobiCoreDriver/mem.c b/drivers/gud/MobiCoreDriver/mem.c deleted file mode 100644 index 523dd2c49de2..000000000000 --- a/drivers/gud/MobiCoreDriver/mem.c +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * MobiCore Driver Kernel Module. - * - * This module is written as a Linux device driver. - * This driver represents the command proxy on the lowest layer, from the - * secure world to the non secure world, and vice versa. - * This driver is located in the non secure world (Linux). - * This driver offers IOCTL commands, for access to the secure world, and has - * the interface from the secure world to the normal world. - * The access to the driver is possible with a file descriptor, - * which has to be created by the fd = open(/dev/mobicore) command. - */ -#include "main.h" -#include "debug.h" -#include "mem.h" - -#include <linux/highmem.h> -#include <linux/slab.h> -#include <linux/kthread.h> -#include <linux/pagemap.h> -#include <linux/device.h> - -#ifdef LPAE_SUPPORT -#define MMU_TYPE_PAGE (3 << 0) -#define MMU_BUFFERABLE (1 << 2) /* AttrIndx[0] */ -#define MMU_CACHEABLE (1 << 3) /* AttrIndx[1] */ -#define MMU_NS (1 << 5) -#define MMU_AP_RW_ALL (1 << 6) /* AP[2:1], RW, at any privilege level */ -#define MMU_EXT_SHARED (3 << 8) /* SH[1:0], inner shareable */ -#define MMU_EXT_AF (1 << 10) /* Access Flag */ -#define MMU_EXT_NG (1 << 11) -#define MMU_EXT_XN (((uint64_t)1) << 54) /* XN */ -#else -#define MMU_TYPE_EXT (3 << 0) /* v5 */ -#define MMU_TYPE_SMALL (2 << 0) -#define MMU_BUFFERABLE (1 << 2) -#define MMU_CACHEABLE (1 << 3) -#define MMU_EXT_AP0 (1 << 4) -#define MMU_EXT_AP1 (2 << 4) -#define MMU_EXT_TEX(x) ((x) << 6) /* v5 */ -#define MMU_EXT_SHARED (1 << 10) /* v6 */ -#define MMU_EXT_NG (1 << 11) /* v6 */ -#endif - -/* MobiCore memory context data */ -struct mc_mem_context mem_ctx; - -static inline void release_page(struct page *page) -{ - set_bit(PG_dirty, &page->flags); - - page_cache_release(page); -} - -static int lock_pages(struct task_struct *task, void *virt_start_page_addr, - int pages_no, struct page **pages) -{ - int locked_pages; - - /* lock user pages, must hold the mmap_sem to do this. */ - down_read(&(task->mm->mmap_sem)); - locked_pages = get_user_pages( - task, - task->mm, - (unsigned long)virt_start_page_addr, - pages_no, - 1, /* write access */ - 0, - pages, - NULL); - up_read(&(task->mm->mmap_sem)); - - /* check if we could lock all pages. */ - if (locked_pages != pages_no) { - MCDRV_DBG_ERROR(mcd, "get_user_pages() failed, locked_pages=%d", - locked_pages); - if (locked_pages > 0) { - /* release all locked pages. */ - release_pages(pages, locked_pages, 0); - } - return -ENOMEM; - } - - return 0; -} - -/* Get kernel pointer to shared MMU table given a per-process reference */ -static void *get_mmu_table_kernel_virt(struct mc_mmu_table *table) -{ - if (WARN(!table, "Invalid MMU table")) - return NULL; - - if (WARN(!table->set, "Invalid MMU table set")) - return NULL; - - if (WARN(!table->set->kernel_virt, "Invalid MMU pointer")) - return NULL; - - return &(table->set->kernel_virt->table[table->idx]); -} - -/* - * Search the list of used MMU tables and return the one with the handle. - * Assumes the table_lock is taken. - */ -struct mc_mmu_table *find_mmu_table(unsigned int handle) -{ - struct mc_mmu_table *table; - - list_for_each_entry(table, &mem_ctx.mmu_tables, list) { - if (table->handle == handle) - return table; - } - return NULL; -} - -/* - * Allocate a new MMU table store plus MMU_TABLES_PER_PAGE in the MMU free - * tables list. Assumes the table_lock is already taken by the caller above. - */ -static int alloc_mmu_table_store(void) -{ - unsigned long store; - struct mc_mmu_tables_set *mmutable_set; - struct mc_mmu_table *mmutable, *mmutable2; - struct page *page; - int ret = 0, i; - /* temp list for holding the MMU tables */ - LIST_HEAD(temp); - - store = get_zeroed_page(GFP_KERNEL); - if (!store) - return -ENOMEM; - - /* - * Actually, locking is not necessary, because kernel - * memory is not supposed to get swapped out. But we - * play safe.... - */ - page = virt_to_page(store); - set_bit(PG_reserved, &page->flags); - - /* add all the descriptors to the free descriptors list */ - mmutable_set = kmalloc(sizeof(*mmutable_set), GFP_KERNEL | __GFP_ZERO); - if (mmutable_set == NULL) { - ret = -ENOMEM; - goto free_store; - } - /* initialize */ - mmutable_set->kernel_virt = (void *)store; - mmutable_set->page = page; - mmutable_set->phys = virt_to_phys((void *)store); - /* the set is not yet used */ - atomic_set(&mmutable_set->used_tables, 0); - - /* init add to list. */ - INIT_LIST_HEAD(&(mmutable_set->list)); - list_add(&mmutable_set->list, &mem_ctx.mmu_tables_sets); - - for (i = 0; i < MMU_TABLES_PER_PAGE; i++) { - /* allocate a WSM MMU descriptor */ - mmutable = kmalloc(sizeof(*mmutable), GFP_KERNEL | __GFP_ZERO); - if (mmutable == NULL) { - ret = -ENOMEM; - MCDRV_DBG_ERROR(mcd, "out of memory"); - /* Free the full temp list and the store in this case */ - goto free_temp_list; - } - - /* set set reference */ - mmutable->set = mmutable_set; - mmutable->idx = i; - mmutable->virt = get_mmu_table_kernel_virt(mmutable); - mmutable->phys = mmutable_set->phys+i*sizeof(struct mmutable); - atomic_set(&mmutable->usage, 0); - - /* add to temp list. */ - INIT_LIST_HEAD(&mmutable->list); - list_add_tail(&mmutable->list, &temp); - } - - /* - * If everything went ok then merge the temp list with the global - * free list - */ - list_splice_tail(&temp, &mem_ctx.free_mmu_tables); - return 0; -free_temp_list: - list_for_each_entry_safe(mmutable, mmutable2, &temp, list) { - kfree(mmutable); - } - - list_del(&mmutable_set->list); - -free_store: - free_page(store); - return ret; -} - -/* Get a unique handle */ -static uint32_t get_new_table_handle(void) -{ - uint32_t handle; - struct mc_mmu_table *table; - /* assumption mem_ctx.table_lock mutex is locked */ -retry: - handle = atomic_inc_return(&mem_ctx.table_counter); - if (handle == 0) { - atomic_set(&mem_ctx.table_counter, 1); - handle = 1; - } - list_for_each_entry(table, &mem_ctx.mmu_tables, list) { - if (table->handle == handle) - goto retry; - } - - return handle; -} - -/* - * Get a MMU table from the free tables list or allocate a new one and - * initialize it. Assumes the table_lock is already taken. - */ -static struct mc_mmu_table *alloc_mmu_table(struct mc_instance *instance) -{ - int ret = 0; - struct mc_mmu_table *table = NULL; - - if (list_empty(&mem_ctx.free_mmu_tables)) { - ret = alloc_mmu_table_store(); - if (ret) { - MCDRV_DBG_ERROR(mcd, "Failed to allocate new store!"); - return ERR_PTR(-ENOMEM); - } - /* if it's still empty something wrong has happened */ - if (list_empty(&mem_ctx.free_mmu_tables)) { - MCDRV_DBG_ERROR(mcd, - "Free list not updated correctly!"); - return ERR_PTR(-EFAULT); - } - } - - /* get a WSM MMU descriptor */ - table = list_first_entry(&mem_ctx.free_mmu_tables, - struct mc_mmu_table, list); - if (table == NULL) { - MCDRV_DBG_ERROR(mcd, "out of memory"); - return ERR_PTR(-ENOMEM); - } - /* Move it to the used MMU tables list */ - list_move_tail(&table->list, &mem_ctx.mmu_tables); - - table->handle = get_new_table_handle(); - table->owner = instance; - - atomic_inc(&table->set->used_tables); - atomic_inc(&table->usage); - - MCDRV_DBG_VERBOSE(mcd, - "chunkPhys=0x%llX, idx=%d", - (u64)table->set->phys, table->idx); - - return table; -} - -/* - * Frees the object associated with a MMU table. Initially the object is moved - * to the free tables list, but if all the 4 lists of the store are free - * then the store is also released. - * Assumes the table_lock is already taken. - */ -static void free_mmu_table(struct mc_mmu_table *table) -{ - struct mc_mmu_tables_set *mmutable_set; - - if (WARN(!table, "Invalid table")) - return; - - mmutable_set = table->set; - if (WARN(!mmutable_set, "Invalid table set")) - return; - - list_move_tail(&table->list, &mem_ctx.free_mmu_tables); - - /* if nobody uses this set, we can release it. */ - if (atomic_dec_and_test(&mmutable_set->used_tables)) { - struct mc_mmu_table *tmp; - - /* remove from list */ - list_del(&mmutable_set->list); - /* - * All the MMU tables are in the free list for this set - * so we can just remove them from there - */ - list_for_each_entry_safe(table, tmp, &mem_ctx.free_mmu_tables, - list) { - if (table->set == mmutable_set) { - list_del(&table->list); - kfree(table); - } - } /* end while */ - - /* - * We shouldn't recover from this since it was some data - * corruption before - */ - BUG_ON(!mmutable_set->page); - clear_bit(PG_reserved, &(mmutable_set->page)->flags); - - - BUG_ON(!mmutable_set->kernel_virt); - free_page((unsigned long)mmutable_set->kernel_virt); - - kfree(mmutable_set); - } -} - -/* - * Create a MMU table in a WSM container that has been allocates previously. - * Assumes the table lock is already taken or there is no need to take like - * when first creating the MMU table the full list is locked. - * - * @task pointer to task owning WSM - * @wsm_buffer user space WSM start - * @wsm_len WSM length - * @table Pointer to MMU table details - */ -static int map_buffer(struct task_struct *task, void *wsm_buffer, - unsigned int wsm_len, struct mc_mmu_table *table) -{ - int ret = 0; - unsigned int i, nr_of_pages; - /* start address of the 4 KiB page of wsm_buffer */ - void *virt_addr_page; - struct page *page; - struct mmutable *mmutable; - struct page **mmutable_as_array_of_pointers_to_page = NULL; - /* page offset in wsm buffer */ - unsigned int offset; - - if (WARN(!wsm_buffer, "Invalid WSM buffer pointer")) - return -EINVAL; - - if (WARN(wsm_len == 0, "Invalid WSM buffer length")) - return -EINVAL; - - if (WARN(!table, "Invalid mapping table for WSM")) - return -EINVAL; - - /* no size > 1Mib supported */ - if (wsm_len > SZ_1M) { - MCDRV_DBG_ERROR(mcd, "size > 1 MiB"); - return -EINVAL; - } - - MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x", wsm_buffer, - wsm_len); - - /* calculate page usage */ - virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK); - offset = (unsigned int) (((unsigned long)(wsm_buffer)) & (~PAGE_MASK)); - nr_of_pages = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE; - - MCDRV_DBG_VERBOSE(mcd, "virt addr page start=0x%p, pages=%d", - virt_addr_page, nr_of_pages); - - /* MMU table can hold max 1MiB in 256 pages. */ - if ((nr_of_pages * PAGE_SIZE) > SZ_1M) { - MCDRV_DBG_ERROR(mcd, "WSM paged exceed 1 MiB"); - return -EINVAL; - } - - mmutable = table->virt; -#if (defined LPAE_SUPPORT) || !(defined CONFIG_ARM64) - /* - * We use the memory for the MMU table to hold the pointer - * and convert them later. This works, as everything comes - * down to a 32 bit value. - */ - mmutable_as_array_of_pointers_to_page = (struct page **)mmutable; -#else - mmutable_as_array_of_pointers_to_page = kmalloc( - sizeof(struct page *)*nr_of_pages, GFP_KERNEL | __GFP_ZERO); - if (mmutable_as_array_of_pointers_to_page == NULL) { - ret = -ENOMEM; - goto map_buffer_end; - } -#endif - - /* Request comes from user space */ - if (task != NULL && !is_vmalloc_addr(wsm_buffer)) { - /* - * lock user page in memory, so they do not get swapped - * out. - * REV axh: Kernel 2.6.27 added a new get_user_pages_fast() - * function, maybe it is called fast_gup() in some versions. - * handle user process doing a fork(). - * Child should not get things. - * http://osdir.com/ml/linux-media/2009-07/msg00813.html - * http://lwn.net/Articles/275808/ - */ - ret = lock_pages(task, virt_addr_page, nr_of_pages, - mmutable_as_array_of_pointers_to_page); - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "lock_user_pages() failed"); - goto map_buffer_end; - } - } - /* Request comes from kernel space(cont buffer) */ - else if (task == NULL && !is_vmalloc_addr(wsm_buffer)) { - void *uaddr = wsm_buffer; - for (i = 0; i < nr_of_pages; i++) { - page = virt_to_page(uaddr); - if (!page) { - MCDRV_DBG_ERROR(mcd, "failed to map address"); - return -EINVAL; - } - get_page(page); - mmutable_as_array_of_pointers_to_page[i] = page; - uaddr += PAGE_SIZE; - } - } - /* Request comes from kernel space(vmalloc buffer) */ - else { - void *uaddr = wsm_buffer; - for (i = 0; i < nr_of_pages; i++) { - page = vmalloc_to_page(uaddr); - if (!page) { - MCDRV_DBG_ERROR(mcd, "failed to map address"); - return -EINVAL; - } - get_page(page); - mmutable_as_array_of_pointers_to_page[i] = page; - uaddr += PAGE_SIZE; - } - } - - table->pages = nr_of_pages; - - /* - * create MMU Table entries. - * used_mmutable->table contains a list of page pointers here. - * For a proper cleanup we have to ensure that the following - * code either works and used_mmutable contains a valid MMU table - * - or fails and used_mmutable->table contains the list of page - * pointers. - * Any mixed contents will make cleanup difficult. - * Fill the table in reverse order as the table is used as input and - * output. - */ - i = MC_ARM_MMU_TABLE_ENTRIES-1; - do { - if (i < nr_of_pages) { -#ifdef LPAE_SUPPORT - uint64_t pte; -#else - uint32_t pte; -#endif - page = mmutable_as_array_of_pointers_to_page[i]; - - if (!page) { - MCDRV_DBG_ERROR(mcd, "page address is null"); - return -EFAULT; - } - /* - * create MMU table entry, see ARM MMU docu for details - * about flags stored in the lowest 12 bits. - * As a side reference, the Article - * "ARM's multiply-mapped memory mess" - * found in the collection at - * http://lwn.net/Articles/409032/ - * is also worth reading. - */ - pte = page_to_phys(page); -#ifdef LPAE_SUPPORT - pte |= MMU_EXT_XN - | MMU_EXT_NG - | MMU_EXT_AF - | MMU_AP_RW_ALL - | MMU_NS - | MMU_CACHEABLE | MMU_BUFFERABLE - | MMU_TYPE_PAGE; -#else - pte |= MMU_EXT_AP1 | MMU_EXT_AP0 - | MMU_CACHEABLE | MMU_BUFFERABLE - | MMU_TYPE_SMALL | MMU_TYPE_EXT | MMU_EXT_NG; -#endif /* LPAE_SUPPORT */ - /* - * Linux uses different mappings for SMP systems(the - * sharing flag is set for the pte. In order not to - * confuse things too much in Mobicore make sure the - * shared buffers have the same flags. - * This should also be done in SWD side - */ -#ifdef CONFIG_SMP -#ifdef LPAE_SUPPORT - pte |= MMU_EXT_SHARED; -#else - pte |= MMU_EXT_SHARED | MMU_EXT_TEX(1); -#endif /* LPAE_SUPPORT */ -#endif /* CONFIG_SMP */ - - mmutable->table_entries[i] = pte; - MCDRV_DBG_VERBOSE(mcd, "MMU entry %d: 0x%llx, virt %p", - i, (u64)(pte), page); - } else { - /* ensure rest of table is empty */ - mmutable->table_entries[i] = 0; - } - } while (i-- != 0); - -map_buffer_end: -#if !(defined LPAE_SUPPORT) && (defined CONFIG_ARM64) - kfree(mmutable_as_array_of_pointers_to_page); -#endif - return ret; -} - -/* - * Remove a MMU table in a WSM container. Afterwards the container may be - * released. Assumes the table_lock and the lock is taken. - */ -static void unmap_buffers(struct mc_mmu_table *table) -{ - struct mmutable *mmutable; - int i; - - if (WARN_ON(!table)) - return; - - /* found the table, now release the resources. */ - MCDRV_DBG_VERBOSE(mcd, - "clear table, phys=0x%llX, nr_of_pages=%d, virt=%p", - (u64)table->phys, table->pages, table->virt); - - mmutable = table->virt; - - /* release all locked user space pages */ - for (i = 0; i < table->pages; i++) { - /* convert physical entries from MMU table to page pointers */ - struct page *page = pte_page(mmutable->table_entries[i]); - MCDRV_DBG_VERBOSE(mcd, "MMU entry %d: 0x%llx, virt %p", i, - (u64)(mmutable->table_entries[i]), page); - BUG_ON(!page); - release_page(page); - } - - /* remember that all pages have been freed */ - table->pages = 0; -} - -/* Delete a used MMU table. Assumes the table_lock and the lock is taken */ -static void unmap_mmu_table(struct mc_mmu_table *table) -{ - /* Check if it's not locked by other processes too! */ - if (!atomic_dec_and_test(&table->usage)) - return; - - /* release if Nwd and Swd/MC do no longer use it. */ - unmap_buffers(table); - free_mmu_table(table); -} - -int mc_free_mmu_table(struct mc_instance *instance, uint32_t handle) -{ - struct mc_mmu_table *table; - int ret = 0; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - mutex_lock(&mem_ctx.table_lock); - table = find_mmu_table(handle); - - if (table == NULL) { - MCDRV_DBG_VERBOSE(mcd, "entry not found"); - ret = -EINVAL; - goto err_unlock; - } - if (instance != table->owner && !is_daemon(instance)) { - MCDRV_DBG_ERROR(mcd, "instance does no own it"); - ret = -EPERM; - goto err_unlock; - } - /* free table (if no further locks exist) */ - unmap_mmu_table(table); -err_unlock: - mutex_unlock(&mem_ctx.table_lock); - - return ret; -} - -int mc_lock_mmu_table(struct mc_instance *instance, uint32_t handle) -{ - int ret = 0; - struct mc_mmu_table *table = NULL; - - if (WARN(!instance, "No instance data available")) - return -EFAULT; - - mutex_lock(&mem_ctx.table_lock); - table = find_mmu_table(handle); - - if (table == NULL) { - MCDRV_DBG_VERBOSE(mcd, "entry not found %u", handle); - ret = -EINVAL; - goto table_err; - } - if (instance != table->owner && !is_daemon(instance)) { - MCDRV_DBG_ERROR(mcd, "instance does no own it"); - ret = -EPERM; - goto table_err; - } - - /* lock entry */ - atomic_inc(&table->usage); -table_err: - mutex_unlock(&mem_ctx.table_lock); - return ret; -} -/* - * Allocate MMU table and map buffer into it. - * That is, create respective table entries. - */ -struct mc_mmu_table *mc_alloc_mmu_table(struct mc_instance *instance, - struct task_struct *task, void *wsm_buffer, unsigned int wsm_len) -{ - int ret = 0; - struct mc_mmu_table *table; - - if (WARN(!instance, "No instance data available")) - return ERR_PTR(-EFAULT); - - mutex_lock(&mem_ctx.table_lock); - table = alloc_mmu_table(instance); - if (IS_ERR(table)) { - MCDRV_DBG_ERROR(mcd, "alloc_mmu_table() failed"); - ret = -ENOMEM; - goto err_no_mem; - } - - /* create the MMU page for the WSM */ - ret = map_buffer(task, wsm_buffer, wsm_len, table); - - if (ret != 0) { - MCDRV_DBG_ERROR(mcd, "map_buffer() failed"); - unmap_mmu_table(table); - goto err_no_mem; - } - MCDRV_DBG_VERBOSE(mcd, - "mapped buffer %p to table with handle %d @ 0x%llX", - wsm_buffer, table->handle, (u64)table->phys); - - mutex_unlock(&mem_ctx.table_lock); - return table; -err_no_mem: - mutex_unlock(&mem_ctx.table_lock); - return ERR_PTR(ret); -} - -phys_addr_t mc_find_mmu_table(uint32_t handle, int32_t fd) -{ - phys_addr_t ret = 0; - struct mc_mmu_table *table = NULL; - - mutex_lock(&mem_ctx.table_lock); - table = find_mmu_table(handle); - - if (table == NULL) { - MCDRV_DBG_ERROR(mcd, "entry not found %u", handle); - ret = 0; - goto table_err; - } - - /* It's safe here not to lock the instance since the owner of - * the table will be cleared only with the table lock taken */ - if (!mc_check_owner_fd(table->owner, fd)) { - MCDRV_DBG_ERROR(mcd, "not valid owner %u", handle); - ret = 0; - goto table_err; - } - - ret = table->phys; -table_err: - mutex_unlock(&mem_ctx.table_lock); - return ret; -} - -void mc_clean_mmu_tables(void) -{ - struct mc_mmu_table *table, *tmp; - - mutex_lock(&mem_ctx.table_lock); - /* Check if some WSM is orphaned. */ - list_for_each_entry_safe(table, tmp, &mem_ctx.mmu_tables, list) { - if (table->owner == NULL) { - /*MCDRV_DBG(mcd, - "cleariM MMU: p=0x%llX pages=%d", - (u64)table->phys, - table->pages);*/ - unmap_mmu_table(table); - } - } - mutex_unlock(&mem_ctx.table_lock); -} - -void mc_clear_mmu_tables(struct mc_instance *instance) -{ - struct mc_mmu_table *table, *tmp; - - mutex_lock(&mem_ctx.table_lock); - /* Check if some WSM is still in use. */ - list_for_each_entry_safe(table, tmp, &mem_ctx.mmu_tables, list) { - if (table->owner == instance) { - /*MCDRV_DBG(mcd, "release WSM MMU: p=0x%llX pages=%d", - (u64)table->phys, - table->pages);*/ - /* unlock app usage and free or mark it as orphan */ - table->owner = NULL; - unmap_mmu_table(table); - } - } - mutex_unlock(&mem_ctx.table_lock); -} - -int mc_init_mmu_tables(void) -{ - /* init list for WSM MMU chunks. */ - INIT_LIST_HEAD(&mem_ctx.mmu_tables_sets); - - /* MMU table descriptor list. */ - INIT_LIST_HEAD(&mem_ctx.mmu_tables); - - /* MMU free table descriptor list. */ - INIT_LIST_HEAD(&mem_ctx.free_mmu_tables); - - mutex_init(&mem_ctx.table_lock); - atomic_set(&mem_ctx.table_counter, 1); - - return 0; -} - -void mc_release_mmu_tables(void) -{ - struct mc_mmu_table *table; - /* Check if some WSM is still in use. */ - list_for_each_entry(table, &mem_ctx.mmu_tables, list) { - WARN(1, "WSM MMU still in use: phys=0x%llX ,nr_of_pages=%d", - (u64)table->phys, table->pages); - } -} diff --git a/drivers/gud/MobiCoreDriver/mem.h b/drivers/gud/MobiCoreDriver/mem.h deleted file mode 100644 index 10fc2e87cdce..000000000000 --- a/drivers/gud/MobiCoreDriver/mem.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_MEM_H_ -#define _MC_MEM_H_ - -#ifdef LPAE_SUPPORT -/* - * Number of page table entries in one MMU table. This is ARM specific, an - * MMU table covers 2 MiB by using 512 entries referring to 4KiB pages each. - */ -#define MC_ARM_MMU_TABLE_ENTRIES 512 - -/* ARM level 3 (MMU) table with 512 entries. Size: 4k */ -struct mmutable { - uint64_t table_entries[MC_ARM_MMU_TABLE_ENTRIES]; -}; - -/* There is 1 table in each page. */ -#define MMU_TABLES_PER_PAGE 1 -#else -/* - * MobiCore specific page tables for world shared memory. - * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level. - * MobiCore uses the default ARM format. - * - * Number of page table entries in one MMU table. This is ARM specific, an - * MMU table covers 1 MiB by using 256 entries referring to 4KiB pages each. - */ -#define MC_ARM_MMU_TABLE_ENTRIES 256 - -/* ARM level 2 (MMU) table with 256 entries. Size: 1k */ -struct mmutable { - uint32_t table_entries[MC_ARM_MMU_TABLE_ENTRIES]; -}; - -/* There are 4 tables in each page. */ -#define MMU_TABLES_PER_PAGE 4 -#endif - -/* Store for four MMU tables in one 4kb page*/ -struct mc_mmu_table_store { - struct mmutable table[MMU_TABLES_PER_PAGE]; -}; - -/* Usage and maintenance information about mc_mmu_table_store */ -struct mc_mmu_tables_set { - struct list_head list; - /* kernel virtual address */ - struct mc_mmu_table_store *kernel_virt; - /* physical address */ - phys_addr_t phys; - /* pointer to page struct */ - struct page *page; - /* How many pages from this set are used */ - atomic_t used_tables; -}; - -/* - * MMU table allocated to the Daemon or a TLC describing a world shared - * buffer. - * When users map a malloc()ed area into SWd, a MMU table is allocated. - * In addition, the area of maximum 1MB virtual address space is mapped into - * the MMU table and a handle for this table is returned to the user. - */ -struct mc_mmu_table { - struct list_head list; - /* Table lock */ - struct mutex lock; - /* handle as communicated to user mode */ - unsigned int handle; - /* Number of references kept to this MMU table */ - atomic_t usage; - /* owner of this MMU table */ - struct mc_instance *owner; - /* set describing where our MMU table is stored */ - struct mc_mmu_tables_set *set; - /* index into MMU table set */ - unsigned int idx; - /* size of buffer */ - unsigned int pages; - /* virtual address*/ - void *virt; - /* physical address */ - phys_addr_t phys; -}; - -/* MobiCore Driver Memory context data. */ -struct mc_mem_context { - struct mc_instance *daemon_inst; - /* Backing store for MMU tables */ - struct list_head mmu_tables_sets; - /* Bookkeeping for used MMU tables */ - struct list_head mmu_tables; - /* Bookkeeping for free MMU tables */ - struct list_head free_mmu_tables; - /* semaphore to synchronize access to above lists */ - struct mutex table_lock; - atomic_t table_counter; -}; - -/* - * Allocate MMU table and map buffer into it. - * That is, create respective table entries. - */ -struct mc_mmu_table *mc_alloc_mmu_table(struct mc_instance *instance, - struct task_struct *task, void *wsm_buffer, unsigned int wsm_len); - -/* Delete all the MMU tables associated with an instance */ -void mc_clear_mmu_tables(struct mc_instance *instance); - -/* Release all orphaned MMU tables */ -void mc_clean_mmu_tables(void); - -/* Delete a used MMU table. */ -int mc_free_mmu_table(struct mc_instance *instance, uint32_t handle); - -/* - * Lock a MMU table - the daemon adds +1 to refcount of the MMU table - * marking it in use by SWD so it doesn't get released when the TLC dies. - */ -int mc_lock_mmu_table(struct mc_instance *instance, uint32_t handle); - -/* Return the phys address of MMU table. */ -phys_addr_t mc_find_mmu_table(uint32_t handle, int32_t fd); -/* Release all used MMU tables to Linux memory space */ -void mc_release_mmu_tables(void); - -/* Initialize all MMU tables structure */ -int mc_init_mmu_tables(void); - -#endif /* _MC_MEM_H_ */ diff --git a/drivers/gud/MobiCoreDriver/ops.c b/drivers/gud/MobiCoreDriver/ops.c deleted file mode 100644 index 57a075727e1d..000000000000 --- a/drivers/gud/MobiCoreDriver/ops.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * MobiCore Driver Kernel Module. - * - * This module is written as a Linux device driver. - * This driver represents the command proxy on the lowest layer, from the - * secure world to the non secure world, and vice versa. - * This driver is located in the non secure world (Linux). - * This driver offers IOCTL commands, for access to the secure world, and has - * the interface from the secure world to the normal world. - * The access to the driver is possible with a file descriptor, - * which has to be created by the fd = open(/dev/mobicore) command. - */ -#include <linux/kthread.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/workqueue.h> -#include <linux/cpu.h> -#include <linux/moduleparam.h> - - -#include "main.h" -#include "fastcall.h" -#include "ops.h" -#include "mem.h" -#include "pm.h" -#include "debug.h" - -/* MobiCore context data */ -static struct mc_context *ctx; -#ifdef TBASE_CORE_SWITCHER -static uint32_t active_cpu; - -#ifdef TEST - /* - * Normal world <t-base core info for testing. - */ - - module_param(active_cpu, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - MODULE_PARM_DESC(active_cpu, "Active <t-base Core"); -#endif - - -static int mobicore_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu); -static struct notifier_block mobicore_cpu_notifer = { - .notifier_call = mobicore_cpu_callback, -}; -#endif - -static inline long smc(union fc_generic *fc) -{ - /* If we request sleep yields must be filtered out as they - * make no sense */ - if (ctx->mcp) - if (ctx->mcp->flags.sleep_mode.sleep_req) { - if (fc->as_in.cmd == MC_SMC_N_YIELD) - return MC_FC_RET_ERR_INVALID; - } - return _smc(fc); -} - -struct fastcall_work { -#ifdef MC_FASTCALL_WORKER_THREAD - struct kthread_work work; -#else - struct work_struct work; -#endif - void *data; -}; - -#ifdef MC_FASTCALL_WORKER_THREAD -static void fastcall_work_func(struct kthread_work *work); -#else -static void fastcall_work_func(struct work_struct *work); -#endif - - -#ifdef MC_FASTCALL_WORKER_THREAD - -static struct task_struct *fastcall_thread; -static DEFINE_KTHREAD_WORKER(fastcall_worker); - -bool mc_fastcall(void *data) -{ - struct fastcall_work fc_work = { - KTHREAD_WORK_INIT(fc_work.work, fastcall_work_func), - .data = data, - }; - - if (!queue_kthread_work(&fastcall_worker, &fc_work.work)) - return false; - flush_kthread_work(&fc_work.work); - return true; -} - -int mc_fastcall_init(struct mc_context *context) -{ - int ret = 0; - ctx = context; - - fastcall_thread = kthread_create(kthread_worker_fn, &fastcall_worker, - "mc_fastcall"); - if (IS_ERR(fastcall_thread)) { - ret = PTR_ERR(fastcall_thread); - fastcall_thread = NULL; - MCDRV_DBG_ERROR(mcd, "cannot create fastcall wq (%d)", ret); - return ret; - } - - wake_up_process(fastcall_thread); - - /* this thread MUST run on CPU 0 at startup */ - set_cpus_allowed(fastcall_thread, CPU_MASK_CPU0); -#ifdef TBASE_CORE_SWITCHER - register_cpu_notifier(&mobicore_cpu_notifer); -#endif - return 0; -} - -void mc_fastcall_destroy(void) -{ - if (!IS_ERR_OR_NULL(fastcall_thread)) { - kthread_stop(fastcall_thread); - fastcall_thread = NULL; - } -} -#else - -bool mc_fastcall(void *data) -{ - struct fastcall_work work = { - .data = data, - }; - INIT_WORK(&work.work, fastcall_work_func); - if (!schedule_work_on(0, &work.work)) - return false; - flush_work(&work.work); - return true; -} - -int mc_fastcall_init(struct mc_context *context) -{ - ctx = context; - return 0; -}; - -void mc_fastcall_destroy(void) {}; -#endif - -#ifdef MC_FASTCALL_WORKER_THREAD -static void fastcall_work_func(struct kthread_work *work) -#else -static void fastcall_work_func(struct work_struct *work) -#endif -{ - struct fastcall_work *fc_work = - container_of(work, struct fastcall_work, work); - union fc_generic *fc_generic = fc_work->data; -#ifdef TBASE_CORE_SWITCHER - uint32_t cpu_swap = 0, new_cpu; - uint32_t cpu_id[] = CPU_IDS; -#endif - -#ifdef MC_CRYPTO_CLOCK_MANAGEMENT - mc_pm_clock_enable(); -#endif - - - if (fc_generic == NULL) - return; -#ifdef TBASE_CORE_SWITCHER - if (fc_generic->as_in.cmd == MC_FC_SWITCH_CORE) { - cpu_swap = 1; - new_cpu = fc_generic->as_in.param[0]; - fc_generic->as_in.param[0] = cpu_id[fc_generic->as_in.param[0]]; - } -#endif - smc(fc_work->data); -#ifdef TBASE_CORE_SWITCHER - if (cpu_swap) { - if (fc_generic->as_out.ret == 0) { - cpumask_t cpu; - active_cpu = new_cpu; - MCDRV_DBG(mcd, "CoreSwap ok %d -> %d\n", - raw_smp_processor_id(), active_cpu); - cpumask_clear(&cpu); - cpumask_set_cpu(active_cpu, &cpu); -#ifdef MC_FASTCALL_WORKER_THREAD - set_cpus_allowed(fastcall_thread, cpu); -#endif - } else { - MCDRV_DBG(mcd, "CoreSwap failed %d -> %d\n", - raw_smp_processor_id(), - fc_generic->as_in.param[0]); - } - } -#endif -#ifdef MC_CRYPTO_CLOCK_MANAGEMENT - mc_pm_clock_disable(); -#endif -} - -int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info) -{ - int ret = 0; - union mc_fc_info fc_info; - - MCDRV_DBG_VERBOSE(mcd, "enter"); - - memset(&fc_info, 0, sizeof(fc_info)); - fc_info.as_in.cmd = MC_FC_INFO; - fc_info.as_in.ext_info_id = ext_info_id; - - MCDRV_DBG(mcd, "<- cmd=0x%08x, ext_info_id=0x%08x", - fc_info.as_in.cmd, fc_info.as_in.ext_info_id); - - mc_fastcall(&(fc_info.as_generic)); - - MCDRV_DBG(mcd, - "-> r=0x%08x ret=0x%08x state=0x%08x ext_info=0x%08x", - fc_info.as_out.resp, - fc_info.as_out.ret, - fc_info.as_out.state, - fc_info.as_out.ext_info); - - ret = convert_fc_ret(fc_info.as_out.ret); - - *state = fc_info.as_out.state; - *ext_info = fc_info.as_out.ext_info; - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret); - - return ret; -} - -#ifdef TBASE_CORE_SWITCHER - -uint32_t mc_active_core(void) -{ - return active_cpu; -} - -int mc_switch_core(uint32_t core_num) -{ - int32_t ret = 0; - union mc_fc_swich_core fc_switch_core; - - if (!cpu_online(core_num)) - return 1; - - MCDRV_DBG_VERBOSE(mcd, "enter\n"); - - memset(&fc_switch_core, 0, sizeof(fc_switch_core)); - fc_switch_core.as_in.cmd = MC_FC_SWITCH_CORE; - - if (core_num < COUNT_OF_CPUS) - fc_switch_core.as_in.core_id = core_num; - else - fc_switch_core.as_in.core_id = 0; - - MCDRV_DBG(mcd, - "<- cmd=0x%08x, core_id=0x%08x\n", - fc_switch_core.as_in.cmd, - fc_switch_core.as_in.core_id); - MCDRV_DBG(mcd, - "<- core_num=0x%08x, active_cpu=0x%08x\n", - core_num, active_cpu); - mc_fastcall(&(fc_switch_core.as_generic)); - - ret = convert_fc_ret(fc_switch_core.as_out.ret); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); - - return ret; -} - -void mc_cpu_offfline(int cpu) -{ - if (active_cpu == cpu) { - int i; - /* Chose the first online CPU and switch! */ - for_each_online_cpu(i) { - if (i == cpu) { - MCDRV_DBG(mcd, "Skipping CPU %d\n", cpu); - continue; - } - MCDRV_DBG(mcd, "CPU %d is dying, switching to %d\n", - cpu, i); - mc_switch_core(i); - break; - } - } else { - MCDRV_DBG(mcd, "not active CPU, no action taken\n"); - } -} - -static int mobicore_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - - switch (action) { - case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: - dev_info(mcd, "Cpu %u is going to die\n", cpu); - mc_cpu_offfline(cpu); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - dev_info(mcd, "Cpu %u is dead\n", cpu); - break; - } - return NOTIFY_OK; -} -#endif - -/* Yield to MobiCore */ -int mc_yield(void) -{ - int ret = 0; - union fc_generic yield; - - MCDRV_DBG_VERBOSE(mcd, "enter"); - memset(&yield, 0, sizeof(yield)); - yield.as_in.cmd = MC_SMC_N_YIELD; - mc_fastcall(&yield); - ret = convert_fc_ret(yield.as_out.ret); - - return ret; -} - -/* call common notify */ -int mc_nsiq(void) -{ - int ret = 0; - union fc_generic nsiq; - MCDRV_DBG_VERBOSE(mcd, "enter"); - memset(&nsiq, 0, sizeof(nsiq)); - nsiq.as_in.cmd = MC_SMC_N_SIQ; - mc_fastcall(&nsiq); - ret = convert_fc_ret(nsiq.as_out.ret); - return ret; -} - -/* call common notify */ -int _nsiq(void) -{ - int ret = 0; - union fc_generic nsiq; - MCDRV_DBG_VERBOSE(mcd, "enter"); - memset(&nsiq, 0, sizeof(nsiq)); - nsiq.as_in.cmd = MC_SMC_N_SIQ; - _smc(&nsiq); - ret = convert_fc_ret(nsiq.as_out.ret); - return ret; -} - -/* Call the INIT fastcall to setup MobiCore initialization */ -int mc_init(phys_addr_t base, uint32_t nq_length, - uint32_t mcp_offset, uint32_t mcp_length) -{ - int ret = 0; - union mc_fc_init fc_init; - uint64_t base_addr = (uint64_t)base; - uint32_t base_high = (uint32_t)(base_addr >> 32); - - MCDRV_DBG_VERBOSE(mcd, "enter"); - - memset(&fc_init, 0, sizeof(fc_init)); - - fc_init.as_in.cmd = MC_FC_INIT; - /* base address of mci buffer 4KB aligned */ - fc_init.as_in.base = (uint32_t)base_addr; - /* notification buffer start/length [16:16] [start, length] */ - fc_init.as_in.nq_info = ((base_high && 0xFFFF) << 16) | - (nq_length & 0xFFFF); - /* mcp buffer start/length [16:16] [start, length] */ - fc_init.as_in.mcp_info = (mcp_offset << 16) | (mcp_length & 0xFFFF); - - /* - * Set KMOD notification queue to start of MCI - * mciInfo was already set up in mmap - */ - MCDRV_DBG(mcd, - "cmd=0x%08x, base=0x%08x,nq_info=0x%08x, mcp_info=0x%08x", - fc_init.as_in.cmd, fc_init.as_in.base, fc_init.as_in.nq_info, - fc_init.as_in.mcp_info); - mc_fastcall(&fc_init.as_generic); - MCDRV_DBG(mcd, "out cmd=0x%08x, ret=0x%08x", fc_init.as_out.resp, - fc_init.as_out.ret); - - ret = convert_fc_ret(fc_init.as_out.ret); - - MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret); - - return ret; -} - -/* Return MobiCore driver version */ -uint32_t mc_get_version(void) -{ - MCDRV_DBG(mcd, "MobiCore driver version is %i.%i", - MCDRVMODULEAPI_VERSION_MAJOR, - MCDRVMODULEAPI_VERSION_MINOR); - - return MC_VERSION(MCDRVMODULEAPI_VERSION_MAJOR, - MCDRVMODULEAPI_VERSION_MINOR); -} diff --git a/drivers/gud/MobiCoreDriver/ops.h b/drivers/gud/MobiCoreDriver/ops.h deleted file mode 100644 index 30458a37d120..000000000000 --- a/drivers/gud/MobiCoreDriver/ops.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_OPS_H_ -#define _MC_OPS_H_ - -#include <linux/workqueue.h> -#include "fastcall.h" - -int mc_yield(void); -int mc_nsiq(void); -int _nsiq(void); -uint32_t mc_get_version(void); - -int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info); -int mc_init(phys_addr_t base, uint32_t nq_length, uint32_t mcp_offset, - uint32_t mcp_length); -#ifdef TBASE_CORE_SWITCHER -int mc_switch_core(uint32_t core_num); -#endif - -bool mc_fastcall(void *data); - -int mc_fastcall_init(struct mc_context *context); -void mc_fastcall_destroy(void); - -#endif /* _MC_OPS_H_ */ diff --git a/drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h b/drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h deleted file mode 100644 index 81096113a68c..000000000000 --- a/drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * Header file of MobiCore Driver Kernel Module Platform - * specific structures - * - * Internal structures of the McDrvModule - * - * Header file the MobiCore Driver Kernel Module, - * its internal structures and defines. - */ -#ifndef _MC_PLATFORM_H_ -#define _MC_PLATFORM_H_ - -/* MobiCore Interrupt for Qualcomm */ -#define MC_INTR_SSIQ 280 - -/* Use SMC for fastcalls */ -#define MC_SMC_FASTCALL - -/*--------------- Implementation -------------- */ -#include <soc/qcom/scm.h> - -#if defined(CONFIG_ARCH_APQ8084) || defined(CONFIG_ARCH_MSM8916) || \ - defined(CONFIG_ARCH_MSM8994) - - #include <soc/qcom/qseecomi.h> - #include <linux/slab.h> - #include <linux/io.h> - #include <linux/mm.h> - #include <asm/cacheflush.h> - #include <linux/errno.h> - - #define SCM_MOBIOS_FNID(s, c) (((((s) & 0xFF) << 8) | ((c) & 0xFF)) \ - | 0x33000000) - - #define TZ_EXECUTIVE_EXT_ID_PARAM_ID \ - TZ_SYSCALL_CREATE_PARAM_ID_4( \ - TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ - TZ_SYSCALL_PARAM_TYPE_VAL, \ - TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ - TZ_SYSCALL_PARAM_TYPE_VAL) - -#endif - -/* from following file */ -#define SCM_SVC_MOBICORE 250 -#define SCM_CMD_MOBICORE 1 - - -static inline int smc_fastcall(void *fc_generic, size_t size) -{ -#if defined(CONFIG_ARCH_APQ8084) || defined(CONFIG_ARCH_MSM8916) || \ - defined(CONFIG_ARCH_MSM8994) - if (is_scm_armv8()) { - struct scm_desc desc = {0}; - int ret; - void *scm_buf = NULL; - - scm_buf = kzalloc(PAGE_ALIGN(size), GFP_KERNEL); - if (!scm_buf) - return -ENOMEM; - memcpy(scm_buf, fc_generic, size); - dmac_flush_range(scm_buf, scm_buf + size); - - desc.arginfo = TZ_EXECUTIVE_EXT_ID_PARAM_ID; - desc.args[0] = virt_to_phys(scm_buf); - desc.args[1] = (u32)size; - desc.args[2] = virt_to_phys(scm_buf); - desc.args[3] = (u32)size; - ret = scm_call2( - SCM_MOBIOS_FNID(SCM_SVC_MOBICORE, SCM_CMD_MOBICORE), - &desc); - - dmac_flush_range(scm_buf, scm_buf + size); - - memcpy(fc_generic, scm_buf, size); - kfree(scm_buf); - return ret; - } else { -#endif - - return scm_call(SCM_SVC_MOBICORE, SCM_CMD_MOBICORE, - fc_generic, size, - fc_generic, size); -#if defined(CONFIG_ARCH_APQ8084) || defined(CONFIG_ARCH_MSM8916) || \ - defined(CONFIG_ARCH_MSM8994) - } -#endif -} - -/* Enable mobicore mem traces */ -#define MC_MEM_TRACES - -/* Enable the use of vm_unamp instead of the deprecated do_munmap - * and other 3.7 features - */ -#define MC_VM_UNMAP - -/* - * Perform crypto clock enable/disable - */ -#if !defined(CONFIG_ARCH_MSM8960) && !defined(CONFIG_ARCH_MSM8994) -#define MC_CRYPTO_CLOCK_MANAGEMENT -#endif - -#if defined(CONFIG_ARCH_MSM8916) || defined(CONFIG_ARCH_MSM8909) -#define MC_USE_DEVICE_TREE -#endif - -#endif /* _MC_PLATFORM_H_ */ diff --git a/drivers/gud/MobiCoreDriver/pm.c b/drivers/gud/MobiCoreDriver/pm.c deleted file mode 100644 index f89726565946..000000000000 --- a/drivers/gud/MobiCoreDriver/pm.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * MobiCore Driver Kernel Module. - * This module is written as a Linux device driver. - * This driver represents the command proxy on the lowest layer, from the - * secure world to the non secure world, and vice versa. - * This driver is located in the non secure world (Linux). - * This driver offers IOCTL commands, for access to the secure world, and has - * the interface from the secure world to the normal world. - * The access to the driver is possible with a file descriptor, - * which has to be created by the fd = open(/dev/mobicore) command. - */ -#include <linux/module.h> -#include <linux/timer.h> -#include <linux/suspend.h> -#include <linux/device.h> - -#include "main.h" -#include "pm.h" -#include "fastcall.h" -#include "ops.h" -#include "logging.h" -#include "debug.h" - -#ifdef MC_CRYPTO_CLOCK_MANAGEMENT - #include <linux/clk.h> - #include <linux/err.h> - - struct clk *mc_ce_iface_clk = NULL; - struct clk *mc_ce_core_clk = NULL; - struct clk *mc_ce_bus_clk = NULL; - -#endif /* MC_CRYPTO_CLOCK_MANAGEMENT */ - -#if defined(MC_CRYPTO_CLOCK_MANAGEMENT) && defined(MC_USE_DEVICE_TREE) - #include <linux/of.h> - #define QSEE_CE_CLK_100MHZ 100000000 - struct clk *mc_ce_core_src_clk = NULL; -#endif /* MC_CRYPTO_CLOCK_MANAGEMENT && MC_USE_DEVICE_TREE */ - -#ifdef MC_PM_RUNTIME - -static struct mc_context *ctx; - -static bool sleep_ready(void) -{ - if (!ctx->mcp) - return false; - - if (!(ctx->mcp->flags.sleep_mode.ready_to_sleep & READY_TO_SLEEP)) - return false; - - return true; -} - -static void mc_suspend_handler(struct work_struct *work) -{ - if (!ctx->mcp) - return; - - ctx->mcp->flags.sleep_mode.sleep_req = REQ_TO_SLEEP; - _nsiq(); -} -DECLARE_WORK(suspend_work, mc_suspend_handler); - -static inline void dump_sleep_params(struct mc_flags *flags) -{ - MCDRV_DBG(mcd, "MobiCore IDLE=%d!", flags->schedule); - MCDRV_DBG(mcd, - "MobiCore Request Sleep=%d!", flags->sleep_mode.sleep_req); - MCDRV_DBG(mcd, - "MobiCore Sleep Ready=%d!", flags->sleep_mode.ready_to_sleep); -} - -static int mc_suspend_notifier(struct notifier_block *nb, - unsigned long event, void *dummy) -{ - struct mc_mcp_buffer *mcp = ctx->mcp; - /* We have noting to say if MobiCore is not initialized */ - if (!mcp) - return 0; - -#ifdef MC_MEM_TRACES - mobicore_log_read(); -#endif /* MC_MEM_TRACES */ - - switch (event) { - case PM_SUSPEND_PREPARE: - /* - * Make sure we have finished all the work otherwise - * we end up in a race condition - */ - cancel_work_sync(&suspend_work); - /* - * We can't go to sleep if MobiCore is not IDLE - * or not Ready to sleep - */ - dump_sleep_params(&mcp->flags); - if (!sleep_ready()) { - ctx->mcp->flags.sleep_mode.sleep_req = REQ_TO_SLEEP; - schedule_work_on(0, &suspend_work); - flush_work(&suspend_work); - if (!sleep_ready()) { - dump_sleep_params(&mcp->flags); - ctx->mcp->flags.sleep_mode.sleep_req = 0; - MCDRV_DBG_ERROR(mcd, "MobiCore can't SLEEP!"); - return NOTIFY_BAD; - } - } - break; - case PM_POST_SUSPEND: - MCDRV_DBG(mcd, "Resume MobiCore system!"); - ctx->mcp->flags.sleep_mode.sleep_req = 0; - break; - default: - break; - } - return 0; -} - -static struct notifier_block mc_notif_block = { - .notifier_call = mc_suspend_notifier, -}; - -int mc_pm_initialize(struct mc_context *context) -{ - int ret = 0; - - ctx = context; - - ret = register_pm_notifier(&mc_notif_block); - if (ret) - MCDRV_DBG_ERROR(mcd, "device pm register failed"); - - return ret; -} - -int mc_pm_free(void) -{ - int ret = unregister_pm_notifier(&mc_notif_block); - if (ret) - MCDRV_DBG_ERROR(mcd, "device pm unregister failed"); - return ret; -} - -bool mc_pm_sleep_ready(void) -{ - if (ctx == 0) - return true; - return sleep_ready(); -} -#endif /* MC_PM_RUNTIME */ - -#ifdef MC_CRYPTO_CLOCK_MANAGEMENT - -int mc_pm_clock_initialize(void) -{ - int ret = 0; - -#ifdef MC_USE_DEVICE_TREE - /* Get core clk src */ - mc_ce_core_src_clk = clk_get(mcd, "core_clk_src"); - if (IS_ERR(mc_ce_core_src_clk)) { - ret = PTR_ERR(mc_ce_core_src_clk); - MCDRV_DBG_ERROR(mcd, - "cannot get core clock src with error: %d", - ret); - goto error; - } else { - int ce_opp_freq_hz = QSEE_CE_CLK_100MHZ; - - if (of_property_read_u32(mcd->of_node, - "qcom,ce-opp-freq", - &ce_opp_freq_hz)) { - ce_opp_freq_hz = QSEE_CE_CLK_100MHZ; - MCDRV_DBG_ERROR(mcd, - "cannot get ce clock frequency. Using %d", - ce_opp_freq_hz); - } - ret = clk_set_rate(mc_ce_core_src_clk, ce_opp_freq_hz); - if (ret) { - clk_put(mc_ce_core_src_clk); - mc_ce_core_src_clk = NULL; - MCDRV_DBG_ERROR(mcd, "cannot set core clock src rate"); - ret = -EIO; - goto error; - } - } -#endif /* MC_CRYPTO_CLOCK_MANAGEMENT && MC_USE_DEVICE_TREE */ - - /* Get core clk */ - mc_ce_core_clk = clk_get(mcd, "core_clk"); - if (IS_ERR(mc_ce_core_clk)) { - ret = PTR_ERR(mc_ce_core_clk); - MCDRV_DBG_ERROR(mcd, "cannot get core clock"); - goto error; - } - /* Get Interface clk */ - mc_ce_iface_clk = clk_get(mcd, "iface_clk"); - if (IS_ERR(mc_ce_iface_clk)) { - clk_put(mc_ce_core_clk); - ret = PTR_ERR(mc_ce_iface_clk); - MCDRV_DBG_ERROR(mcd, "cannot get iface clock"); - goto error; - } - /* Get AXI clk */ - mc_ce_bus_clk = clk_get(mcd, "bus_clk"); - if (IS_ERR(mc_ce_bus_clk)) { - clk_put(mc_ce_iface_clk); - clk_put(mc_ce_core_clk); - ret = PTR_ERR(mc_ce_bus_clk); - MCDRV_DBG_ERROR(mcd, "cannot get AXI bus clock"); - goto error; - } - - MCDRV_DBG(mcd, "obtained crypto clocks"); - return ret; - -error: - mc_ce_core_clk = NULL; - mc_ce_iface_clk = NULL; - mc_ce_bus_clk = NULL; - - return ret; -} - -void mc_pm_clock_finalize(void) -{ - if (mc_ce_bus_clk != NULL) - clk_put(mc_ce_bus_clk); - - if (mc_ce_iface_clk != NULL) - clk_put(mc_ce_iface_clk); - - if (mc_ce_core_clk != NULL) - clk_put(mc_ce_core_clk); - -#ifdef MC_USE_DEVICE_TREE - if (mc_ce_core_src_clk != NULL) - clk_put(mc_ce_core_src_clk); -#endif /* MC_CRYPTO_CLOCK_MANAGEMENT && MC_USE_DEVICE_TREE */ -} - -int mc_pm_clock_enable(void) -{ - int rc = 0; - - rc = clk_prepare_enable(mc_ce_core_clk); - if (rc) { - MCDRV_DBG_ERROR(mcd, "cannot enable clock"); - } else { - rc = clk_prepare_enable(mc_ce_iface_clk); - if (rc) { - clk_disable_unprepare(mc_ce_core_clk); - MCDRV_DBG_ERROR(mcd, "cannot enable clock"); - } else { - rc = clk_prepare_enable(mc_ce_bus_clk); - if (rc) { - clk_disable_unprepare(mc_ce_iface_clk); - MCDRV_DBG_ERROR(mcd, "cannot enable clock"); - } - } - } - return rc; -} - -void mc_pm_clock_disable(void) -{ - if (mc_ce_iface_clk != NULL) - clk_disable_unprepare(mc_ce_iface_clk); - - if (mc_ce_core_clk != NULL) - clk_disable_unprepare(mc_ce_core_clk); - - if (mc_ce_bus_clk != NULL) - clk_disable_unprepare(mc_ce_bus_clk); -} - -#endif /* MC_CRYPTO_CLOCK_MANAGEMENT */ diff --git a/drivers/gud/MobiCoreDriver/pm.h b/drivers/gud/MobiCoreDriver/pm.h deleted file mode 100644 index 6581425a71cb..000000000000 --- a/drivers/gud/MobiCoreDriver/pm.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_PM_H_ -#define _MC_PM_H_ - -#include "main.h" -#ifdef MC_BL_NOTIFIER -#include <asm/bL_switcher.h> -#endif - - -#define NO_SLEEP_REQ 0 -#define REQ_TO_SLEEP 1 - -#define NORMAL_EXECUTION 0 -#define READY_TO_SLEEP 1 - -/* How much time after resume the daemon should backoff */ -#define DAEMON_BACKOFF_TIME 500 - -/* Initialize Power Management */ -int mc_pm_initialize(struct mc_context *context); -/* Free all Power Management resources*/ -int mc_pm_free(void); -/* Initialize secure crypto clocks */ -int mc_pm_clock_initialize(void); -/* Free secure crypto clocks */ -void mc_pm_clock_finalize(void); -/* Enable secure crypto clocks */ -int mc_pm_clock_enable(void); -/* Disable secure crypto clocks */ -void mc_pm_clock_disable(void); -/* Test if sleep is possible */ -bool mc_pm_sleep_ready(void); - -#endif /* _MC_PM_H_ */ diff --git a/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h b/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h deleted file mode 100644 index 96805fda11f1..000000000000 --- a/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * Interface to be used by module MobiCoreKernelAPI. - */ -#ifndef _MC_KERNEL_API_H_ -#define _MC_KERNEL_API_H_ - -struct mc_instance; - -/* - * mobicore_open() - Initialize a new MobiCore API instance object - * - * Returns a MobiCore Instance or NULL if no allocation was possible. - */ -struct mc_instance *mobicore_open(void); - -/* - * mobicore_release() - Release a MobiCore instance object - * @instance: MobiCore instance - * - * Returns 0 if Ok or -E ERROR - */ -int mobicore_release(struct mc_instance *instance); - -/* - * mobicore_allocate_wsm() - Allocate MobiCore WSM - * @instance: instance data for MobiCore Daemon and TLCs - * @requested_size: memory size requested in bytes - * @handle: pointer to handle - * @kernel_virt_addr: virtual user start address - * - * Returns 0 if OK - */ -int mobicore_allocate_wsm(struct mc_instance *instance, - unsigned long requested_size, uint32_t *handle, - void **virt_kernel_addr); - -/* - * mobicore_free() - Free a WSM buffer allocated with mobicore_allocate_wsm - * @instance: instance data for MobiCore Daemon and TLCs - * @handle: handle of the buffer - * - * Returns 0 if OK - */ -int mobicore_free_wsm(struct mc_instance *instance, uint32_t handle); - -/* - * mobicore_map_vmem() - Map a virtual memory buffer structure to Mobicore - * @instance: instance data for MobiCore Daemon and TLCs - * @addr: address of the buffer (NB it must be kernel virtual!) - * @len: buffer length (in bytes) - * @handle: unique handle - * - * Returns 0 if no error - */ -int mobicore_map_vmem(struct mc_instance *instance, void *addr, - uint32_t len, uint32_t *handle); - -/* - * mobicore_unmap_vmem() - Unmap a virtual memory buffer from MobiCore - * @instance: instance data for MobiCore Daemon and TLCs - * @handle: unique handle - * - * Returns 0 if no error - */ -int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle); - -/* - * mobicore_sleep_ready() - Test if mobicore can sleep - * - * Returns true if mobicore can sleep, false if it can't sleep - */ -bool mobicore_sleep_ready(void); - - -#endif /* _MC_KERNEL_API_H_ */ diff --git a/drivers/gud/MobiCoreDriver/public/mc_linux.h b/drivers/gud/MobiCoreDriver/public/mc_linux.h deleted file mode 100644 index d1d8e81893e8..000000000000 --- a/drivers/gud/MobiCoreDriver/public/mc_linux.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _MC_LINUX_H_ -#define _MC_LINUX_H_ - -#include "version.h" - -#ifndef __KERNEL__ -#include <stdint.h> -#endif - -#define MC_ADMIN_DEVNODE "mobicore" -#define MC_USER_DEVNODE "mobicore-user" - -/* - * Data exchange structure of the MC_DRV_MODULE_INIT ioctl command. - * INIT request data to SWD - */ -struct mc_ioctl_init { - /* length of notification queue */ - uint32_t nq_length; - /* mcp buffer start/length [16:16] [start, length] */ - uint32_t mcp_offset; - /* length of mcp buffer */ - uint32_t mcp_length; -}; - -/* - * Data exchange structure of the MC_DRV_MODULE_INFO ioctl command. - * INFO request data to the SWD - */ -struct mc_ioctl_info { - uint32_t ext_info_id; /* extended info ID */ - uint32_t state; /* state */ - uint32_t ext_info; /* extended info */ -}; - -/* - * Data exchange structure of the MC_IO_MAP_WSM and MC_IO_MAP_MCI commands. - * - * Allocate a contiguous memory buffer for a process. - * The physical address can be used as for later calls to mmap. - * The handle can be used to communicate about this buffer to the Daemon. - * For MC_IO_MAP_MCI command, the reused field indicates that MCI was set up - * already. I.e. Daemon was restarted. - */ -struct mc_ioctl_map { - uint32_t len; /* Buffer length */ - uint32_t handle; /* WSM handle */ - uint64_t phys_addr; /* physical address of WSM (or 0) */ - uint32_t rfu; - bool reused; /* if WSM memory was reused, or new allocated */ -}; - -/* - * Data exchange structure of the MC_IO_REG_WSM command. - * - * Allocates a physical MMU table and maps the buffer into this page. - * Returns the physical address of the MMU table. - * The page alignment will be created and the appropriated pSize and pOffsetMMU - * will be modified to the used values. - * - * We assume the 64 bit compatible one to be the default and the - * 32 bit one to be the compat one but we must serve both of them. - */ -struct mc_compat_ioctl_reg_wsm { - uint32_t buffer; /* base address of the virtual address */ - uint32_t len; /* size of the virtual address space */ - uint32_t pid; /* process id */ - uint32_t handle; /* driver handle for locked memory */ - uint64_t table_phys; /* physical address of the MMU table */ -}; - -struct mc_ioctl_reg_wsm { - uint64_t buffer; /* base address of the virtual address */ - uint32_t len; /* size of the virtual address space */ - uint32_t pid; /* process id */ - uint32_t handle; /* driver handle for locked memory */ - uint64_t table_phys;/* physical address of the MMU table */ -}; - -/* - * Data exchange structure of the MC_IO_RESOLVE_CONT_WSM ioctl command. - */ -struct mc_ioctl_resolv_cont_wsm { - /* driver handle for buffer */ - uint32_t handle; - /* length memory */ - uint32_t length; - /* base address of memory */ - uint64_t phys; - /* fd to owner of the buffer */ - int32_t fd; -}; - -/* - * Data exchange structure of the MC_IO_RESOLVE_WSM ioctl command. - */ -struct mc_ioctl_resolv_wsm { - /* driver handle for buffer */ - uint32_t handle; - /* fd to owner of the buffer */ - int32_t fd; - /* base address of memory */ - uint64_t phys; -}; - - -/* - * defines for the ioctl mobicore driver module function call from user space. - */ -/* MobiCore IOCTL magic number */ -#define MC_IOC_MAGIC 'M' - -#define MC_IO_INIT _IOWR(MC_IOC_MAGIC, 0, struct mc_ioctl_init) -#define MC_IO_INFO _IOWR(MC_IOC_MAGIC, 1, struct mc_ioctl_info) -#define MC_IO_VERSION _IOR(MC_IOC_MAGIC, 2, uint32_t) -/* - * ioctl parameter to send the YIELD command to the SWD. - * Only possible in Privileged Mode. - * ioctl(fd, MC_DRV_MODULE_YIELD) - */ -#define MC_IO_YIELD _IO(MC_IOC_MAGIC, 3) -/* - * ioctl parameter to send the NSIQ signal to the SWD. - * Only possible in Privileged Mode - * ioctl(fd, MC_DRV_MODULE_NSIQ) - */ -#define MC_IO_NSIQ _IO(MC_IOC_MAGIC, 4) -/* - * Free's memory which is formerly allocated by the driver's mmap - * command. The parameter must be this mmaped address. - * The internal instance data regarding to this address are deleted as - * well as each according memory page and its appropriated reserved bit - * is cleared (ClearPageReserved). - * Usage: ioctl(fd, MC_DRV_MODULE_FREE, &address) with address being of - * type long address - */ -#define MC_IO_FREE _IO(MC_IOC_MAGIC, 5) -/* - * Creates a MMU Table of the given base address and the size of the - * data. - * Parameter: mc_ioctl_reg_wsm - * - * Since the end ID is also based on the size of the structure it is - * safe to use the same ID(6) for both - */ -#define MC_IO_REG_WSM _IOWR(MC_IOC_MAGIC, 6, struct mc_ioctl_reg_wsm) -#define MC_COMPAT_REG_WSM _IOWR(MC_IOC_MAGIC, 6, \ - struct mc_compat_ioctl_reg_wsm) - -#define MC_IO_UNREG_WSM _IO(MC_IOC_MAGIC, 7) -#define MC_IO_LOCK_WSM _IO(MC_IOC_MAGIC, 8) -#define MC_IO_UNLOCK_WSM _IO(MC_IOC_MAGIC, 9) - -/* - * Allocate contiguous memory for a process for later mapping with mmap. - * MC_IO_MAP_WSM usual operation, pages are registered in - * device structure and freed later. - * MC_IO_MAP_MCI get Instance of MCI, allocates or mmaps - * the MCI to daemon - */ -#define MC_IO_MAP_WSM _IOWR(MC_IOC_MAGIC, 11, struct mc_ioctl_map) -#define MC_IO_MAP_MCI _IOWR(MC_IOC_MAGIC, 12, struct mc_ioctl_map) - -/* - * Clean orphaned WSM buffers. Only available to the daemon and should - * only be carried out if the TLC crashes or otherwise calls exit() in - * an unexpected manner. - * The clean is needed together with the lock/unlock mechanism so the daemon - * has clear control of the mapped buffers so it can close a Trustlet before - * release all the WSM buffers, otherwise the Trustlet would be able to write - * to possibly kernel memory areas - */ -#define MC_IO_CLEAN_WSM _IO(MC_IOC_MAGIC, 14) - -/* - * Get MMU phys address of a buffer handle allocated to the user. - * Only available to the daemon. - */ -#define MC_IO_RESOLVE_WSM _IOWR(MC_IOC_MAGIC, 15, \ - struct mc_ioctl_resolv_wsm) - -/* - * Get the phys address & length of a allocated contiguous buffer. - * Only available to the daemon */ -#define MC_IO_RESOLVE_CONT_WSM _IOWR(MC_IOC_MAGIC, 16, \ - struct mc_ioctl_resolv_cont_wsm) - -/* - * Setup the mem traces when called. - * Only available to the daemon */ -#define MC_IO_LOG_SETUP _IO(MC_IOC_MAGIC, 17) - -#endif /* _MC_LINUX_H_ */ diff --git a/drivers/gud/MobiCoreDriver/public/version.h b/drivers/gud/MobiCoreDriver/public/version.h deleted file mode 100644 index a4b216e1aeef..000000000000 --- a/drivers/gud/MobiCoreDriver/public/version.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _MC_DRV_VERSION_H_ -#define _MC_DRV_VERSION_H_ - -#define MCDRVMODULEAPI_VERSION_MAJOR 1 -#define MCDRVMODULEAPI_VERSION_MINOR 1 - -#endif /* _MC_DRV_VERSION_H_ */ diff --git a/drivers/gud/MobiCoreKernelApi/Makefile b/drivers/gud/MobiCoreKernelApi/Makefile deleted file mode 100644 index 1e2017101a8c..000000000000 --- a/drivers/gud/MobiCoreKernelApi/Makefile +++ /dev/null @@ -1,73 +0,0 @@ -# -# this makefile is called from the kernel make syste -ifeq ($(MODE),release) - ccflags-y += -O2 -DNDEBUG -else # DEBUG - # "-O" is needed to expand inlines - ccflags-y += -O -g3 -DDEBUG -endif # DEBUG/RELEASE - -ifdef MOBICORE_CFLAGS - ccflags-y +=$(MOBICORE_CFLAGS) -endif - -#Set the extra symbols -ifdef MCDRV_SYMBOLS_FILE - KBUILD_EXTRA_SYMBOLS=$(MCDRV_SYMBOLS_FILE) -endif - -ifeq ($(PLATFORM), ARM_VE_A9X4_QEMU) - ccflags-y += -DMC_NETLINK_COMPAT_V37 -endif - -ifeq ($(PLATFORM), MSM8974_SURF_STD) - ccflags-y += -DMC_NETLINK_COMPAT_V37 -endif - -ifeq ($(PLATFORM), EXYNOS_5422_STD) - ccflags-y += -DMC_NETLINK_COMPAT_V37 -endif - -ifeq ($(PLATFORM), EXYNOS_5430_STD) - ccflags-y += -DMC_NETLINK_COMPAT_V37 -endif - -ifeq ($(PLATFORM), EXYNOS_7410_STD) - ccflags-y += -DMC_NETLINK_COMPAT_V37 -endif - -ifeq ($(PLATFORM), EXYNOS_5433_STD) - ccflags-y += -DMC_NETLINK_COMPAT_V37 -endif - -ifeq ($(PLATFORM), LGE_ODIN_LPAE) - ccflags-y += -DMC_NETLINK_COMPAT_V37 -endif - -ifeq ($(PLATFORM), MSM8084_SURF_STD) - ccflags-y += -DMC_NETLINK_COMPAT_V37 -endif - -ifeq ($(PLATFORM), MSM8916_SURF_STD) - ccflags-y += -DMC_NETLINK_COMPAT_V37 -endif - - -#EXTRA_CFLAGS += -DDEBUG -DDEBUG_VERBOSE -#EXTRA_CFLAGS += -Wno-declaration-after-statement -ccflags-y += -Wno-declaration-after-statement -# add our module to kernel. -obj-m += mcKernelApi.o - -mcKernelApi-objs := main.o clientlib.o device.o session.o connection.o - -clean: - rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \ - Module.markers Module.symvers modules.order - -depend .depend dep: - $(CC) $(CFLAGS) -M *.c > .depend - -ifeq (.depend,$(wildcard .depend)) - include .depend -endif diff --git a/drivers/gud/MobiCoreKernelApi/build.sh b/drivers/gud/MobiCoreKernelApi/build.sh deleted file mode 100644 index 86fe1b89548c..000000000000 --- a/drivers/gud/MobiCoreKernelApi/build.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -if [ -z $COMP_PATH_ROOT ]; then - echo "The build environment is not set!" - echo "Trying to source setupDrivers.sh automatically!" - source ../setupDrivers.sh || exit 1 -fi - -ROOT_PATH=$(dirname $(readlink -f $BASH_SOURCE)) -# These folders need to be relative to the kernel dir or absolute! -PLATFORM=EXYNOS_4X12_STD -CODE_INCLUDE=$(readlink -f $ROOT_PATH/Locals/Code) - -MOBICORE_DRIVER=$COMP_PATH_MobiCoreDriverMod -MOBICORE_DAEMON=$COMP_PATH_MobiCoreDriverLib/Public -MOBICORE_CFLAGS="-I$MOBICORE_DRIVER/Public -I$MOBICORE_DAEMON -I$COMP_PATH_MobiCore/inc/Mci -I$COMP_PATH_MobiCore/inc -I$CODE_INCLUDE/include -I$CODE_INCLUDE/public" -MCDRV_SYMBOLS_FILE="$COMP_PATH_ROOT/MobiCoreDriverMod/Locals/Code/Module.symvers" - -if [ ! -f $MCDRV_SYMBOLS_FILE ]; then - echo "Please build the Mobicore Driver Module first!" - echo "Otherwise you will see warnings of missing symbols" -fi - -# Clean first -make -C $CODE_INCLUDE clean - -make -C $LINUX_PATH \ - MODE=$MODE \ - ARCH=arm \ - CROSS_COMPILE=$CROSS_COMPILE \ - M=$CODE_INCLUDE \ - "MOBICORE_CFLAGS=$MOBICORE_CFLAGS" \ - MCDRV_SYMBOLS_FILE=$MCDRV_SYMBOLS_FILE \ - modules diff --git a/drivers/gud/MobiCoreKernelApi/clientlib.c b/drivers/gud/MobiCoreKernelApi/clientlib.c deleted file mode 100644 index 57133805eeb8..000000000000 --- a/drivers/gud/MobiCoreKernelApi/clientlib.c +++ /dev/null @@ -1,1068 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include <linux/module.h> -#include <linux/init.h> - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/netlink.h> -#include <net/sock.h> -#include <net/net_namespace.h> -#include <linux/list.h> - -#include "public/mobicore_driver_api.h" -#include "public/mobicore_driver_cmd.h" -#include "include/mcinq.h" -#include "device.h" -#include "session.h" - -/* device list */ -LIST_HEAD(devices); -atomic_t device_usage = ATOMIC_INIT(0); - -static struct mcore_device_t *resolve_device_id(uint32_t device_id) -{ - struct mcore_device_t *tmp; - struct list_head *pos; - - /* Get mcore_device_t for device_id */ - list_for_each(pos, &devices) { - tmp = list_entry(pos, struct mcore_device_t, list); - if (tmp->device_id == device_id) - return tmp; - } - return NULL; -} - -static void add_device(struct mcore_device_t *device) -{ - list_add_tail(&(device->list), &devices); -} - -static bool remove_device(uint32_t device_id) -{ - struct mcore_device_t *tmp; - struct list_head *pos, *q; - - list_for_each_safe(pos, q, &devices) { - tmp = list_entry(pos, struct mcore_device_t, list); - if (tmp->device_id == device_id) { - list_del(pos); - mcore_device_cleanup(tmp); - return true; - } - } - return false; -} - -enum mc_result mc_open_device(uint32_t device_id) -{ - enum mc_result mc_result = MC_DRV_OK; - struct connection *dev_con = NULL; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - struct mcore_device_t *device = resolve_device_id(device_id); - if (device != NULL) { - MCDRV_DBG(mc_kapi, - "Device %d already opened\n", device_id); - atomic_inc(&device_usage); - mc_result = MC_DRV_OK; - break; - } - - /* Open new connection to device */ - dev_con = connection_new(); - if (dev_con == NULL) { - mc_result = MC_DRV_ERR_NO_FREE_MEMORY; - break; - } - - if (!connection_connect(dev_con, MC_DAEMON_PID)) { - MCDRV_DBG_ERROR( - mc_kapi, - "Could not setup netlink connection to PID %u", - MC_DAEMON_PID); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - /* Forward device open to the daemon and read result */ - struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device = { - { - MC_DRV_CMD_OPEN_DEVICE - }, - { - device_id - } - }; - - int len = connection_write_data( - dev_con, - &mc_drv_cmd_open_device, - sizeof(struct mc_drv_cmd_open_device_t)); - if (len < 0) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_OPEN_DEVICE writeCmd failed %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - struct mc_drv_response_header_t rsp_header; - memset(&rsp_header, 0, sizeof(rsp_header)); - len = connection_read_datablock( - dev_con, - &rsp_header, - sizeof(rsp_header)); - if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_OPEN_DEVICE readRsp failed %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_OPEN_DEVICE failed, respId=%d", - rsp_header.response_id); - switch (rsp_header.response_id) { - case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR: - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - case MC_DRV_INVALID_DEVICE_NAME: - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - case MC_DRV_RSP_DEVICE_ALREADY_OPENED: - default: - mc_result = MC_DRV_ERR_INVALID_OPERATION; - break; - } - break; - } - - /* there is no payload to read */ - - device = mcore_device_create(device_id, dev_con); - if (device == NULL) { - mc_result = MC_DRV_ERR_NO_FREE_MEMORY; - break; - } - if (!mcore_device_open(device, MC_DRV_MOD_DEVNODE_FULLPATH)) { - mcore_device_cleanup(device); - MCDRV_DBG_ERROR(mc_kapi, - "could not open device file: %s", - MC_DRV_MOD_DEVNODE_FULLPATH); - mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE; - break; - } - - add_device(device); - atomic_inc(&device_usage); - - } while (false); - - if (mc_result != MC_DRV_OK) - connection_cleanup(dev_con); - - return mc_result; -} -EXPORT_SYMBOL(mc_open_device); - -enum mc_result mc_close_device(uint32_t device_id) -{ - enum mc_result mc_result = MC_DRV_OK; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - struct mcore_device_t *device = resolve_device_id(device_id); - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - /* Check if it's not used by other modules */ - if (!atomic_dec_and_test(&device_usage)) { - mc_result = MC_DRV_OK; - break; - } - - struct connection *dev_con = device->connection; - - /* Return if not all sessions have been closed */ - if (mcore_device_has_sessions(device)) { - MCDRV_DBG_ERROR(mc_kapi, - "cannot close with sessions pending"); - mc_result = MC_DRV_ERR_SESSION_PENDING; - break; - } - - struct mc_drv_cmd_close_device_t mc_drv_cmd_close_device = { - { - MC_DRV_CMD_CLOSE_DEVICE - } - }; - int len = connection_write_data( - dev_con, - &mc_drv_cmd_close_device, - sizeof(struct mc_drv_cmd_close_device_t)); - /* ignore error, but log details */ - if (len < 0) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_CLOSE_DEVICE writeCmd failed %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - } - - struct mc_drv_response_header_t rsp_header; - memset(&rsp_header, 0, sizeof(rsp_header)); - len = connection_read_datablock( - dev_con, - &rsp_header, - sizeof(rsp_header)); - if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_CLOSE_DEVICE readResp failed %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_CLOSE_DEVICE failed, respId=%d", - rsp_header.response_id); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - remove_device(device_id); - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_close_device); - -enum mc_result mc_open_session(struct mc_session_handle *session, - const struct mc_uuid_t *uuid, - uint8_t *tci, uint32_t tci_len) -{ - enum mc_result mc_result = MC_DRV_OK; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - if (session == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Session is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - if (uuid == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "UUID is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - if (tci == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "TCI is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - if (tci_len > MC_MAX_TCI_LEN) { - MCDRV_DBG_ERROR(mc_kapi, "TCI length is longer than %d", - MC_MAX_TCI_LEN); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - /* Get the device associated with the given session */ - struct mcore_device_t *device = - resolve_device_id(session->device_id); - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - struct connection *dev_con = device->connection; - - /* Get the wsm of the given TCI */ - struct wsm *wsm = - mcore_device_find_contiguous_wsm(device, tci); - if (wsm == NULL) { - MCDRV_DBG_ERROR(mc_kapi, - "Could not resolve TCI address "); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - if (wsm->len < tci_len) { - MCDRV_DBG_ERROR(mc_kapi, - "length is more than allocated TCI"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - /* Prepare open session command */ - struct mc_drv_cmd_open_session_t cmd_open_session = { - { - MC_DRV_CMD_OPEN_SESSION - }, - { - session->device_id, - *uuid, - (uint32_t)((uintptr_t)(wsm->virt_addr) & 0xFFF), - wsm->handle, - tci_len - } - }; - - /* Transmit command data */ - int len = connection_write_data(dev_con, - &cmd_open_session, - sizeof(cmd_open_session)); - if (len != sizeof(cmd_open_session)) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_OPEN_SESSION writeData failed %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - /* Read command response */ - - /* read header first */ - struct mc_drv_response_header_t rsp_header; - memset(&rsp_header, 0, sizeof(rsp_header)); - len = connection_read_datablock(dev_con, - &rsp_header, - sizeof(rsp_header)); - if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_OPEN_SESSION readResp failed %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_OPEN_SESSION failed, respId=%d", - rsp_header.response_id); - switch (rsp_header.response_id) { - case MC_DRV_RSP_TRUSTLET_NOT_FOUND: - mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE; - break; - case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR: - case MC_DRV_RSP_DEVICE_NOT_OPENED: - case MC_DRV_RSP_FAILED: - default: - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - break; - } - - /* read payload */ - struct mc_drv_rsp_open_session_payload_t - rsp_open_session_payload; - memset(&rsp_open_session_payload, 0, - sizeof(rsp_open_session_payload)); - len = connection_read_datablock( - dev_con, - &rsp_open_session_payload, - sizeof(rsp_open_session_payload)); - if (len != sizeof(rsp_open_session_payload)) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_OPEN_SESSION readPayload fail %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - /* Register session with handle */ - session->session_id = rsp_open_session_payload.session_id; - - /* Set up second channel for notifications */ - struct connection *session_connection = connection_new(); - if (session_connection == NULL) { - mc_result = MC_DRV_ERR_NO_FREE_MEMORY; - break; - } - - if (!connection_connect(session_connection, MC_DAEMON_PID)) { - MCDRV_DBG_ERROR( - mc_kapi, - "Could not setup netlink connection to PID %u", - MC_DAEMON_PID); - connection_cleanup(session_connection); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - /* Write command to use channel for notifications */ - struct mc_drv_cmd_nqconnect_t cmd_nqconnect = { - { - MC_DRV_CMD_NQ_CONNECT - }, - { - session->device_id, - session->session_id, - rsp_open_session_payload.device_session_id, - rsp_open_session_payload.session_magic - } - }; - connection_write_data(session_connection, - &cmd_nqconnect, - sizeof(cmd_nqconnect)); - - /* Read command response, header first */ - len = connection_read_datablock(session_connection, - &rsp_header, - sizeof(rsp_header)); - if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_NQ_CONNECT readRsp failed %d", - len); - connection_cleanup(session_connection); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_NQ_CONNECT failed, respId=%d", - rsp_header.response_id); - connection_cleanup(session_connection); - mc_result = MC_DRV_ERR_NQ_FAILED; - break; - } - - /* there is no payload. */ - - /* Session established, new session object must be created */ - if (!mcore_device_create_new_session(device, - session->session_id, - session_connection)) { - connection_cleanup(session_connection); - mc_result = MC_DRV_ERR_NO_FREE_MEMORY; - break; - } - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_open_session); - -enum mc_result mc_close_session(struct mc_session_handle *session) -{ - enum mc_result mc_result = MC_DRV_OK; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - if (session == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Session is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - struct mcore_device_t *device = - resolve_device_id(session->device_id); - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - struct connection *dev_con = device->connection; - - struct session *nq_session = - mcore_device_resolve_session_id(device, - session->session_id); - - if (nq_session == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Session not found"); - mc_result = MC_DRV_ERR_UNKNOWN_SESSION; - break; - } - - /* Write close session command */ - struct mc_drv_cmd_close_session_t cmd_close_session = { - { - MC_DRV_CMD_CLOSE_SESSION - }, - { - session->session_id, - } - }; - connection_write_data(dev_con, - &cmd_close_session, - sizeof(cmd_close_session)); - - /* Read command response */ - struct mc_drv_response_header_t rsp_header; - memset(&rsp_header, 0, sizeof(rsp_header)); - int len = connection_read_datablock(dev_con, - &rsp_header, - sizeof(rsp_header)); - if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_CLOSE_SESSION readRsp failed %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_CLOSE_SESSION failed, respId=%d", - rsp_header.response_id); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - - mcore_device_remove_session(device, session->session_id); - mc_result = MC_DRV_OK; - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_close_session); - -enum mc_result mc_notify(struct mc_session_handle *session) -{ - enum mc_result mc_result = MC_DRV_OK; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - if (session == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Session is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - struct mcore_device_t *device = - resolve_device_id(session->device_id); - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - struct connection *dev_con = device->connection; - - struct session *nqsession = - mcore_device_resolve_session_id(device, session->session_id); - if (nqsession == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Session not found"); - mc_result = MC_DRV_ERR_UNKNOWN_SESSION; - break; - } - - struct mc_drv_cmd_notify_t cmd_notify = { - { - MC_DRV_CMD_NOTIFY - }, - { - session->session_id - } - }; - - connection_write_data(dev_con, - &cmd_notify, - sizeof(cmd_notify)); - - /* Daemon will not return a response */ - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_notify); - -enum mc_result mc_wait_notification(struct mc_session_handle *session, - int32_t timeout) -{ - enum mc_result mc_result = MC_DRV_OK; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - if (session == NULL) { - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - struct mcore_device_t *device = - resolve_device_id(session->device_id); - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - - struct session *nq_session = - mcore_device_resolve_session_id(device, - session->session_id); - if (nq_session == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Session not found"); - mc_result = MC_DRV_ERR_UNKNOWN_SESSION; - break; - } - - struct connection *nqconnection = - nq_session->notification_connection; - uint32_t count = 0; - - /* Read notification queue till it's empty */ - for (;;) { - struct notification notification; - memset(¬ification, 0, sizeof(notification)); - ssize_t num_read = - connection_read_data(nqconnection, - ¬ification, - sizeof(notification), - timeout); - /* - * Exit on timeout in first run. Later runs have - * timeout set to 0. - * -2 means, there is no more data. - */ - if (count == 0 && num_read == -2) { - MCDRV_DBG_ERROR(mc_kapi, "read timeout"); - mc_result = MC_DRV_ERR_TIMEOUT; - break; - } - /* - * After first notification the queue will be - * drained, Thus we set no timeout for the - * following reads - */ - timeout = 0; - - if (num_read != sizeof(struct notification)) { - if (count == 0) { - /* failure in first read, notify it */ - mc_result = MC_DRV_ERR_NOTIFICATION; - MCDRV_DBG_ERROR( - mc_kapi, - "read notification failed, " - "%i bytes received", (int)num_read); - break; - } else { - /* - * Read of the n-th notification - * failed/timeout. We don't tell the - * caller, as we got valid notifications - * before. - */ - mc_result = MC_DRV_OK; - break; - } - } - - count++; - MCDRV_DBG_VERBOSE(mc_kapi, - "count=%d, SessionID=%d, Payload=%d", - count, - notification.session_id, - notification.payload); - - if (notification.payload != 0) { - /* Session end point died -> store exit code */ - session_set_error_info(nq_session, - notification.payload); - - mc_result = MC_DRV_INFO_NOTIFICATION; - break; - } - } /* for(;;) */ - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_wait_notification); - -enum mc_result mc_malloc_wsm(uint32_t device_id, uint32_t align, uint32_t len, - uint8_t **wsm, uint32_t wsm_flags) -{ - enum mc_result mc_result = MC_DRV_ERR_UNKNOWN; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - struct mcore_device_t *device = resolve_device_id(device_id); - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - if (wsm == NULL) { - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - struct wsm *wsm_stack = - mcore_device_allocate_contiguous_wsm(device, len); - if (wsm_stack == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Allocation of WSM failed"); - mc_result = MC_DRV_ERR_NO_FREE_MEMORY; - break; - } - - *wsm = (uint8_t *)wsm_stack->virt_addr; - mc_result = MC_DRV_OK; - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_malloc_wsm); - -enum mc_result mc_free_wsm(uint32_t device_id, uint8_t *wsm) -{ - enum mc_result mc_result = MC_DRV_ERR_UNKNOWN; - struct mcore_device_t *device; - - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - /* Get the device associated wit the given session */ - device = resolve_device_id(device_id); - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - - /* find WSM object */ - struct wsm *wsm_stack = - mcore_device_find_contiguous_wsm(device, wsm); - if (wsm_stack == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "unknown address"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - /* Free the given virtual address */ - if (!mcore_device_free_contiguous_wsm(device, wsm_stack)) { - MCDRV_DBG_ERROR(mc_kapi, - "Free of virtual address failed"); - mc_result = MC_DRV_ERR_FREE_MEMORY_FAILED; - break; - } - mc_result = MC_DRV_OK; - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_free_wsm); - -enum mc_result mc_map(struct mc_session_handle *session_handle, void *buf, - uint32_t buf_len, struct mc_bulk_map *map_info) -{ - enum mc_result mc_result = MC_DRV_ERR_UNKNOWN; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - if (session_handle == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "session_handle is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - if (map_info == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "map_info is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - if (buf == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "buf is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - /* Determine device the session belongs to */ - struct mcore_device_t *device = - resolve_device_id(session_handle->device_id); - - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - struct connection *dev_con = device->connection; - - /* Get session */ - uint32_t session_id = session_handle->session_id; - struct session *session = - mcore_device_resolve_session_id(device, - session_id); - if (session == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Session not found"); - mc_result = MC_DRV_ERR_UNKNOWN_SESSION; - break; - } - - /* - * Register mapped bulk buffer to Kernel Module and keep mapped - * bulk buffer in mind - */ - struct bulk_buffer_descriptor *bulk_buf = - session_add_bulk_buf(session, buf, buf_len); - if (bulk_buf == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Error mapping bulk buffer"); - mc_result = MC_DRV_ERR_BULK_MAPPING; - break; - } - - /* Prepare map command */ - uintptr_t offset = (uintptr_t)(bulk_buf->virt_addr) & 0xFFF; - struct mc_drv_cmd_map_bulk_mem_t mc_drv_cmd_map_bulk_mem = { - { - MC_DRV_CMD_MAP_BULK_BUF - }, - { - session->session_id, - bulk_buf->handle, - 0, - (uint32_t)offset, - bulk_buf->len - } - }; - - /* Transmit map command to MobiCore device */ - connection_write_data(dev_con, - &mc_drv_cmd_map_bulk_mem, - sizeof(mc_drv_cmd_map_bulk_mem)); - - /* Read command response */ - struct mc_drv_response_header_t rsp_header; - memset(&rsp_header, 0, sizeof(rsp_header)); - int len = connection_read_datablock(dev_con, - &rsp_header, - sizeof(rsp_header)); - if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_MAP_BULK_BUF readRsp failed %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_MAP_BULK_BUF failed, respId=%d", - rsp_header.response_id); - - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - - /* - * Unregister mapped bulk buffer from Kernel Module and - * remove mapped bulk buffer from session maintenance - */ - if (!session_remove_bulk_buf(session, buf)) { - /* Removing of bulk buffer not possible */ - MCDRV_DBG_ERROR(mc_kapi, - "Unreg of bulk memory failed"); - } - break; - } - - struct mc_drv_rsp_map_bulk_mem_payload_t - rsp_map_bulk_mem_payload; - memset(&rsp_map_bulk_mem_payload, 0, - sizeof(rsp_map_bulk_mem_payload)); - connection_read_datablock(dev_con, - &rsp_map_bulk_mem_payload, - sizeof(rsp_map_bulk_mem_payload)); - - /* Set mapping info for Trustlet */ - map_info->secure_virt_addr = - rsp_map_bulk_mem_payload.secure_virtual_adr; - map_info->secure_virt_len = buf_len; - mc_result = MC_DRV_OK; - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_map); - -enum mc_result mc_unmap(struct mc_session_handle *session_handle, void *buf, - struct mc_bulk_map *map_info) -{ - enum mc_result mc_result = MC_DRV_ERR_UNKNOWN; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - if (session_handle == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "session_handle is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - if (map_info == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "map_info is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - if (buf == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "buf is null"); - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - /* Determine device the session belongs to */ - struct mcore_device_t *device = - resolve_device_id(session_handle->device_id); - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - struct connection *dev_con = device->connection; - - /* Get session */ - uint32_t session_id = session_handle->session_id; - struct session *session = - mcore_device_resolve_session_id(device, - session_id); - if (session == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Session not found"); - mc_result = MC_DRV_ERR_UNKNOWN_SESSION; - break; - } - - uint32_t handle = session_find_bulk_buf(session, buf); - if (handle == 0) { - MCDRV_DBG_ERROR(mc_kapi, "Buffer not found"); - mc_result = MC_DRV_ERR_BULK_UNMAPPING; - break; - } - - - /* Prepare unmap command */ - struct mc_drv_cmd_unmap_bulk_mem_t cmd_unmap_bulk_mem = { - { - MC_DRV_CMD_UNMAP_BULK_BUF - }, - { - session->session_id, - handle, - map_info->secure_virt_addr, - map_info->secure_virt_len - } - }; - - connection_write_data(dev_con, - &cmd_unmap_bulk_mem, - sizeof(cmd_unmap_bulk_mem)); - - /* Read command response */ - struct mc_drv_response_header_t rsp_header; - memset(&rsp_header, 0, sizeof(rsp_header)); - int len = connection_read_datablock(dev_con, - &rsp_header, - sizeof(rsp_header)); - if (len != sizeof(rsp_header)) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_UNMAP_BULK_BUF readRsp failed %d", - len); - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - if (rsp_header.response_id != MC_DRV_RSP_OK) { - MCDRV_DBG_ERROR(mc_kapi, - "CMD_UNMAP_BULK_BUF failed, respId=%d", - rsp_header.response_id); - - mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE; - break; - } - - /*struct mc_drv_rsp_unmap_bulk_mem_payload_t - rsp_unmap_bulk_mem_payload; - connection_read_datablock(dev_con, - &rsp_unmap_bulk_mem_payload, - sizeof(rsp_unmap_bulk_mem_payload));*/ - - /* - * Unregister mapped bulk buffer from Kernel Module and - * remove mapped bulk buffer from session maintenance - */ - if (!session_remove_bulk_buf(session, buf)) { - /* Removing of bulk buffer not possible */ - MCDRV_DBG_ERROR(mc_kapi, - "Unregistering of bulk memory failed"); - mc_result = MC_DRV_ERR_BULK_UNMAPPING; - break; - } - - mc_result = MC_DRV_OK; - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_unmap); - -enum mc_result mc_get_session_error_code(struct mc_session_handle *session, - int32_t *last_error) -{ - enum mc_result mc_result = MC_DRV_OK; - - MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__); - - do { - if (session == NULL || last_error == NULL) { - mc_result = MC_DRV_ERR_INVALID_PARAMETER; - break; - } - - /* Get device */ - struct mcore_device_t *device = - resolve_device_id(session->device_id); - if (device == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Device not found"); - mc_result = MC_DRV_ERR_UNKNOWN_DEVICE; - break; - } - - /* Get session */ - uint32_t session_id = session->session_id; - struct session *nqsession = - mcore_device_resolve_session_id(device, - session_id); - if (nqsession == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Session not found"); - mc_result = MC_DRV_ERR_UNKNOWN_SESSION; - break; - } - - *last_error = session_get_last_err(nqsession); - - } while (false); - - return mc_result; -} -EXPORT_SYMBOL(mc_get_session_error_code); - diff --git a/drivers/gud/MobiCoreKernelApi/common.h b/drivers/gud/MobiCoreKernelApi/common.h deleted file mode 100644 index b6c404b8b235..000000000000 --- a/drivers/gud/MobiCoreKernelApi/common.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * Common data types for use by the MobiCore Kernel API Driver - */ -#ifndef _MC_KAPI_COMMON_H -#define _MC_KAPI_COMMON_H - -#include "connection.h" -#include "mcinq.h" - -void mcapi_insert_connection(struct connection *connection); -void mcapi_remove_connection(uint32_t seq); -unsigned int mcapi_unique_id(void); - -#define MC_DAEMON_PID 0xFFFFFFFF -#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/mobicore" - -/* dummy function helper macro */ -#define DUMMY_FUNCTION() do {} while (0) - -/* Found in main.c */ -extern struct device *mc_kapi; - -#define MCDRV_ERROR(dev, txt, ...) \ - dev_err(dev, "%s() ### ERROR: " txt, __func__, ##__VA_ARGS__) - -#if defined(DEBUG) - -/* #define DEBUG_VERBOSE */ -#if defined(DEBUG_VERBOSE) -#define MCDRV_DBG_VERBOSE MCDRV_DBG -#else -#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() -#endif - -#define MCDRV_DBG(dev, txt, ...) \ - dev_info(dev, "%s(): " txt, __func__, ##__VA_ARGS__) - -#define MCDRV_DBG_WARN(dev, txt, ...) \ - dev_warn(dev, "%s() WARNING: " txt, __func__, ##__VA_ARGS__) - -#define MCDRV_DBG_ERROR(dev, txt, ...) \ - dev_err(dev, "%s() ### ERROR: " txt, __func__, ##__VA_ARGS__) - -#define MCDRV_ASSERT(cond) \ - do { \ - if (unlikely(!(cond))) { \ - panic("mc_kernelapi Assertion failed: %s:%d\n", \ - __FILE__, __LINE__); \ - } \ - } while (0) - -#elif defined(NDEBUG) - -#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION() -#define MCDRV_DBG(...) DUMMY_FUNCTION() -#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION() -#define MCDRV_DBG_ERROR(...) DUMMY_FUNCTION() - -#define MCDRV_ASSERT(...) DUMMY_FUNCTION() - -#else -#error "Define DEBUG or NDEBUG" -#endif /* [not] defined(DEBUG_MCMODULE) */ - -#define assert(expr) MCDRV_ASSERT(expr) - -#endif /* _MC_KAPI_COMMON_H */ diff --git a/drivers/gud/MobiCoreKernelApi/connection.c b/drivers/gud/MobiCoreKernelApi/connection.c deleted file mode 100644 index 99e835ff0e9c..000000000000 --- a/drivers/gud/MobiCoreKernelApi/connection.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/netlink.h> -#include <linux/skbuff.h> -#include <linux/netlink.h> -#include <linux/semaphore.h> -#include <linux/time.h> -#include <net/sock.h> -#include <net/net_namespace.h> - -#include "connection.h" -#include "common.h" - -/* Define the initial state of the Data Available Semaphore */ -#define SEM_NO_DATA_AVAILABLE 0 - -struct connection *connection_new(void) -{ - struct connection *conn; - - conn = kzalloc(sizeof(*conn), GFP_KERNEL); - if (conn == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Allocation failure"); - return NULL; - } - conn->sequence_magic = mcapi_unique_id(); - mutex_init(&conn->data_lock); - sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE); - - mcapi_insert_connection(conn); - return conn; -} - -void connection_cleanup(struct connection *conn) -{ - if (!conn) - return; - - kfree_skb(conn->skb); - - mcapi_remove_connection(conn->sequence_magic); - kfree(conn); -} - -bool connection_connect(struct connection *conn, pid_t dest) -{ - /* Nothing to connect */ - conn->peer_pid = dest; - return true; -} - -size_t connection_read_data_msg(struct connection *conn, void *buffer, - uint32_t len) -{ - size_t ret = -1; - MCDRV_DBG_VERBOSE(mc_kapi, - "reading connection data %u, connection data left %u", - len, conn->data_len); - /* trying to read more than the left data */ - if (len > conn->data_len) { - ret = conn->data_len; - memcpy(buffer, conn->data_start, conn->data_len); - conn->data_len = 0; - } else { - ret = len; - memcpy(buffer, conn->data_start, len); - conn->data_len -= len; - conn->data_start += len; - } - - if (conn->data_len == 0) { - conn->data_start = NULL; - kfree_skb(conn->skb); - conn->skb = NULL; - } - MCDRV_DBG_VERBOSE(mc_kapi, "read %zu", ret); - return ret; -} - -size_t connection_read_datablock(struct connection *conn, void *buffer, - uint32_t len) -{ - return connection_read_data(conn, buffer, len, -1); -} - -size_t connection_read_data(struct connection *conn, void *buffer, uint32_t len, - int32_t timeout) -{ - size_t ret = 0; - - MCDRV_ASSERT(buffer != NULL); - MCDRV_ASSERT(conn->socket_descriptor != NULL); - - MCDRV_DBG_VERBOSE(mc_kapi, "read data len = %u for PID = %u", - len, conn->sequence_magic); - do { - /* - * Wait until data is available or timeout - * msecs_to_jiffies(-1) -> wait forever for the sem - */ - if (down_timeout(&(conn->data_available_sem), - msecs_to_jiffies(timeout))) { - MCDRV_DBG_VERBOSE(mc_kapi, - "Timeout reading the data sem"); - ret = -2; - break; - } - - if (mutex_lock_interruptible(&(conn->data_lock))) { - MCDRV_DBG_ERROR(mc_kapi, - "interrupted reading the data sem"); - ret = -1; - break; - } - - /* Have data, use it */ - if (conn->data_len > 0) - ret = connection_read_data_msg(conn, buffer, len); - - mutex_unlock(&(conn->data_lock)); - - /* There is still some data left */ - if (conn->data_len > 0) - up(&conn->data_available_sem); - - } while (0); - - return ret; -} - -size_t connection_write_data(struct connection *conn, void *buffer, - uint32_t len) -{ - struct sk_buff *skb = NULL; - struct nlmsghdr *nlh; - int ret = 0; - - MCDRV_DBG_VERBOSE(mc_kapi, "buffer length %u from pid %u\n", - len, conn->sequence_magic); - do { - skb = nlmsg_new(NLMSG_SPACE(len), GFP_KERNEL); - if (!skb) { - ret = -1; - break; - } - - nlh = nlmsg_put(skb, 0, conn->sequence_magic, 2, - NLMSG_LENGTH(len), NLM_F_REQUEST); - if (!nlh) { - ret = -1; - kfree_skb(skb); - break; - } - memcpy(NLMSG_DATA(nlh), buffer, len); - - /* netlink_unicast frees skb */ - netlink_unicast(conn->socket_descriptor, skb, - conn->peer_pid, MSG_DONTWAIT); - ret = len; - } while (0); - - return ret; -} - -int connection_process(struct connection *conn, struct sk_buff *skb) -{ - int ret = 0; - do { - if (mutex_lock_interruptible(&(conn->data_lock))) { - MCDRV_DBG_ERROR(mc_kapi, - "Interrupted getting data semaphore!"); - ret = -1; - break; - } - - kfree_skb(conn->skb); - - /* Get a reference to the incoming skb */ - conn->skb = skb_get(skb); - if (conn->skb) { - conn->data_msg = nlmsg_hdr(conn->skb); - conn->data_len = NLMSG_PAYLOAD(conn->data_msg, 0); - conn->data_start = NLMSG_DATA(conn->data_msg); - up(&(conn->data_available_sem)); - } - mutex_unlock(&(conn->data_lock)); - ret = 0; - } while (0); - return ret; -} diff --git a/drivers/gud/MobiCoreKernelApi/connection.h b/drivers/gud/MobiCoreKernelApi/connection.h deleted file mode 100644 index 1b7436635810..000000000000 --- a/drivers/gud/MobiCoreKernelApi/connection.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_KAPI_CONNECTION_H_ -#define _MC_KAPI_CONNECTION_H_ - -#include <linux/semaphore.h> -#include <linux/mutex.h> - -#include <stddef.h> -#include <stdbool.h> - -struct connection { - /* Netlink socket */ - struct sock *socket_descriptor; - /* Random? magic to match requests/answers */ - uint32_t sequence_magic; - - struct nlmsghdr *data_msg; - /* How much connection data is left */ - uint32_t data_len; - /* Start pointer of remaining data */ - void *data_start; - struct sk_buff *skb; - - /* Data protection lock */ - struct mutex data_lock; - /* Data protection semaphore */ - struct semaphore data_available_sem; - - /* PID address used for local connection */ - pid_t self_pid; - /* Remote PID for connection */ - pid_t peer_pid; - - /* The list param for using the kernel lists */ - struct list_head list; -}; - -struct connection *connection_new(void); -void connection_cleanup(struct connection *conn); -bool connection_connect(struct connection *conn, pid_t dest); -size_t connection_read_datablock(struct connection *conn, void *buffer, - uint32_t len); -size_t connection_read_data(struct connection *conn, void *buffer, - uint32_t len, int32_t timeout); -size_t connection_write_data(struct connection *conn, void *buffer, - uint32_t len); -int connection_process(struct connection *conn, struct sk_buff *skb); - -#endif /* _MC_KAPI_CONNECTION_H_ */ diff --git a/drivers/gud/MobiCoreKernelApi/device.c b/drivers/gud/MobiCoreKernelApi/device.c deleted file mode 100644 index e3d54e68c484..000000000000 --- a/drivers/gud/MobiCoreKernelApi/device.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * MobiCore client library device management. - * - * Device and Trustlet Session management Functions. - */ -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/device.h> -#include "mc_kernel_api.h" -#include "public/mobicore_driver_api.h" - -#include "device.h" -#include "common.h" - -static struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle) -{ - struct wsm *wsm; - - wsm = kzalloc(sizeof(*wsm), GFP_KERNEL); - if (wsm == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Allocation failure"); - return NULL; - } - wsm->virt_addr = virt_addr; - wsm->len = len; - wsm->handle = handle; - return wsm; -} - -struct mcore_device_t *mcore_device_create(uint32_t device_id, - struct connection *connection) -{ - struct mcore_device_t *dev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Allocation failure"); - return NULL; - } - dev->device_id = device_id; - dev->connection = connection; - - INIT_LIST_HEAD(&dev->session_vector); - INIT_LIST_HEAD(&dev->wsm_mmu_vector); - - return dev; -} - -void mcore_device_cleanup(struct mcore_device_t *dev) -{ - struct session *tmp; - struct wsm *wsm; - struct list_head *pos, *q; - - /* - * Delete all session objects. Usually this should not be needed - * as close_device() requires that all sessions have been closed before. - */ - list_for_each_safe(pos, q, &dev->session_vector) { - tmp = list_entry(pos, struct session, list); - list_del(pos); - session_cleanup(tmp); - } - - /* Free all allocated WSM descriptors */ - list_for_each_safe(pos, q, &dev->wsm_mmu_vector) { - wsm = list_entry(pos, struct wsm, list); - list_del(pos); - kfree(wsm); - } - connection_cleanup(dev->connection); - - mcore_device_close(dev); - kfree(dev); -} - -bool mcore_device_open(struct mcore_device_t *dev, const char *device_name) -{ - dev->instance = mobicore_open(); - return (dev->instance != NULL); -} - -void mcore_device_close(struct mcore_device_t *dev) -{ - mobicore_release(dev->instance); -} - -bool mcore_device_has_sessions(struct mcore_device_t *dev) -{ - return !list_empty(&dev->session_vector); -} - -bool mcore_device_create_new_session(struct mcore_device_t *dev, - uint32_t session_id, - struct connection *connection) -{ - /* Check if session_id already exists */ - if (mcore_device_resolve_session_id(dev, session_id)) { - MCDRV_DBG_ERROR(mc_kapi, - " session %u already exists", session_id); - return false; - } - struct session *session = - session_create(session_id, dev->instance, connection); - if (session == NULL) - return false; - list_add_tail(&(session->list), &(dev->session_vector)); - return true; -} - -bool mcore_device_remove_session(struct mcore_device_t *dev, - uint32_t session_id) -{ - bool ret = false; - struct session *tmp; - struct list_head *pos, *q; - - list_for_each_safe(pos, q, &dev->session_vector) { - tmp = list_entry(pos, struct session, list); - if (tmp->session_id == session_id) { - list_del(pos); - session_cleanup(tmp); - ret = true; - break; - } - } - return ret; -} - -struct session *mcore_device_resolve_session_id(struct mcore_device_t *dev, - uint32_t session_id) -{ - struct session *ret = NULL; - struct session *tmp; - struct list_head *pos; - - /* Get session for session_id */ - list_for_each(pos, &dev->session_vector) { - tmp = list_entry(pos, struct session, list); - if (tmp->session_id == session_id) { - ret = tmp; - break; - } - } - return ret; -} - -struct wsm *mcore_device_allocate_contiguous_wsm(struct mcore_device_t *dev, - uint32_t len) -{ - struct wsm *wsm = NULL; - do { - if (len == 0) - break; - - /* Allocate shared memory */ - void *virt_addr; - uint32_t handle; - int ret = mobicore_allocate_wsm(dev->instance, len, &handle, - &virt_addr); - if (ret != 0) - break; - - /* Register (vaddr) with device */ - wsm = wsm_create(virt_addr, len, handle); - if (wsm == NULL) { - mobicore_free_wsm(dev->instance, handle); - break; - } - - list_add_tail(&(wsm->list), &(dev->wsm_mmu_vector)); - - } while (0); - - return wsm; -} - -bool mcore_device_free_contiguous_wsm(struct mcore_device_t *dev, - struct wsm *wsm) -{ - bool ret = false; - struct wsm *tmp; - struct list_head *pos; - - list_for_each(pos, &dev->wsm_mmu_vector) { - tmp = list_entry(pos, struct wsm, list); - if (tmp == wsm) { - ret = true; - break; - } - } - - if (ret) { - MCDRV_DBG_VERBOSE(mc_kapi, - "freeWsm virt_addr=0x%p, handle=%d", - wsm->virt_addr, wsm->handle); - - /* ignore return code */ - mobicore_free_wsm(dev->instance, wsm->handle); - - list_del(pos); - kfree(wsm); - } - return ret; -} - -struct wsm *mcore_device_find_contiguous_wsm(struct mcore_device_t *dev, - void *virt_addr) -{ - struct wsm *wsm; - struct list_head *pos; - - list_for_each(pos, &dev->wsm_mmu_vector) { - wsm = list_entry(pos, struct wsm, list); - if (virt_addr == wsm->virt_addr) - return wsm; - } - - return NULL; -} diff --git a/drivers/gud/MobiCoreKernelApi/device.h b/drivers/gud/MobiCoreKernelApi/device.h deleted file mode 100644 index e73042848e63..000000000000 --- a/drivers/gud/MobiCoreKernelApi/device.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * MobiCore client library device management. - * - * Device and Trustlet Session management Functions. - */ -#ifndef _MC_KAPI_DEVICE_H_ -#define _MC_KAPI_DEVICE_H_ - -#include <linux/list.h> - -#include "connection.h" -#include "session.h" -#include "wsm.h" - -struct mcore_device_t { - /* MobiCore Trustlet session associated with the device */ - struct list_head session_vector; - struct list_head wsm_mmu_vector; /* WSM L2 or L3 Table */ - - uint32_t device_id; /* Device identifier */ - struct connection *connection; /* The device connection */ - struct mc_instance *instance; /* MobiCore Driver instance */ - - /* The list param for using the kernel lists */ - struct list_head list; -}; - -struct mcore_device_t *mcore_device_create( - uint32_t device_id, struct connection *connection); -void mcore_device_cleanup(struct mcore_device_t *dev); - - -bool mcore_device_open(struct mcore_device_t *dev, const char *device_name); -void mcore_device_close(struct mcore_device_t *dev); -bool mcore_device_has_sessions(struct mcore_device_t *dev); -bool mcore_device_create_new_session( - struct mcore_device_t *dev, uint32_t session_id, - struct connection *connection); -bool mcore_device_remove_session( - struct mcore_device_t *dev, uint32_t session_id); -struct session *mcore_device_resolve_session_id( - struct mcore_device_t *dev, uint32_t session_id); -struct wsm *mcore_device_allocate_contiguous_wsm( - struct mcore_device_t *dev, uint32_t len); -bool mcore_device_free_contiguous_wsm( - struct mcore_device_t *dev, struct wsm *wsm); -struct wsm *mcore_device_find_contiguous_wsm( - struct mcore_device_t *dev, void *virt_addr); - -#endif /* _MC_KAPI_DEVICE_H_ */ diff --git a/drivers/gud/MobiCoreKernelApi/include/mcinq.h b/drivers/gud/MobiCoreKernelApi/include/mcinq.h deleted file mode 100644 index 30444993b640..000000000000 --- a/drivers/gud/MobiCoreKernelApi/include/mcinq.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * Notifications inform the MobiCore runtime environment that information is - * pending in a WSM buffer. - * - * The Trustlet Connector (TLC) and the corresponding Trustlet also utilize - * this buffer to notify each other about new data within the - * Trustlet Connector Interface (TCI). - * - * The buffer is set up as a queue, which means that more than one - * notification can be written to the buffer before the switch to the other - * world is performed. Each side therefore facilitates an incoming and an - * outgoing queue for communication with the other side. - * - * Notifications hold the session ID, which is used to reference the - * communication partner in the other world. - * So if, e.g., the TLC in the normal world wants to notify his Trustlet - * about new data in the TLC buffer - * - * Notification queue declarations. - */ -#ifndef _MCINQ_H_ -#define _MCINQ_H_ - -/* Minimum and maximum count of elements in the notification queue */ -#define MIN_NQ_ELEM 1 /* Minimum notification queue elements. */ -#define MAX_NQ_ELEM 64 /* Maximum notification queue elements. */ - -/* Minimum notification length (in bytes). */ -#define MIN_NQ_LEN (MIN_NQ_ELEM * sizeof(notification)) - -/* Maximum notification length (in bytes). */ -#define MAX_NQ_LEN (MAX_NQ_ELEM * sizeof(notification)) - -/* - * MCP session ID is used when directly communicating with the MobiCore - * (e.g. for starting and stopping of Trustlets). - */ -#define SID_MCP 0 -/* Invalid session id is returned in case of an error. */ -#define SID_INVALID 0xffffffff - -/* Notification data structure. */ -struct notification { - uint32_t session_id; /* Session ID. */ - int32_t payload; /* Additional notification info */ -}; - -/* - * Notification payload codes. - * 0 indicated a plain simple notification, - * a positive value is a termination reason from the task, - * a negative value is a termination reason from MobiCore. - * Possible negative values are given below. - */ -enum notification_payload { - /* task terminated, but exit code is invalid */ - ERR_INVALID_EXIT_CODE = -1, - /* task terminated due to session end, no exit code available */ - ERR_SESSION_CLOSE = -2, - /* task terminated due to invalid operation */ - ERR_INVALID_OPERATION = -3, - /* session ID is unknown */ - ERR_INVALID_SID = -4, - /* session is not active */ - ERR_SID_NOT_ACTIVE = -5 -}; - -/* - * Declaration of the notification queue header. - * Layout as specified in the data structure specification. - */ -struct notification_queue_header { - uint32_t write_cnt; /* Write counter. */ - uint32_t read_cnt; /* Read counter. */ - uint32_t queue_size; /* Queue size. */ -}; - -/* - * Queue struct which defines a queue object. - * The queue struct is accessed by the queue<operation> type of - * function. elementCnt must be a power of two and the power needs - * to be smaller than power of uint32_t (obviously 32). - */ -struct notification_queue { - /* Queue header. */ - struct notification_queue_header hdr; - /* Notification elements. */ - struct notification notification[MIN_NQ_ELEM]; -}; - -#endif /* _MCINQ_H_ */ diff --git a/drivers/gud/MobiCoreKernelApi/include/mcuuid.h b/drivers/gud/MobiCoreKernelApi/include/mcuuid.h deleted file mode 100644 index eca5191edf8e..000000000000 --- a/drivers/gud/MobiCoreKernelApi/include/mcuuid.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MCUUID_H_ -#define _MCUUID_H_ - -#define UUID_TYPE - -/* Universally Unique Identifier (UUID) according to ISO/IEC 11578. */ -struct mc_uuid_t { - uint8_t value[16]; /* Value of the UUID. */ -}; - -#endif /* _MCUUID_H_ */ diff --git a/drivers/gud/MobiCoreKernelApi/main.c b/drivers/gud/MobiCoreKernelApi/main.c deleted file mode 100644 index 405f84058c63..000000000000 --- a/drivers/gud/MobiCoreKernelApi/main.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include <linux/module.h> -#include <linux/init.h> - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/netlink.h> -#include <linux/kthread.h> -#include <linux/device.h> -#include <net/sock.h> - -#include <linux/list.h> - -#include "connection.h" -#include "common.h" - -#define MC_DAEMON_NETLINK 17 - -struct mc_kernelapi_ctx { - struct sock *sk; - struct list_head peers; - atomic_t counter; -}; - -struct mc_kernelapi_ctx *mod_ctx; - -/* Define a MobiCore Kernel API device structure for use with dev_debug() etc */ -struct device_driver mc_kernel_api_name = { - .name = "mckernelapi" -}; - -struct device mc_kernel_api_subname = { - .init_name = "", /* Set to 'mcapi' at mcapi_init() time */ - .driver = &mc_kernel_api_name -}; - -struct device *mc_kapi = &mc_kernel_api_subname; - -/* get a unique ID */ -unsigned int mcapi_unique_id(void) -{ - return (unsigned int)atomic_inc_return(&(mod_ctx->counter)); -} - -static struct connection *mcapi_find_connection(uint32_t seq) -{ - struct connection *tmp; - struct list_head *pos; - - /* Get session for session_id */ - list_for_each(pos, &mod_ctx->peers) { - tmp = list_entry(pos, struct connection, list); - if (tmp->sequence_magic == seq) - return tmp; - } - - return NULL; -} - -void mcapi_insert_connection(struct connection *connection) -{ - list_add_tail(&(connection->list), &(mod_ctx->peers)); - connection->socket_descriptor = mod_ctx->sk; -} - -void mcapi_remove_connection(uint32_t seq) -{ - struct connection *tmp; - struct list_head *pos, *q; - - /* - * Delete all session objects. Usually this should not be needed as - * closeDevice() requires that all sessions have been closed before. - */ - list_for_each_safe(pos, q, &mod_ctx->peers) { - tmp = list_entry(pos, struct connection, list); - if (tmp->sequence_magic == seq) { - list_del(pos); - break; - } - } -} - -static int mcapi_process(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct connection *c; - int seq; - int ret; - - seq = nlh->nlmsg_seq; - MCDRV_DBG_VERBOSE(mc_kapi, "nlmsg len %d type %d pid 0x%X seq %d\n", - nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_pid, seq); - do { - c = mcapi_find_connection(seq); - if (!c) { - MCDRV_ERROR(mc_kapi, - "Invalid incoming connection - seq=%u!", - seq); - ret = -1; - break; - } - - /* Pass the buffer to the appropriate connection */ - connection_process(c, skb); - - ret = 0; - } while (false); - return ret; -} - -static void mcapi_callback(struct sk_buff *skb) -{ - struct nlmsghdr *nlh = nlmsg_hdr(skb); - int len = skb->len; - int err = 0; - - while (NLMSG_OK(nlh, len)) { - err = mcapi_process(skb, nlh); - - /* if err or if this message says it wants a response */ - if (err || (nlh->nlmsg_flags & NLM_F_ACK)) - netlink_ack(skb, nlh, err); - - nlh = NLMSG_NEXT(nlh, len); - } -} - -static int __init mcapi_init(void) -{ - struct netlink_kernel_cfg netlink_cfg; - - dev_set_name(mc_kapi, "mcapi"); - - dev_info(mc_kapi, "Mobicore API module initialized!\n"); - - netlink_cfg.groups = 0; - netlink_cfg.flags = 0; - netlink_cfg.input = mcapi_callback; - netlink_cfg.cb_mutex = NULL; - netlink_cfg.bind = NULL; - - mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL); - if (mod_ctx == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Allocation failure"); - return -ENOMEM; - } - /* start kernel thread */ - mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, - &netlink_cfg); - if (!mod_ctx->sk) { - MCDRV_ERROR(mc_kapi, "register of receive handler failed"); - kfree(mod_ctx); - mod_ctx = NULL; - return -EFAULT; - } - - INIT_LIST_HEAD(&mod_ctx->peers); - return 0; -} - -static void __exit mcapi_exit(void) -{ - dev_info(mc_kapi, "Unloading Mobicore API module.\n"); - - if (mod_ctx->sk != NULL) { - netlink_kernel_release(mod_ctx->sk); - mod_ctx->sk = NULL; - } - kfree(mod_ctx); - mod_ctx = NULL; -} - -module_init(mcapi_init); -module_exit(mcapi_exit); - -MODULE_AUTHOR("Trustonic Limited"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("MobiCore API driver"); diff --git a/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h deleted file mode 100644 index 7bf2a2f66b72..000000000000 --- a/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * MobiCore Driver API. - * - * The MobiCore (MC) Driver API provides access functions to the MobiCore - * runtime environment and the contained Trustlets. - */ -#ifndef _MOBICORE_DRIVER_API_H_ -#define _MOBICORE_DRIVER_API_H_ - -#define __MC_CLIENT_LIB_API - -#include "mcuuid.h" - -/* - * Return values of MobiCore driver functions. - */ -enum mc_result { - /* Function call succeeded. */ - MC_DRV_OK = 0, - /* No notification available. */ - MC_DRV_NO_NOTIFICATION = 1, - /* Error during notification on communication level. */ - MC_DRV_ERR_NOTIFICATION = 2, - /* Function not implemented. */ - MC_DRV_ERR_NOT_IMPLEMENTED = 3, - /* No more resources available. */ - MC_DRV_ERR_OUT_OF_RESOURCES = 4, - /* Driver initialization failed. */ - MC_DRV_ERR_INIT = 5, - /* Unknown error. */ - MC_DRV_ERR_UNKNOWN = 6, - /* The specified device is unknown. */ - MC_DRV_ERR_UNKNOWN_DEVICE = 7, - /* The specified session is unknown.*/ - MC_DRV_ERR_UNKNOWN_SESSION = 8, - /* The specified operation is not allowed. */ - MC_DRV_ERR_INVALID_OPERATION = 9, - /* The response header from the MC is invalid. */ - MC_DRV_ERR_INVALID_RESPONSE = 10, - /* Function call timed out. */ - MC_DRV_ERR_TIMEOUT = 11, - /* Can not allocate additional memory. */ - MC_DRV_ERR_NO_FREE_MEMORY = 12, - /* Free memory failed. */ - MC_DRV_ERR_FREE_MEMORY_FAILED = 13, - /* Still some open sessions pending. */ - MC_DRV_ERR_SESSION_PENDING = 14, - /* MC daemon not reachable */ - MC_DRV_ERR_DAEMON_UNREACHABLE = 15, - /* The device file of the kernel module could not be opened. */ - MC_DRV_ERR_INVALID_DEVICE_FILE = 16, - /* Invalid parameter. */ - MC_DRV_ERR_INVALID_PARAMETER = 17, - /* Unspecified error from Kernel Module*/ - MC_DRV_ERR_KERNEL_MODULE = 18, - /* Error during mapping of additional bulk memory to session. */ - MC_DRV_ERR_BULK_MAPPING = 19, - /* Error during unmapping of additional bulk memory to session. */ - MC_DRV_ERR_BULK_UNMAPPING = 20, - /* Notification received, exit code available. */ - MC_DRV_INFO_NOTIFICATION = 21, - /* Set up of NWd connection failed. */ - MC_DRV_ERR_NQ_FAILED = 22 -}; - -/* - * Driver control command. - */ -enum mc_driver_ctrl { - /* Return the driver version */ - MC_CTRL_GET_VERSION = 1 -}; - -/* - * Structure of Session Handle, includes the Session ID and the Device ID the - * Session belongs to. - * The session handle will be used for session-based MobiCore communication. - * It will be passed to calls which address a communication end point in the - * MobiCore environment. - */ -struct mc_session_handle { - uint32_t session_id; /* MobiCore session ID */ - uint32_t device_id; /* Device ID the session belongs to */ -}; - -/* - * Information structure about additional mapped Bulk buffer between the - * Trustlet Connector (NWd) and the Trustlet (SWd). This structure is - * initialized from a Trustlet Connector by calling mc_map(). - * In order to use the memory within a Trustlet the Trustlet Connector has to - * inform the Trustlet with the content of this structure via the TCI. - */ -struct mc_bulk_map { - /* The virtual address of the Bulk buffer regarding the address space - * of the Trustlet, already includes a possible offset! */ - uint32_t secure_virt_addr; - uint32_t secure_virt_len; /* Length of the mapped Bulk buffer */ -}; - -/* The default device ID */ -#define MC_DEVICE_ID_DEFAULT 0 -/* Wait infinite for a response of the MC. */ -#define MC_INFINITE_TIMEOUT ((int32_t)(-1)) -/* Do not wait for a response of the MC. */ -#define MC_NO_TIMEOUT 0 -/* TCI/DCI must not exceed 1MiB */ -#define MC_MAX_TCI_LEN 0x100000 - -/** - * mc_open_device() - Open a new connection to a MobiCore device. - * @device_id: Identifier for the MobiCore device to be used. - * MC_DEVICE_ID_DEFAULT refers to the default device. - * - * Initializes all device specific resources required to communicate with a - * MobiCore instance located on the specified device in the system. If the - * device does not exist the function will return MC_DRV_ERR_UNKNOWN_DEVICE. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_ERR_INVALID_OPERATION: device already opened - * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon - * MC_DRV_ERR_UNKNOWN_DEVICE: device_id unknown - * MC_DRV_ERR_INVALID_DEVICE_FILE: kernel module under /dev/mobicore - * cannot be opened - */ -__MC_CLIENT_LIB_API enum mc_result mc_open_device(uint32_t device_id); - -/** - * mc_close_device() - Close the connection to a MobiCore device. - * @device_id: Identifier for the MobiCore device. - * - * When closing a device, active sessions have to be closed beforehand. - * Resources associated with the device will be released. - * The device may be opened again after it has been closed. - * - * MC_DEVICE_ID_DEFAULT refers to the default device. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid - * MC_DRV_ERR_SESSION_PENDING: a session is still open - * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur - */ -__MC_CLIENT_LIB_API enum mc_result mc_close_device(uint32_t device_id); - -/** - * mc_open_session() - Open a new session to a Trustlet. - * @session: On success, the session data will be returned - * @uuid: UUID of the Trustlet to be opened - * @tci: TCI buffer for communicating with the Trustlet - * @tci_len: Length of the TCI buffer. Maximum allowed value - * is MC_MAX_TCI_LEN - * - * The Trustlet with the given UUID has to be available in the flash filesystem. - * - * Write MCP open message to buffer and notify MobiCore about the availability - * of a new command. - * - * Waits till the MobiCore responses with the new session ID (stored in the MCP - * buffer). - * - * Note that session.device_id has to be the device id of an opened device. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_INVALID_PARAMETER: session parameter is invalid - * MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid - * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon socket occur - * MC_DRV_ERR_NQ_FAILED: daemon returns an error - */ -__MC_CLIENT_LIB_API enum mc_result mc_open_session( - struct mc_session_handle *session, const struct mc_uuid_t *uuid, - uint8_t *tci, uint32_t tci_len); - -/** - * mc_close_session() - Close a Trustlet session. - * @session: Session to be closed. - * - * Closes the specified MobiCore session. The call will block until the - * session has been closed. - * - * Device device_id has to be opened in advance. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_INVALID_PARAMETER: session parameter is invalid - * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid - * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid - * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur - * MC_DRV_ERR_INVALID_DEVICE_FILE: daemon cannot open Trustlet file - */ -__MC_CLIENT_LIB_API enum mc_result mc_close_session( - struct mc_session_handle *session); - -/** - * mc_notify() - Notify a session. - * @session: The session to be notified. - * - * Notifies the session end point about available message data. - * If the session parameter is correct, notify will always succeed. - * Corresponding errors can only be received by mc_wait_notification(). - * - * A session has to be opened in advance. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_INVALID_PARAMETER: session parameter is invalid - * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid - * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid - */ -__MC_CLIENT_LIB_API enum mc_result mc_notify(struct mc_session_handle *session); - -/** - * mc_wait_notification() - Wait for a notification. - * @session: The session the notification should correspond to. - * @timeout: Time in milliseconds to wait - * (MC_NO_TIMEOUT : direct return, > 0 : milliseconds, - * MC_INFINITE_TIMEOUT : wait infinitely) - * - * Wait for a notification issued by the MobiCore for a specific session. - * The timeout parameter specifies the number of milliseconds the call will wait - * for a notification. - * - * If the caller passes 0 as timeout value the call will immediately return. - * If timeout value is below 0 the call will block until a notification for the - * session has been received. - * - * If timeout is below 0, call will block. - * - * Caller has to trust the other side to send a notification to wake him up - * again. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_ERR_TIMEOUT: no notification arrived in time - * MC_DRV_INFO_NOTIFICATION: a problem with the session was - * encountered. Get more details with - * mc_get_session_error_code() - * MC_DRV_ERR_NOTIFICATION: a problem with the socket occurred - * MC_DRV_INVALID_PARAMETER: a parameter is invalid - * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid - * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid - */ -__MC_CLIENT_LIB_API enum mc_result mc_wait_notification( - struct mc_session_handle *session, int32_t timeout); - -/** - * mc_malloc_wsm() - Allocate a block of world shared memory (WSM). - * @device_id: The ID of an opened device to retrieve the WSM from. - * @align: The alignment (number of pages) of the memory block - * (e.g. 0x00000001 for 4kb). - * @len: Length of the block in bytes. - * @wsm: Virtual address of the world shared memory block. - * @wsm_flags: Platform specific flags describing the memory to - * be allocated. - * - * The MC driver allocates a contiguous block of memory which can be used as - * WSM. - * This implicates that the allocated memory is aligned according to the - * alignment parameter. - * - * Always returns a buffer of size WSM_SIZE aligned to 4K. - * - * Align and wsm_flags are currently ignored - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_INVALID_PARAMETER: a parameter is invalid - * MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid - * MC_DRV_ERR_NO_FREE_MEMORY: no more contiguous memory is - * available in this size or for this - * process - */ -__MC_CLIENT_LIB_API enum mc_result mc_malloc_wsm( - uint32_t device_id, - uint32_t align, - uint32_t len, - uint8_t **wsm, - uint32_t wsm_flags -); - -/** - * mc_free_wsm() - Free a block of world shared memory (WSM). - * @device_id: The ID to which the given address belongs - * @wsm: Address of WSM block to be freed - * - * The MC driver will free a block of world shared memory (WSM) previously - * allocated with mc_malloc_wsm(). The caller has to assure that the address - * handed over to the driver is a valid WSM address. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_INVALID_PARAMETER: a parameter is invalid - * MC_DRV_ERR_UNKNOWN_DEVICE: when device id is invalid - * MC_DRV_ERR_FREE_MEMORY_FAILED: on failure - */ -__MC_CLIENT_LIB_API enum mc_result mc_free_wsm(uint32_t device_id, - uint8_t *wsm); - -/** - *mc_map() - Map additional bulk buffer between a Trustlet Connector (TLC) - * and the Trustlet (TL) for a session - * @session: Session handle with information of the device_id and - * the session_id. The given buffer is mapped to the - * session specified in the sessionHandle - * @buf: Virtual address of a memory portion (relative to TLC) - * to be shared with the Trustlet, already includes a - * possible offset! - * @len: length of buffer block in bytes. - * @map_info: Information structure about the mapped Bulk buffer - * between the TLC (NWd) and the TL (SWd). - * - * Memory allocated in user space of the TLC can be mapped as additional - * communication channel (besides TCI) to the Trustlet. Limitation of the - * Trustlet memory structure apply: only 6 chunks can be mapped with a maximum - * chunk size of 1 MiB each. - * - * It is up to the application layer (TLC) to inform the Trustlet - * about the additional mapped bulk memory. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_INVALID_PARAMETER: a parameter is invalid - * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid - * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid - * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur - * MC_DRV_ERR_BULK_MAPPING: buf is already uses as bulk buffer or - * when registering the buffer failed - */ -__MC_CLIENT_LIB_API enum mc_result mc_map( - struct mc_session_handle *session, void *buf, uint32_t len, - struct mc_bulk_map *map_info); - -/** - * mc_unmap() - Remove additional mapped bulk buffer between Trustlet Connector - * (TLC) and the Trustlet (TL) for a session - * @session: Session handle with information of the device_id and - * the session_id. The given buffer is unmapped from the - * session specified in the sessionHandle. - * @buf: Virtual address of a memory portion (relative to TLC) - * shared with the TL, already includes a possible offset! - * @map_info: Information structure about the mapped Bulk buffer - * between the TLC (NWd) and the TL (SWd) - * - * The bulk buffer will immediately be unmapped from the session context. - * - * The application layer (TLC) must inform the TL about unmapping of the - * additional bulk memory before calling mc_unmap! - * - * The clientlib currently ignores the len field in map_info. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_INVALID_PARAMETER: a parameter is invalid - * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid - * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid - * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur - * MC_DRV_ERR_BULK_UNMAPPING: buf was not registered earlier - * or when unregistering failed - */ -__MC_CLIENT_LIB_API enum mc_result mc_unmap( - struct mc_session_handle *session, void *buf, - struct mc_bulk_map *map_info); - -/** - * mc_get_session_error_code() - Get additional error information of the last - * error that occurred on a session. - * @session: Session handle with information of the device_id and - * the session_id - * @last_error: >0 Trustlet has terminated itself with this value, - * <0 Trustlet is dead because of an error within the - * MobiCore (e.g. Kernel exception). See also MCI - * definition. - * - * After the request the stored error code will be deleted. - * - * Return codes: - * MC_DRV_OK: operation completed successfully - * MC_DRV_INVALID_PARAMETER: a parameter is invalid - * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid - * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid - */ -__MC_CLIENT_LIB_API enum mc_result mc_get_session_error_code( - struct mc_session_handle *session, int32_t *last_error); - -#endif /* _MOBICORE_DRIVER_API_H_ */ diff --git a/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h deleted file mode 100644 index 4e6ba0ddf676..000000000000 --- a/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MOBICORE_DRIVER_CMD_H_ -#define _MOBICORE_DRIVER_CMD_H_ - -#include "mcuuid.h" - -enum mc_drv_cmd_t { - MC_DRV_CMD_PING = 0, - MC_DRV_CMD_GET_INFO = 1, - MC_DRV_CMD_OPEN_DEVICE = 2, - MC_DRV_CMD_CLOSE_DEVICE = 3, - MC_DRV_CMD_NQ_CONNECT = 4, - MC_DRV_CMD_OPEN_SESSION = 5, - MC_DRV_CMD_CLOSE_SESSION = 6, - MC_DRV_CMD_NOTIFY = 7, - MC_DRV_CMD_MAP_BULK_BUF = 8, - MC_DRV_CMD_UNMAP_BULK_BUF = 9 -}; - - -enum mc_drv_rsp_t { - MC_DRV_RSP_OK = 0, - MC_DRV_RSP_FAILED = 1, - MC_DRV_RSP_DEVICE_NOT_OPENED = 2, - MC_DRV_RSP_DEVICE_ALREADY_OPENED = 3, - MC_DRV_RSP_COMMAND_NOT_ALLOWED = 4, - MC_DRV_INVALID_DEVICE_NAME = 5, - MC_DRV_RSP_MAP_BULK_ERRO = 6, - MC_DRV_RSP_TRUSTLET_NOT_FOUND = 7, - MC_DRV_RSP_PAYLOAD_LENGTH_ERROR = 8, -}; - - -struct mc_drv_command_header_t { - uint32_t command_id; -}; - -struct mc_drv_response_header_t { - uint32_t response_id; -}; - -#define MC_DEVICE_ID_DEFAULT 0 /* The default device ID */ - -struct mc_drv_cmd_open_device_payload_t { - uint32_t device_id; -}; - -struct mc_drv_cmd_open_device_t { - struct mc_drv_command_header_t header; - struct mc_drv_cmd_open_device_payload_t payload; -}; - - -struct mc_drv_rsp_open_device_payload_t { - /* empty */ -}; - -struct mc_drv_rsp_open_device_t { - struct mc_drv_response_header_t header; - struct mc_drv_rsp_open_device_payload_t payload; -}; - -struct mc_drv_cmd_close_device_t { - struct mc_drv_command_header_t header; - /* - * no payload here because close has none. - * If we use an empty struct, C++ will count it as 4 bytes. - * This will write too much into the socket at write(cmd,sizeof(cmd)) - */ -}; - - -struct mc_drv_rsp_close_device_payload_t { - /* empty */ -}; - -struct mc_drv_rsp_close_device_t { - struct mc_drv_response_header_t header; - struct mc_drv_rsp_close_device_payload_t payload; -}; - -struct mc_drv_cmd_open_session_payload_t { - uint32_t device_id; - struct mc_uuid_t uuid; - uint32_t tci; - uint32_t handle; - uint32_t len; -}; - -struct mc_drv_cmd_open_session_t { - struct mc_drv_command_header_t header; - struct mc_drv_cmd_open_session_payload_t payload; -}; - - -struct mc_drv_rsp_open_session_payload_t { - uint32_t session_id; - uint32_t device_session_id; - uint32_t session_magic; -}; - -struct mc_drv_rsp_open_session_t { - struct mc_drv_response_header_t header; - struct mc_drv_rsp_open_session_payload_t payload; -}; - -struct mc_drv_cmd_close_session_payload_t { - uint32_t session_id; -}; - -struct mc_drv_cmd_close_session_t { - struct mc_drv_command_header_t header; - struct mc_drv_cmd_close_session_payload_t payload; -}; - - -struct mc_drv_rsp_close_session_payload_t { - /* empty */ -}; - -struct mc_drv_rsp_close_session_t { - struct mc_drv_response_header_t header; - struct mc_drv_rsp_close_session_payload_t payload; -}; - -struct mc_drv_cmd_notify_payload_t { - uint32_t session_id; -}; - -struct mc_drv_cmd_notify_t { - struct mc_drv_command_header_t header; - struct mc_drv_cmd_notify_payload_t payload; -}; - - -struct mc_drv_rsp_notify_payload_t { - /* empty */ -}; - -struct mc_drv_rsp_notify_t { - struct mc_drv_response_header_t header; - struct mc_drv_rsp_notify_payload_t payload; -}; - -struct mc_drv_cmd_map_bulk_mem_payload_t { - uint32_t session_id; - uint32_t handle; - uint32_t rfu; - uint32_t offset_payload; - uint32_t len_bulk_mem; -}; - -struct mc_drv_cmd_map_bulk_mem_t { - struct mc_drv_command_header_t header; - struct mc_drv_cmd_map_bulk_mem_payload_t payload; -}; - - -struct mc_drv_rsp_map_bulk_mem_payload_t { - uint32_t session_id; - uint32_t secure_virtual_adr; -}; - -struct mc_drv_rsp_map_bulk_mem_t { - struct mc_drv_response_header_t header; - struct mc_drv_rsp_map_bulk_mem_payload_t payload; -}; - -struct mc_drv_cmd_unmap_bulk_mem_payload_t { - uint32_t session_id; - uint32_t handle; - uint32_t secure_virtual_adr; - uint32_t len_bulk_mem; -}; - -struct mc_drv_cmd_unmap_bulk_mem_t { - struct mc_drv_command_header_t header; - struct mc_drv_cmd_unmap_bulk_mem_payload_t payload; -}; - - -struct mc_drv_rsp_unmap_bulk_mem_payload_t { - uint32_t response_id; - uint32_t session_id; -}; - -struct mc_drv_rsp_unmap_bulk_mem_t { - struct mc_drv_response_header_t header; - struct mc_drv_rsp_unmap_bulk_mem_payload_t payload; -}; - -struct mc_drv_cmd_nqconnect_payload_t { - uint32_t device_id; - uint32_t session_id; - uint32_t device_session_id; - uint32_t session_magic; /* Random data */ -}; - -struct mc_drv_cmd_nqconnect_t { - struct mc_drv_command_header_t header; - struct mc_drv_cmd_nqconnect_payload_t payload; -}; - - -struct mc_drv_rsp_nqconnect_payload_t { - /* empty; */ -}; - -struct mc_drv_rsp_nqconnect_t { - struct mc_drv_response_header_t header; - struct mc_drv_rsp_nqconnect_payload_t payload; -}; - -union mc_drv_command_t { - struct mc_drv_command_header_t header; - struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device; - struct mc_drv_cmd_close_device_t mc_drv_cmd_close_device; - struct mc_drv_cmd_open_session_t mc_drv_cmd_open_session; - struct mc_drv_cmd_close_session_t mc_drv_cmd_close_session; - struct mc_drv_cmd_nqconnect_t mc_drv_cmd_nqconnect; - struct mc_drv_cmd_notify_t mc_drv_cmd_notify; - struct mc_drv_cmd_map_bulk_mem_t mc_drv_cmd_map_bulk_mem; - struct mc_drv_cmd_unmap_bulk_mem_t mc_drv_cmd_unmap_bulk_mem; -}; - -union mc_drv_response_t { - struct mc_drv_response_header_t header; - struct mc_drv_rsp_open_device_t mc_drv_rsp_open_device; - struct mc_drv_rsp_close_device_t mc_drv_rsp_close_device; - struct mc_drv_rsp_open_session_t mc_drv_rsp_open_session; - struct mc_drv_rsp_close_session_t mc_drv_rsp_close_session; - struct mc_drv_rsp_nqconnect_t mc_drv_rsp_nqconnect; - struct mc_drv_rsp_notify_t mc_drv_rsp_notify; - struct mc_drv_rsp_map_bulk_mem_t mc_drv_rsp_map_bulk_mem; - struct mc_drv_rsp_unmap_bulk_mem_t mc_drv_rsp_unmap_bulk_mem; -}; - -#endif /* _MOBICORE_DRIVER_CMD_H_ */ diff --git a/drivers/gud/MobiCoreKernelApi/session.c b/drivers/gud/MobiCoreKernelApi/session.c deleted file mode 100644 index 4f14ce904413..000000000000 --- a/drivers/gud/MobiCoreKernelApi/session.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/device.h> -#include "mc_kernel_api.h" -#include "public/mobicore_driver_api.h" - -#include "session.h" - -struct bulk_buffer_descriptor *bulk_buffer_descriptor_create( - void *virt_addr, uint32_t len, uint32_t handle) -{ - struct bulk_buffer_descriptor *desc; - - desc = kzalloc(sizeof(*desc), GFP_KERNEL); - if (desc == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Allocation failure"); - return NULL; - } - desc->virt_addr = virt_addr; - desc->len = len; - desc->handle = handle; - - return desc; -} - -struct session *session_create( - uint32_t session_id, void *instance, struct connection *connection) -{ - struct session *session; - - session = kzalloc(sizeof(*session), GFP_KERNEL); - if (session == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Allocation failure"); - return NULL; - } - session->session_id = session_id; - session->instance = instance; - session->notification_connection = connection; - session->session_info.last_error = SESSION_ERR_NO; - session->session_info.state = SESSION_STATE_INITIAL; - - INIT_LIST_HEAD(&(session->bulk_buffer_descriptors)); - return session; -} - -void session_cleanup(struct session *session) -{ - struct bulk_buffer_descriptor *bulk_buf_descr; - struct list_head *pos, *q; - - /* Unmap still mapped buffers */ - list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) { - bulk_buf_descr = - list_entry(pos, struct bulk_buffer_descriptor, list); - - MCDRV_DBG_VERBOSE(mc_kapi, - "handle= %d", - bulk_buf_descr->handle); - - /* ignore any error, as we cannot do anything in this case. */ - int ret = mobicore_unmap_vmem(session->instance, - bulk_buf_descr->handle); - if (ret != 0) - MCDRV_DBG_ERROR(mc_kapi, - "mobicore_unmap_vmem failed: %d", ret); - - list_del(pos); - kfree(bulk_buf_descr); - } - - /* Finally delete notification connection */ - connection_cleanup(session->notification_connection); - kfree(session); -} - -void session_set_error_info(struct session *session, int32_t err) -{ - session->session_info.last_error = err; -} - -int32_t session_get_last_err(struct session *session) -{ - return session->session_info.last_error; -} - -struct bulk_buffer_descriptor *session_add_bulk_buf(struct session *session, - void *buf, uint32_t len) -{ - struct bulk_buffer_descriptor *bulk_buf_descr = NULL; - struct bulk_buffer_descriptor *tmp; - struct list_head *pos; - - /* - * Search bulk buffer descriptors for existing vAddr - * At the moment a virtual address can only be added one time - */ - list_for_each(pos, &session->bulk_buffer_descriptors) { - tmp = list_entry(pos, struct bulk_buffer_descriptor, list); - if (tmp->virt_addr == buf) - return NULL; - } - - do { - /* - * Prepare the interface structure for memory registration in - * Kernel Module - */ - uint32_t handle; - - int ret = mobicore_map_vmem(session->instance, buf, len, - &handle); - - if (ret != 0) { - MCDRV_DBG_ERROR(mc_kapi, - "mobicore_map_vmem failed, ret=%d", - ret); - break; - } - - MCDRV_DBG_VERBOSE(mc_kapi, "handle=%d", handle); - - /* Create new descriptor */ - bulk_buf_descr = - bulk_buffer_descriptor_create(buf, len, handle); - if (bulk_buf_descr == NULL) { - /* Discard the returned value */ - (void)mobicore_unmap_vmem(session->instance, handle); - break; - } - - /* Add to vector of descriptors */ - list_add_tail(&(bulk_buf_descr->list), - &(session->bulk_buffer_descriptors)); - } while (0); - - return bulk_buf_descr; -} - -bool session_remove_bulk_buf(struct session *session, void *virt_addr) -{ - bool ret = true; - struct bulk_buffer_descriptor *bulk_buf = NULL; - struct bulk_buffer_descriptor *tmp; - struct list_head *pos, *q; - - MCDRV_DBG_VERBOSE(mc_kapi, "Virtual Address = 0x%p", - virt_addr); - - /* Search and remove bulk buffer descriptor */ - list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) { - tmp = list_entry(pos, struct bulk_buffer_descriptor, list); - if (tmp->virt_addr == virt_addr) { - bulk_buf = tmp; - list_del(pos); - break; - } - } - - if (bulk_buf == NULL) { - MCDRV_DBG_ERROR(mc_kapi, "Virtual Address not found"); - ret = false; - } else { - MCDRV_DBG_VERBOSE(mc_kapi, "Wsm handle=%d", - bulk_buf->handle); - - /* ignore any error, as we cannot do anything */ - int ret = mobicore_unmap_vmem(session->instance, - bulk_buf->handle); - if (ret != 0) - MCDRV_DBG_ERROR(mc_kapi, - "mobicore_unmap_vmem failed: %d", ret); - - kfree(bulk_buf); - } - - return ret; -} - -uint32_t session_find_bulk_buf(struct session *session, void *virt_addr) -{ - struct bulk_buffer_descriptor *tmp; - struct list_head *pos, *q; - - MCDRV_DBG_VERBOSE(mc_kapi, "Virtual Address = 0x%p", - virt_addr); - - /* Search and return buffer descriptor handle */ - list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) { - tmp = list_entry(pos, struct bulk_buffer_descriptor, list); - if (tmp->virt_addr == virt_addr) - return tmp->handle; - } - - return 0; -} diff --git a/drivers/gud/MobiCoreKernelApi/session.h b/drivers/gud/MobiCoreKernelApi/session.h deleted file mode 100644 index 2f7d5a9a0065..000000000000 --- a/drivers/gud/MobiCoreKernelApi/session.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MC_KAPI_SESSION_H_ -#define _MC_KAPI_SESSION_H_ - -#include "common.h" - -#include <linux/list.h> -#include "connection.h" - - -struct bulk_buffer_descriptor { - void *virt_addr; /* The VA of the Bulk buffer */ - uint32_t len; /* Length of the Bulk buffer */ - uint32_t handle; - - /* The list param for using the kernel lists*/ - struct list_head list; -}; - -struct bulk_buffer_descriptor *bulk_buffer_descriptor_create( - void *virt_addr, - uint32_t len, - uint32_t handle -); - -/* - * Session states. - * At the moment not used !! - */ -enum session_state { - SESSION_STATE_INITIAL, - SESSION_STATE_OPEN, - SESSION_STATE_TRUSTLET_DEAD -}; - -#define SESSION_ERR_NO 0 /* No session error */ - -/* - * Session information structure. - * The information structure is used to hold the state of the session, which - * will limit further actions for the session. - * Also the last error code will be stored till it's read. - */ -struct session_information { - enum session_state state; /* Session state */ - int32_t last_error; /* Last error of session */ -}; - - -struct session { - struct mc_instance *instance; - - /* Descriptors of additional bulk buffer of a session */ - struct list_head bulk_buffer_descriptors; - - /* Information about session */ - struct session_information session_info; - - uint32_t session_id; - struct connection *notification_connection; - - /* The list param for using the kernel lists */ - struct list_head list; -}; - -struct session *session_create( - uint32_t session_id, - void *instance, - struct connection *connection -); - -void session_cleanup(struct session *session); - -/* - * session_add_bulk_buf() - Add address information of additional bulk - * buffer memory to session and register virtual - * memory in kernel module - * @session: Session information structure - * @buf: The virtual address of bulk buffer. - * @len: Length of bulk buffer. - * - * The virtual address can only be added one time. If the virtual - * address already exist, NULL is returned. - * - * On success the actual Bulk buffer descriptor with all address information - * is returned, NULL if an error occurs. - */ -struct bulk_buffer_descriptor *session_add_bulk_buf( - struct session *session, void *buf, uint32_t len); - -/* - * session_remove_bulk_buf() - Remove address information of additional bulk - * buffer memory from session and unregister - * virtual memory in kernel module - * @session: Session information structure - * @buf: The virtual address of the bulk buffer - * - * Returns true on success - */ -bool session_remove_bulk_buf(struct session *session, void *buf); - - -/* - * session_find_bulk_buf() - Find the handle of the bulk buffer for this - * session - * - * @session: Session information structure - * @buf: The virtual address of bulk buffer. - * - * On success the actual Bulk buffer handle is returned, 0 - * if an error occurs. - */ -uint32_t session_find_bulk_buf(struct session *session, void *virt_addr); - -/* - * session_set_error_info() - Set additional error information of the last - * error that occurred. - * @session: Session information structure - * @err: The actual error - */ -void session_set_error_info(struct session *session, int32_t err); - -/* - * session_get_last_err() - Get additional error information of the last - * error that occurred. - * @session: Session information structure - * - * After request the information is set to SESSION_ERR_NO. - * - * Returns the last stored error code or SESSION_ERR_NO - */ -int32_t session_get_last_err(struct session *session); - -#endif /* _MC_KAPI_SESSION_H_ */ diff --git a/drivers/gud/MobiCoreKernelApi/wsm.h b/drivers/gud/MobiCoreKernelApi/wsm.h deleted file mode 100644 index b8d4b26c6315..000000000000 --- a/drivers/gud/MobiCoreKernelApi/wsm.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2013 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * World shared memory definitions. - */ -#ifndef _MC_KAPI_WSM_H_ -#define _MC_KAPI_WSM_H_ - -#include "common.h" -#include <linux/list.h> - -struct wsm { - void *virt_addr; - uint32_t len; - uint32_t handle; - struct list_head list; -}; - -#endif /* _MC_KAPI_WSM_H_ */ diff --git a/drivers/gud/README b/drivers/gud/README deleted file mode 100644 index 7567b48d01e4..000000000000 --- a/drivers/gud/README +++ /dev/null @@ -1,6 +0,0 @@ -t-base is an operating system being shipped with TZBSP -on msm chipsets. t-base consists of several components in -the secure world(TrustZone) and non-secure world(linux -kernel, Android user space). The t-base driver -communicates with the t-base kernel that exists in -TrustZone. diff --git a/drivers/gud/build_tag.h b/drivers/gud/build_tag.h deleted file mode 100644 index 1689ba84a54d..000000000000 --- a/drivers/gud/build_tag.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2013-2014 TRUSTONIC LIMITED - * 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 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#define MOBICORE_COMPONENT_BUILD_TAG \ - "t-base-Qualcomm-MSM8994-Android-301B-V001" diff --git a/drivers/gud/setupDrivers.sh b/drivers/gud/setupDrivers.sh deleted file mode 100644 index 994e83e8d951..000000000000 --- a/drivers/gud/setupDrivers.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -export COMP_PATH_ROOT=$(dirname $(readlink -f $BASH_SOURCE)) #set this to the absolute path of the folder containing this file - -# This part has to be set by the customer -# To be set, absolute path of kernel folder -export LINUX_PATH= -# To be set, absolute path! CROSS_COMPILE variable needed by kernel eg /home/user/arm-2009q3/bin/arm-none-linux-gnueabi- -export CROSS_COMPILE= -# To be set, build mode debug or release -export MODE=debug -# To be set, the absolute path to the Linux Android NDK -export NDK_PATH= - -# Global variables needed by build scripts -export COMP_PATH_Logwrapper=$COMP_PATH_ROOT/Logwrapper/Out -export COMP_PATH_MobiCore=$COMP_PATH_ROOT/MobiCore/Out -export COMP_PATH_MobiCoreDriverMod=$COMP_PATH_ROOT/mobicore_driver/Out -export COMP_PATH_MobiCoreDriverLib=$COMP_PATH_ROOT/daemon/Out -export COMP_PATH_AndroidNdkLinux=$NDK_PATH diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c index a267a8e4d320..76896f2a5044 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c @@ -369,6 +369,7 @@ static int msm_fd_open(struct file *file) ctx->vb2_q.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ctx->vb2_q.io_modes = VB2_USERPTR; ctx->vb2_q.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + mutex_init(&ctx->lock); ret = vb2_queue_init(&ctx->vb2_q); if (ret < 0) { dev_err(device->dev, "Error queue init\n"); @@ -411,7 +412,9 @@ static int msm_fd_release(struct file *file) { struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data); + mutex_lock(&ctx->lock); vb2_queue_release(&ctx->vb2_q); + mutex_unlock(&ctx->lock); vfree(ctx->stats); @@ -439,7 +442,9 @@ static unsigned int msm_fd_poll(struct file *file, struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data); unsigned int ret; + mutex_lock(&ctx->lock); ret = vb2_poll(&ctx->vb2_q, file, wait); + mutex_unlock(&ctx->lock); if (atomic_read(&ctx->subscribed_for_event)) { poll_wait(file, &ctx->fh.wait, wait); @@ -679,9 +684,9 @@ static int msm_fd_reqbufs(struct file *file, int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - mutex_lock(&ctx->fd_device->recovery_lock); + mutex_lock(&ctx->lock); ret = vb2_reqbufs(&ctx->vb2_q, req); - mutex_unlock(&ctx->fd_device->recovery_lock); + mutex_unlock(&ctx->lock); return ret; } @@ -697,9 +702,9 @@ static int msm_fd_qbuf(struct file *file, void *fh, int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - mutex_lock(&ctx->fd_device->recovery_lock); + mutex_lock(&ctx->lock); ret = vb2_qbuf(&ctx->vb2_q, pb); - mutex_unlock(&ctx->fd_device->recovery_lock); + mutex_unlock(&ctx->lock); return ret; } @@ -716,9 +721,9 @@ static int msm_fd_dqbuf(struct file *file, int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - mutex_lock(&ctx->fd_device->recovery_lock); + mutex_lock(&ctx->lock); ret = vb2_dqbuf(&ctx->vb2_q, pb, file->f_flags & O_NONBLOCK); - mutex_unlock(&ctx->fd_device->recovery_lock); + mutex_unlock(&ctx->lock); return ret; } @@ -734,7 +739,9 @@ static int msm_fd_streamon(struct file *file, struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); int ret; + mutex_lock(&ctx->lock); ret = vb2_streamon(&ctx->vb2_q, buf_type); + mutex_unlock(&ctx->lock); if (ret < 0) dev_err(ctx->fd_device->dev, "Stream on fails\n"); @@ -753,7 +760,9 @@ static int msm_fd_streamoff(struct file *file, struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); int ret; + mutex_lock(&ctx->lock); ret = vb2_streamoff(&ctx->vb2_q, buf_type); + mutex_unlock(&ctx->lock); if (ret < 0) dev_err(ctx->fd_device->dev, "Stream off fails\n"); @@ -984,15 +993,19 @@ static int msm_fd_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) a->value = ctx->format.size->work_size; break; case V4L2_CID_FD_WORK_MEMORY_FD: + mutex_lock(&ctx->fd_device->recovery_lock); if (ctx->work_buf.handle) msm_fd_hw_unmap_buffer(&ctx->work_buf); if (a->value >= 0) { ret = msm_fd_hw_map_buffer(&ctx->mem_pool, a->value, &ctx->work_buf); - if (ret < 0) + if (ret < 0) { + mutex_unlock(&ctx->fd_device->recovery_lock); return ret; + } } + mutex_unlock(&ctx->fd_device->recovery_lock); break; default: return -EINVAL; diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h index 2f54f42a323d..6d9830954953 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h @@ -156,6 +156,7 @@ struct fd_ctx { struct msm_fd_mem_pool mem_pool; struct msm_fd_stats *stats; struct msm_fd_buf_handle work_buf; + struct mutex lock; }; /* diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c index c102461cad30..b96d7be1e18d 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c +++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c @@ -425,11 +425,13 @@ static long msm_ois_subdev_ioctl(struct v4l2_subdev *sd, pr_err("o_ctrl->i2c_client.i2c_func_tbl NULL\n"); return -EINVAL; } else { + mutex_lock(o_ctrl->ois_mutex); rc = msm_ois_power_down(o_ctrl); if (rc < 0) { pr_err("%s:%d OIS Power down failed\n", __func__, __LINE__); } + mutex_unlock(o_ctrl->ois_mutex); return msm_ois_close(sd, NULL); } default: diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index a393c054ff20..d42356e8c45c 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. 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 @@ -734,6 +734,8 @@ static int __init msm_vidc_init(void) if (rc) { dprintk(VIDC_ERR, "Failed to register platform driver\n"); + msm_vidc_debugfs_deinit_drv(); + debugfs_remove_recursive(vidc_driver->debugfs_root); kfree(vidc_driver); vidc_driver = NULL; } @@ -744,6 +746,7 @@ static int __init msm_vidc_init(void) static void __exit msm_vidc_exit(void) { platform_driver_unregister(&msm_vidc_driver); + msm_vidc_debugfs_deinit_drv(); debugfs_remove_recursive(vidc_driver->debugfs_root); kfree(vidc_driver); vidc_driver = NULL; diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 3cb3d97e6eff..5f16b9db45dd 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1404,7 +1404,6 @@ static void cleanup_instance(struct msm_vidc_inst *inst) msm_comm_smem_free(inst, inst->extradata_handle); debugfs_remove_recursive(inst->debugfs_root); - mutex_lock(&inst->pending_getpropq.lock); WARN_ON(!list_empty(&inst->pending_getpropq.list) && (msm_vidc_debug & VIDC_INFO)); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index ece325d9e120..9dc22d89f16a 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. 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 @@ -30,45 +30,15 @@ int msm_vidc_sys_idle_indicator = 0x0; u32 msm_vidc_firmware_unload_delay = 15000; int msm_vidc_thermal_mitigation_disabled = 0x0; -struct debug_buffer { - char ptr[MAX_DBG_BUF_SIZE]; - char *curr; - u32 filled_size; -}; - -static struct debug_buffer dbg_buf; - -#define INIT_DBG_BUF(__buf) ({ \ - __buf.curr = __buf.ptr;\ - __buf.filled_size = 0; \ -}) +static struct mutex debugfs_lock; #define DYNAMIC_BUF_OWNER(__binfo) ({ \ atomic_read(&__binfo->ref_count) == 2 ? "video driver" : "firmware";\ }) -static int core_info_open(struct inode *inode, struct file *file) +static int vidc_debug_core_show(struct seq_file *s, void *unused) { - file->private_data = inode->i_private; - return 0; -} - -static u32 write_str(struct debug_buffer *buffer, const char *fmt, ...) -{ - va_list args; - u32 size; - va_start(args, fmt); - size = vscnprintf(buffer->curr, MAX_DBG_BUF_SIZE - 1, fmt, args); - va_end(args); - buffer->curr += size; - buffer->filled_size += size; - return size; -} - -static ssize_t core_info_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct msm_vidc_core *core = file->private_data; + struct msm_vidc_core *core = s->private; struct hfi_device *hdev; struct hal_fw_info fw_info; int i = 0, rc = 0; @@ -77,37 +47,46 @@ static ssize_t core_info_read(struct file *file, char __user *buf, dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core); return 0; } + + mutex_lock(&debugfs_lock); hdev = core->device; - INIT_DBG_BUF(dbg_buf); - write_str(&dbg_buf, "===============================\n"); - write_str(&dbg_buf, "CORE %d: 0x%pK\n", core->id, core); - write_str(&dbg_buf, "===============================\n"); - write_str(&dbg_buf, "Core state: %d\n", core->state); + + seq_puts(s, "===============================\n"); + seq_printf(s, "CORE %d: %pK\n", core->id, core); + seq_puts(s, "===============================\n"); + seq_printf(s, "Core state: %d\n", core->state); rc = call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data, &fw_info); if (rc) { dprintk(VIDC_WARN, "Failed to read FW info\n"); goto err_fw_info; } - write_str(&dbg_buf, "FW version : %s\n", &fw_info.version); - write_str(&dbg_buf, "base addr: 0x%x\n", fw_info.base_addr); - write_str(&dbg_buf, "register_base: 0x%x\n", fw_info.register_base); - write_str(&dbg_buf, "register_size: %u\n", fw_info.register_size); - write_str(&dbg_buf, "irq: %u\n", fw_info.irq); + seq_printf(s, "FW version : %s\n", fw_info.version); + seq_printf(s, "base addr: %pa\n", &fw_info.base_addr); + seq_printf(s, "register_base: %pa\n", &fw_info.register_base); + seq_printf(s, "register_size: %u\n", fw_info.register_size); + seq_printf(s, "irq: %u\n", fw_info.irq); err_fw_info: for (i = SYS_MSG_START; i < SYS_MSG_END; i++) { - write_str(&dbg_buf, "completions[%d]: %s\n", i, + seq_printf(s, "completions[%d]: %s\n", i, completion_done(&core->completions[SYS_MSG_INDEX(i)]) ? "pending" : "done"); } - return simple_read_from_buffer(buf, count, ppos, - dbg_buf.ptr, dbg_buf.filled_size); + mutex_unlock(&debugfs_lock); + return 0; +} + +static int vidc_debug_core_open(struct inode *inode, struct file *file) +{ + return single_open(file, vidc_debug_core_show, inode->i_private); } static const struct file_operations core_info_fops = { - .open = core_info_open, - .read = core_info_read, + .open = vidc_debug_core_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; static int trigger_ssr_open(struct inode *inode, struct file *file) @@ -139,7 +118,10 @@ static const struct file_operations ssr_fops = { struct dentry *msm_vidc_debugfs_init_drv(void) { - struct dentry *dir = debugfs_create_dir("msm_vidc", NULL); + struct dentry *dir = NULL; + + mutex_init(&debugfs_lock); + dir = debugfs_create_dir("msm_vidc", NULL); if (IS_ERR_OR_NULL(dir)) { dir = NULL; goto failed_create_dir; @@ -222,6 +204,11 @@ failed_create_dir: return NULL; } +void msm_vidc_debugfs_deinit_drv(void) +{ + mutex_destroy(&debugfs_lock); +} + struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core, struct dentry *parent) { @@ -238,6 +225,7 @@ struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core, dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n"); goto failed_create_dir; } + if (!debugfs_create_file("info", S_IRUGO, dir, core, &core_info_fops)) { dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); goto failed_create_dir; @@ -251,13 +239,32 @@ failed_create_dir: return dir; } -static int inst_info_open(struct inode *inode, struct file *file) +static struct msm_vidc_inst *get_inst(struct msm_vidc_inst *inst) { - file->private_data = inode->i_private; - return 0; + struct msm_vidc_core *core = NULL; + struct msm_vidc_inst *temp, *ret = NULL; + + if (!inst) + return NULL; + + mutex_lock(&vidc_driver->lock); + list_for_each_entry(core, &vidc_driver->cores, list) { + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) + if (temp == inst) { + ret = inst; + break; + } + mutex_unlock(&core->lock); + if (ret != NULL) + break; + } + mutex_unlock(&vidc_driver->lock); + return ret; } -static int publish_unreleased_reference(struct msm_vidc_inst *inst) +static int publish_unreleased_reference(struct msm_vidc_inst *inst, + struct seq_file *s) { struct buffer_info *temp = NULL; @@ -267,121 +274,141 @@ static int publish_unreleased_reference(struct msm_vidc_inst *inst) } if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) { - write_str(&dbg_buf, "Pending buffer references:\n"); + seq_puts(s, "Pending buffer references\n"); mutex_lock(&inst->registeredbufs.lock); list_for_each_entry(temp, &inst->registeredbufs.list, list) { if (temp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && !temp->inactive && atomic_read(&temp->ref_count)) { - write_str(&dbg_buf, - "\tpending buffer: 0x%lx fd[0] = %d ref_count = %d held by: %s\n", - temp->device_addr[0], - temp->fd[0], - atomic_read(&temp->ref_count), - DYNAMIC_BUF_OWNER(temp)); + seq_printf(s, + "\tpending buffer: %pad fd[0] = %d ref_count = %d held by: %s\n", + &temp->device_addr[0], + temp->fd[0], + atomic_read(&temp->ref_count), + DYNAMIC_BUF_OWNER(temp)); } } mutex_unlock(&inst->registeredbufs.lock); } + return 0; } -static ssize_t inst_info_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) +static int vidc_debug_inst_show(struct seq_file *s, void *unused) { - struct msm_vidc_inst *inst = file->private_data; + struct msm_vidc_inst *inst = get_inst(s->private); int i, j; + if (!inst) { - dprintk(VIDC_ERR, "Invalid params, core: %pK\n", inst); - return 0; + dprintk(VIDC_ERR, "Instance deleted\n"); + return -EINVAL; } - INIT_DBG_BUF(dbg_buf); - write_str(&dbg_buf, "===============================\n"); - write_str(&dbg_buf, "INSTANCE: 0x%pK (%s)\n", inst, + + mutex_lock(&debugfs_lock); + seq_puts(s, "==============================\n"); + seq_printf(s, "INSTANCE: %pK (%s)\n", inst, inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder"); - write_str(&dbg_buf, "===============================\n"); - write_str(&dbg_buf, "core: 0x%pK\n", inst->core); - write_str(&dbg_buf, "height: %d\n", inst->prop.height[CAPTURE_PORT]); - write_str(&dbg_buf, "width: %d\n", inst->prop.width[CAPTURE_PORT]); - write_str(&dbg_buf, "fps: %d\n", inst->prop.fps); - write_str(&dbg_buf, "state: %d\n", inst->state); - write_str(&dbg_buf, "secure: %d\n", !!(inst->flags & VIDC_SECURE)); - write_str(&dbg_buf, "-----------Formats-------------\n"); + seq_puts(s, "==============================\n"); + seq_printf(s, "core: %pK\n", inst->core); + seq_printf(s, "height: %d\n", inst->prop.height[CAPTURE_PORT]); + seq_printf(s, "width: %d\n", inst->prop.width[CAPTURE_PORT]); + seq_printf(s, "fps: %d\n", inst->prop.fps); + seq_printf(s, "state: %d\n", inst->state); + seq_printf(s, "secure: %d\n", !!(inst->flags & VIDC_SECURE)); + seq_puts(s, "-----------Formats-------------\n"); for (i = 0; i < MAX_PORT_NUM; i++) { - write_str(&dbg_buf, "capability: %s\n", i == OUTPUT_PORT ? + seq_printf(s, "capability: %s\n", + i == OUTPUT_PORT ? "Output" : "Capture"); + seq_printf(s, "name : %s\n", inst->fmts[i]->name); + seq_printf(s, "planes : %d\n", inst->fmts[i]->num_planes); + seq_printf(s, "type: %s\n", inst->fmts[i]->type == OUTPUT_PORT ? "Output" : "Capture"); - write_str(&dbg_buf, "name : %s\n", inst->fmts[i]->name); - write_str(&dbg_buf, "planes : %d\n", inst->fmts[i]->num_planes); - write_str( - &dbg_buf, "type: %s\n", inst->fmts[i]->type == OUTPUT_PORT ? - "Output" : "Capture"); + switch (inst->buffer_mode_set[i]) { case HAL_BUFFER_MODE_STATIC: - write_str(&dbg_buf, "buffer mode : %s\n", "static"); + seq_printf(s, "buffer mode : %s\n", "static"); break; case HAL_BUFFER_MODE_RING: - write_str(&dbg_buf, "buffer mode : %s\n", "ring"); + seq_printf(s, "buffer mode : %s\n", "ring"); break; case HAL_BUFFER_MODE_DYNAMIC: - write_str(&dbg_buf, "buffer mode : %s\n", "dynamic"); + seq_printf(s, "buffer mode : %s\n", "dynamic"); break; default: - write_str(&dbg_buf, "buffer mode : unsupported\n"); + seq_puts(s, "buffer mode : unsupported\n"); } - write_str(&dbg_buf, "count: %u\n", + seq_printf(s, "count: %u\n", inst->bufq[i].vb2_bufq.num_buffers); for (j = 0; j < inst->fmts[i]->num_planes; j++) - write_str(&dbg_buf, "size for plane %d: %u\n", j, + seq_printf(s, "size for plane %d: %u\n", j, inst->bufq[i].vb2_bufq.plane_sizes[j]); if (i < MAX_PORT_NUM - 1) - write_str(&dbg_buf, "\n"); + seq_puts(s, "\n"); } - write_str(&dbg_buf, "-------------------------------\n"); + seq_puts(s, "-------------------------------\n"); for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) { - write_str(&dbg_buf, "completions[%d]: %s\n", i, + seq_printf(s, "completions[%d]: %s\n", i, completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ? "pending" : "done"); } - write_str(&dbg_buf, "ETB Count: %d\n", inst->count.etb); - write_str(&dbg_buf, "EBD Count: %d\n", inst->count.ebd); - write_str(&dbg_buf, "FTB Count: %d\n", inst->count.ftb); - write_str(&dbg_buf, "FBD Count: %d\n", inst->count.fbd); - publish_unreleased_reference(inst); + seq_printf(s, "ETB Count: %d\n", inst->count.etb); + seq_printf(s, "EBD Count: %d\n", inst->count.ebd); + seq_printf(s, "FTB Count: %d\n", inst->count.ftb); + seq_printf(s, "FBD Count: %d\n", inst->count.fbd); + + publish_unreleased_reference(inst, s); + mutex_unlock(&debugfs_lock); + return 0; +} - return simple_read_from_buffer(buf, count, ppos, - dbg_buf.ptr, dbg_buf.filled_size); +static int vidc_debug_inst_open(struct inode *inode, struct file *file) +{ + return single_open(file, vidc_debug_inst_show, inode->i_private); } static const struct file_operations inst_info_fops = { - .open = inst_info_open, - .read = inst_info_read, + .open = vidc_debug_inst_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, struct dentry *parent) { - struct dentry *dir = NULL; + struct dentry *dir = NULL, *info = NULL; char debugfs_name[MAX_DEBUGFS_NAME]; + if (!inst) { - dprintk(VIDC_ERR, "Invalid params, inst: %pK\n", inst); - goto failed_create_dir; + dprintk(VIDC_ERR, "Invalid params, inst: %p\n", inst); + goto exit; } snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%pK", inst); - dir = debugfs_create_dir(debugfs_name, parent); + if (!dir) { dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n"); - goto failed_create_dir; + goto exit; } - if (!debugfs_create_file("info", S_IRUGO, dir, inst, &inst_info_fops)) { + + info = debugfs_create_file("info", 0444, dir, + inst, &inst_info_fops); + if (!info) { dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); - goto failed_create_dir; + goto failed_create_file; } + + dir->d_inode->i_private = info->d_inode->i_private; inst->debug.pdata[FRAME_PROCESSING].sampling = true; -failed_create_dir: + return dir; + +failed_create_file: + debugfs_remove_recursive(dir); + dir = NULL; +exit: return dir; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h index 5080915bba2a..7c2d0c29f7a0 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2017 The Linux Foundation. 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 @@ -112,6 +112,7 @@ extern int msm_vidc_thermal_mitigation_disabled; struct dentry *msm_vidc_debugfs_init_drv(void); +void msm_vidc_debugfs_deinit_drv(void); struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core, struct dentry *parent); struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 1d230c5ec6e9..2debc49187f0 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -20,6 +20,13 @@ #include <media/v4l2-dev.h> #include <media/v4l2-ioctl.h> +#define convert_in_user(srcptr, dstptr) \ +({ \ + typeof(*srcptr) val; \ + \ + get_user(val, srcptr) || put_user(val, dstptr); \ +}) + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = -ENOIOCTLCMD; @@ -45,27 +52,45 @@ struct v4l2_window32 { compat_caddr_t bitmap; }; -static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +static int bufsize_v4l2_window32(struct v4l2_window32 __user *up) +{ + __u32 clipcount; + + if (get_user(clipcount, &up->clipcount)) + return -EFAULT; + if (clipcount > 2048) + return -EINVAL; + return clipcount * sizeof(struct v4l2_clip); +} + +static int get_v4l2_window32(struct v4l2_window __user *kp, struct + v4l2_window32 __user *up, void __user *aux_buf, int aux_space) { + __u32 clipcount; + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(&kp->w, &up->w, sizeof(up->w)) || - get_user(kp->field, &up->field) || - get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount)) + copy_in_user(&kp->w, &up->w, sizeof(up->w)) || + convert_in_user(&up->field, &kp->field) || + convert_in_user(&up->chromakey, &kp->chromakey) || + get_user(clipcount, &up->clipcount) || + put_user(clipcount, &kp->clipcount)) return -EFAULT; - if (kp->clipcount > 2048) + if (clipcount > 2048) return -EINVAL; - if (kp->clipcount) { + if (clipcount) { struct v4l2_clip32 __user *uclips; struct v4l2_clip __user *kclips; - int n = kp->clipcount; + int n = clipcount; compat_caddr_t p; if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); - kp->clips = kclips; + if (aux_space < n * sizeof(struct v4l2_clip)) + return -EFAULT; + kclips = aux_buf; + if (put_user(kclips, &kp->clips)) + return -EFAULT; while (--n >= 0) { if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) return -EFAULT; @@ -74,75 +99,77 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user uclips += 1; kclips += 1; } - } else - kp->clips = NULL; + } else { + if (put_user(NULL, &kp->clips)) + return -EFAULT; + } return 0; } -static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +static int put_v4l2_window32(struct v4l2_window __user *kp, struct v4l2_window32 __user *up) { - if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || - put_user(kp->field, &up->field) || - put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount)) - return -EFAULT; + if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) || + convert_in_user(&kp->field, &up->field) || + convert_in_user(&kp->chromakey, &up->chromakey) || + convert_in_user(&kp->clipcount, &up->clipcount)) + return -EFAULT; return 0; } -static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) +static inline int get_v4l2_pix_format(struct v4l2_pix_format __user *kp, struct v4l2_pix_format __user *up) { - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) + if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format))) return -EFAULT; return 0; } -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane __user *kp, struct v4l2_pix_format_mplane __user *up) { - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) + if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; return 0; } -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) +static inline int put_v4l2_pix_format(struct v4l2_pix_format __user *kp, struct v4l2_pix_format __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) + if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format))) return -EFAULT; return 0; } -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, +static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane __user *kp, struct v4l2_pix_format_mplane __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) + if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; return 0; } -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) +static inline int get_v4l2_vbi_format(struct v4l2_vbi_format __user *kp, struct v4l2_vbi_format __user *up) { - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) + if (copy_in_user(kp, up, sizeof(struct v4l2_vbi_format))) return -EFAULT; return 0; } -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) +static inline int put_v4l2_vbi_format(struct v4l2_vbi_format __user *kp, struct v4l2_vbi_format __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) + if (copy_in_user(up, kp, sizeof(struct v4l2_vbi_format))) return -EFAULT; return 0; } -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) +static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format __user *kp, struct v4l2_sliced_vbi_format __user *up) { - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) + if (copy_in_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) return -EFAULT; return 0; } -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) +static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format __user *kp, struct v4l2_sliced_vbi_format __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) + if (copy_in_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) return -EFAULT; return 0; } @@ -176,12 +203,31 @@ struct v4l2_create_buffers32 { __u32 reserved[8]; }; -static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int __bufsize_v4l2_format32(struct v4l2_format32 __user *up) +{ + __u32 type; + + if (get_user(type, &up->type)) + return -EFAULT; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + return bufsize_v4l2_window32(&up->fmt.win); + default: + return 0; + } +} + +static int __get_v4l2_format32(struct v4l2_format __user *kp, struct + v4l2_format32 __user *up, void __user *aux_buf, int aux_space) { - if (get_user(kp->type, &up->type)) + __u32 type; + + if (get_user(type, &up->type) || put_user(type, &kp->type)) return -EFAULT; - switch (kp->type) { + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); @@ -191,7 +237,7 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us &up->fmt.pix_mp); case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); + return get_v4l2_window32(&kp->fmt.win, &up->fmt.win, aux_buf, aux_space); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); @@ -205,24 +251,46 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us } } -static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int bufsize_v4l2_format32(struct v4l2_format32 __user *up) +{ + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32))) + return -EFAULT; + return __bufsize_v4l2_format32(up); +} + +static int get_v4l2_format32(struct v4l2_format __user *kp, struct + v4l2_format32 __user *up, void __user *aux_buf, int aux_space) { if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32))) return -EFAULT; - return __get_v4l2_format32(kp, up); + return __get_v4l2_format32(kp, up, aux_buf, aux_space); +} + +static int bufsize_v4l2_create32(struct v4l2_create_buffers32 __user *up) +{ + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32))) + return -EFAULT; + return __bufsize_v4l2_format32(&up->format); } -static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int get_v4l2_create32(struct v4l2_create_buffers __user *kp, struct + v4l2_create_buffers32 __user *up, void __user *aux_buf, + int aux_space) { if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || - copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) + copy_in_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) return -EFAULT; - return __get_v4l2_format32(&kp->format, &up->format); + return __get_v4l2_format32(&kp->format, &up->format, aux_buf, aux_space); } -static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int __put_v4l2_format32(struct v4l2_format __user *kp, struct v4l2_format32 __user *up) { - switch (kp->type) { + __u32 type; + + if (get_user(type, &kp->type)) + return -EFAULT; + + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); @@ -246,7 +314,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us } } -static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int put_v4l2_format32(struct v4l2_format __user *kp, struct v4l2_format32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || put_user(kp->type, &up->type)) @@ -254,10 +322,10 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user return __put_v4l2_format32(kp, up); } -static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int put_v4l2_create32(struct v4l2_create_buffers __user *kp, struct v4l2_create_buffers32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || - copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) + copy_in_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) return -EFAULT; return __put_v4l2_format32(&kp->format, &up->format); } @@ -271,24 +339,24 @@ struct v4l2_standard32 { __u32 reserved[4]; }; -static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int get_v4l2_standard32(struct v4l2_standard __user *kp, struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || - get_user(kp->index, &up->index)) + convert_in_user(&up->index, &kp->index)) return -EFAULT; return 0; } -static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int put_v4l2_standard32(struct v4l2_standard __user *kp, struct v4l2_standard32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || - put_user(kp->index, &up->index) || - copy_to_user(up->id, &kp->id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, 24) || - copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) + convert_in_user(&kp->index, &up->index) || + copy_in_user(up->id, &kp->id, sizeof(__u64)) || + copy_in_user(up->name, kp->name, 24) || + copy_in_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || + convert_in_user(&kp->framelines, &up->framelines) || + copy_in_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) return -EFAULT; return 0; } @@ -331,7 +399,6 @@ struct v4l2_buffer32 { static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, enum v4l2_memory memory) { - void __user *up_pln; compat_long_t p; if (copy_in_user(up, up32, 2 * sizeof(__u32)) || @@ -344,10 +411,9 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, return -EFAULT; if (memory == V4L2_MEMORY_USERPTR) { - if (get_user(p, &up32->m.userptr)) - return -EFAULT; - up_pln = compat_ptr(p); - if (put_user((unsigned long)up_pln, &up->m.userptr)) + if (get_user(p, &up32->m.userptr) || + put_user((unsigned long) compat_ptr(p), + &up->m.userptr)) return -EFAULT; } else if (memory == V4L2_MEMORY_DMABUF) { if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int))) @@ -386,8 +452,34 @@ static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, return 0; } -static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int bufsize_v4l2_buffer32(struct v4l2_buffer32 __user *up) { + __u32 type; + __u32 length; + + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || + get_user(type, &up->type) || + get_user(length, &up->length)) + return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + if (length > VIDEO_MAX_PLANES) + return -EINVAL; + + /* We don't really care if userspace decides to kill itself + * by passing a very big length value + */ + return length * sizeof(struct v4l2_plane); + } + return 0; +} + +static int get_v4l2_buffer32(struct v4l2_buffer __user *kp, struct + v4l2_buffer32 __user *up, void __user *aux_buf, int aux_space) +{ + __u32 type; + __u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; @@ -395,40 +487,40 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int ret; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || - get_user(kp->index, &up->index) || - get_user(kp->type, &up->type) || - get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory)) + convert_in_user(&up->index, &kp->index) || + get_user(type, &up->type) || + put_user(type, &kp->type) || + convert_in_user(&up->flags, &kp->flags) || + get_user(memory, &up->memory) || + put_user(memory, &kp->memory) || + convert_in_user(&up->length, &kp->length) || + get_user(length, &up->length) || + put_user(length, &kp->length)) return -EFAULT; - if (V4L2_TYPE_IS_OUTPUT(kp->type)) - if (get_user(kp->bytesused, &up->bytesused) || - get_user(kp->field, &up->field) || - get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, - &up->timestamp.tv_usec)) + if (V4L2_TYPE_IS_OUTPUT(type)) + if (convert_in_user(&up->bytesused, &kp->bytesused) || + convert_in_user(&up->field, &kp->field) || + convert_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || + convert_in_user(&up->timestamp.tv_usec, + &kp->timestamp.tv_usec)) return -EFAULT; - if (V4L2_TYPE_IS_PRIVATE(kp->type)) { + if (V4L2_TYPE_IS_PRIVATE(type)) { compat_long_t tmp; - if (get_user(kp->length, &up->length) || - get_user(tmp, &up->m.userptr)) + if (get_user(tmp, &up->m.userptr) || + put_user((unsigned long) compat_ptr(tmp), + &kp->m.userptr)) return -EFAULT; - - kp->m.userptr = (unsigned long)compat_ptr(tmp); } - if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - if (get_user(kp->length, &up->length)) - return -EFAULT; - - num_planes = kp->length; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + num_planes = length; if (num_planes == 0) { - kp->m.planes = NULL; /* num_planes == 0 is legal, e.g. when userspace doesn't * need planes array on DQBUF*/ - return 0; + return put_user(NULL, &kp->m.planes); } if (get_user(p, &up->m.planes)) @@ -441,41 +533,44 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user /* We don't really care if userspace decides to kill itself * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * - sizeof(struct v4l2_plane)); - kp->m.planes = uplane; + if (aux_space < num_planes * sizeof(struct v4l2_plane)) + return -EFAULT; + + uplane = aux_buf; + if (put_user((__force struct v4l2_plane *)uplane, + &kp->m.planes)) + return -EFAULT; while (--num_planes >= 0) { - ret = get_v4l2_plane32(uplane, uplane32, kp->memory); + ret = get_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; ++uplane; ++uplane32; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: - if (get_user(kp->length, &up->length) || - get_user(kp->m.offset, &up->m.offset)) + if (convert_in_user(&up->m.offset, &kp->m.offset)) return -EFAULT; break; case V4L2_MEMORY_USERPTR: { - compat_long_t tmp; - - if (get_user(kp->length, &up->length) || - get_user(tmp, &up->m.userptr)) - return -EFAULT; + compat_long_t tmp; - kp->m.userptr = (unsigned long)compat_ptr(tmp); + if (get_user(tmp, &up->m.userptr) || + put_user((unsigned long) + compat_ptr(tmp), + &kp->m.userptr)) + return -EFAULT; } break; case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) + if (convert_in_user(&up->m.offset, &kp->m.offset)) return -EFAULT; break; case V4L2_MEMORY_DMABUF: - if (get_user(kp->m.fd, &up->m.fd)) + if (convert_in_user(&up->m.fd, &kp->m.fd)) return -EFAULT; break; } @@ -484,8 +579,11 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user return 0; } -static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int put_v4l2_buffer32(struct v4l2_buffer __user *kp, struct v4l2_buffer32 __user *up) { + __u32 type; + __u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; @@ -493,63 +591,65 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int ret; if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || - put_user(kp->index, &up->index) || - put_user(kp->type, &up->type) || - put_user(kp->flags, &up->flags) || - put_user(kp->memory, &up->memory)) + convert_in_user(&kp->index, &up->index) || + get_user(type, &kp->type) || + put_user(type, &up->type) || + convert_in_user(&kp->flags, &up->flags) || + get_user(memory, &kp->memory) || + put_user(memory, &up->memory)) return -EFAULT; - if (put_user(kp->bytesused, &up->bytesused) || - put_user(kp->field, &up->field) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->reserved2, &up->reserved2) || - put_user(kp->reserved, &up->reserved)) + if (convert_in_user(&kp->bytesused, &up->bytesused) || + convert_in_user(&kp->field, &up->field) || + convert_in_user(&kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + convert_in_user(&kp->timestamp.tv_usec, &up->timestamp.tv_usec) || + copy_in_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || + convert_in_user(&kp->sequence, &up->sequence) || + convert_in_user(&kp->reserved2, &up->reserved2) || + convert_in_user(&kp->reserved, &up->reserved) || + get_user(length, &kp->length) || + put_user(length, &up->length)) return -EFAULT; - if (V4L2_TYPE_IS_PRIVATE(kp->type)) { - if (put_user(kp->length, &up->length) || - put_user(kp->m.userptr, &up->m.userptr)) + if (V4L2_TYPE_IS_PRIVATE(type)) { + if (convert_in_user(&kp->m.userptr, &up->m.userptr)) return -EFAULT; } - if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + num_planes = length; if (num_planes == 0) return 0; - uplane = kp->m.planes; + if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes))) + return -EFAULT; if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p); while (--num_planes >= 0) { - ret = put_v4l2_plane32(uplane, uplane32, kp->memory); + ret = put_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; ++uplane; ++uplane32; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: - if (put_user(kp->length, &up->length) || - put_user(kp->m.offset, &up->m.offset)) + if (convert_in_user(&kp->m.offset, &up->m.offset)) return -EFAULT; break; case V4L2_MEMORY_USERPTR: - if (put_user(kp->length, &up->length) || - put_user(kp->m.userptr, &up->m.userptr)) + if (convert_in_user(&kp->m.userptr, &up->m.userptr)) return -EFAULT; break; case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) + if (convert_in_user(&kp->m.offset, &up->m.offset)) return -EFAULT; break; case V4L2_MEMORY_DMABUF: - if (put_user(kp->m.fd, &up->m.fd)) + if (convert_in_user(&kp->m.fd, &up->m.fd)) return -EFAULT; break; } @@ -565,30 +665,31 @@ struct v4l2_framebuffer32 { struct v4l2_pix_format fmt; }; -static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, struct v4l2_framebuffer32 __user *up) { - u32 tmp; + compat_caddr_t tmp; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || get_user(tmp, &up->base) || - get_user(kp->capability, &up->capability) || - get_user(kp->flags, &up->flags)) + put_user((__force void *)compat_ptr(tmp), &kp->base) || + convert_in_user(&up->capability, &kp->capability) || + convert_in_user(&up->flags, &kp->flags) || + get_v4l2_pix_format(&kp->fmt, &up->fmt)) return -EFAULT; - kp->base = compat_ptr(tmp); - get_v4l2_pix_format(&kp->fmt, &up->fmt); return 0; } -static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, struct v4l2_framebuffer32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->base); + void *base; if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || - put_user(tmp, &up->base) || - put_user(kp->capability, &up->capability) || - put_user(kp->flags, &up->flags)) + get_user(base, &kp->base) || + put_user(ptr_to_compat(base), &up->base) || + convert_in_user(&kp->capability, &up->capability) || + convert_in_user(&kp->flags, &up->flags) || + put_v4l2_pix_format(&kp->fmt, &up->fmt)) return -EFAULT; - put_v4l2_pix_format(&kp->fmt, &up->fmt); return 0; } @@ -605,16 +706,16 @@ struct v4l2_input32 { /* The 64-bit v4l2_input struct has extra padding at the end of the struct. Otherwise it is identical to the 32-bit version. */ -static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) +static inline int get_v4l2_input32(struct v4l2_input __user *kp, struct v4l2_input32 __user *up) { - if (copy_from_user(kp, up, sizeof(struct v4l2_input32))) + if (copy_in_user(kp, up, sizeof(struct v4l2_input32))) return -EFAULT; return 0; } -static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) +static inline int put_v4l2_input32(struct v4l2_input __user *kp, struct v4l2_input32 __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_input32))) + if (copy_in_user(up, kp, sizeof(struct v4l2_input32))) return -EFAULT; return 0; } @@ -655,33 +756,50 @@ static inline int ctrl_is_pointer(u32 id) } } -static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int bufsize_v4l2_ext_controls32(struct v4l2_ext_controls32 __user *up) +{ + __u32 count; + + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || + get_user(count, &up->count)) + return -EFAULT; + if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; + return count * sizeof(struct v4l2_ext_control); +} + +static int get_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp, struct + v4l2_ext_controls32 __user *up, void __user *aux_buf, + int aux_space) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; - int n; + __u32 count; + unsigned int n; compat_caddr_t p; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || - get_user(kp->ctrl_class, &up->ctrl_class) || - get_user(kp->count, &up->count) || - get_user(kp->error_idx, &up->error_idx) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + convert_in_user(&up->ctrl_class, &kp->ctrl_class) || + get_user(count, &up->count) || + put_user(count, &kp->count) || + convert_in_user(&up->error_idx, &kp->error_idx) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - n = kp->count; - if (n == 0) { - kp->controls = NULL; - return 0; - } + if (count == 0) + return put_user(NULL, &kp->controls); if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); if (!access_ok(VERIFY_READ, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + count * sizeof(struct v4l2_ext_control32))) return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); - kp->controls = kcontrols; - while (--n >= 0) { + if (aux_space < count * sizeof(struct v4l2_ext_control)) + return -EFAULT; + kcontrols = aux_buf; + if (put_user((__force struct v4l2_ext_control *)kcontrols, + &kp->controls)) + return -EFAULT; + for (n = 0; n < count; n++) { if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; if (ctrl_is_pointer(kcontrols->id)) { @@ -699,30 +817,33 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return 0; } -static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int put_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp, struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols = kp->controls; - int n = kp->count; + struct v4l2_ext_control __user *kcontrols; + __u32 count; + unsigned int n; compat_caddr_t p; if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || - put_user(kp->ctrl_class, &up->ctrl_class) || - put_user(kp->count, &up->count) || - put_user(kp->error_idx, &up->error_idx) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + get_user(kcontrols, &kp->controls) || + convert_in_user(&kp->ctrl_class, &up->ctrl_class) || + get_user(count, &kp->count) || + put_user(count, &up->count) || + convert_in_user(&kp->error_idx, &up->error_idx) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; - if (!kp->count) + if (!count) return 0; if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); if (!access_ok(VERIFY_WRITE, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + count * sizeof(struct v4l2_ext_control32))) return -EFAULT; - while (--n >= 0) { + for (n = 0; n < count; n++) { unsigned size = sizeof(*ucontrols); /* Do not modify the pointer when copying a pointer control. @@ -753,16 +874,17 @@ struct v4l2_event32 { __u32 reserved[8]; }; -static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) +static int put_v4l2_event32(struct v4l2_event __user *kp, struct v4l2_event32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || - put_user(kp->type, &up->type) || - copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || - put_user(kp->pending, &up->pending) || - put_user(kp->sequence, &up->sequence) || - put_compat_timespec(&kp->timestamp, &up->timestamp) || - put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) + convert_in_user(&kp->type, &up->type) || + copy_in_user(&up->u, &kp->u, sizeof(kp->u)) || + convert_in_user(&kp->pending, &up->pending) || + convert_in_user(&kp->sequence, &up->sequence) || + convert_in_user(&kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + convert_in_user(&kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || + convert_in_user(&kp->id, &up->id) || + copy_in_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) return -EFAULT; return 0; } @@ -775,31 +897,32 @@ struct v4l2_subdev_edid32 { compat_caddr_t edid; }; -static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up) +static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid __user *kp, struct v4l2_subdev_edid32 __user *up) { - u32 tmp; + compat_uptr_t tmp; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_subdev_edid32)) || - get_user(kp->pad, &up->pad) || - get_user(kp->start_block, &up->start_block) || - get_user(kp->blocks, &up->blocks) || + convert_in_user(&up->pad, &kp->pad) || + convert_in_user(&up->start_block, &kp->start_block) || + convert_in_user(&up->blocks, &kp->blocks) || get_user(tmp, &up->edid) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + put_user(compat_ptr(tmp), &kp->edid) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - kp->edid = compat_ptr(tmp); return 0; } -static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up) +static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid __user *kp, struct v4l2_subdev_edid32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->edid); + void *edid; if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_subdev_edid32)) || - put_user(kp->pad, &up->pad) || - put_user(kp->start_block, &up->start_block) || - put_user(kp->blocks, &up->blocks) || - put_user(tmp, &up->edid) || - copy_to_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + convert_in_user(&kp->pad, &up->pad) || + convert_in_user(&kp->start_block, &up->start_block) || + convert_in_user(&kp->blocks, &up->blocks) || + get_user(edid, &kp->edid) || + put_user(ptr_to_compat(edid), &up->edid) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -832,22 +955,37 @@ static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subde #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32) +/* + * Note that these macros contain return statements to avoid the need for the + * "caller" to check return values. + */ +#define ALLOC_USER_SPACE(size) \ +({ \ + void __user *up_native; \ + up_native = compat_alloc_user_space(size); \ + if (!up_native) \ + return -ENOMEM; \ + if (clear_user(up_native, size)) \ + return -EFAULT; \ + up_native; \ +}) + +#define ALLOC_AND_GET(bufsizefunc, getfunc, structname) \ + do { \ + aux_space = bufsizefunc(up); \ + if (aux_space < 0) \ + return aux_space; \ + up_native = ALLOC_USER_SPACE(sizeof(struct structname) + aux_space); \ + aux_buf = up_native + sizeof(struct structname); \ + err = getfunc(up_native, up, aux_buf, aux_space); \ + } while (0) + static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - union { - struct v4l2_format v2f; - struct v4l2_buffer v2b; - struct v4l2_framebuffer v2fb; - struct v4l2_input v2i; - struct v4l2_standard v2s; - struct v4l2_ext_controls v2ecs; - struct v4l2_event v2ev; - struct v4l2_create_buffers v2crt; - struct v4l2_subdev_edid v2edid; - unsigned long vx; - int vi; - } karg; void __user *up = compat_ptr(arg); + void __user *up_native = NULL; + void __user *aux_buf; + int aux_space; int compatible_arg = 1; long err = 0; @@ -886,30 +1024,35 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_STREAMOFF: case VIDIOC_S_INPUT: case VIDIOC_S_OUTPUT: - err = get_user(karg.vi, (s32 __user *)up); + up_native = ALLOC_USER_SPACE(sizeof(unsigned __user)); + if (convert_in_user((compat_uint_t __user *)up, + (unsigned __user *) up_native)) + return -EFAULT; compatible_arg = 0; break; case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: + up_native = ALLOC_USER_SPACE(sizeof(unsigned __user)); compatible_arg = 0; break; case VIDIOC_SUBDEV_G_EDID: case VIDIOC_SUBDEV_S_EDID: - err = get_v4l2_subdev_edid32(&karg.v2edid, up); + up_native = ALLOC_USER_SPACE(sizeof(struct v4l2_subdev_edid)); + err = get_v4l2_subdev_edid32(up_native, up); compatible_arg = 0; break; case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = get_v4l2_format32(&karg.v2f, up); + ALLOC_AND_GET(bufsize_v4l2_format32, get_v4l2_format32, v4l2_format); compatible_arg = 0; break; case VIDIOC_CREATE_BUFS: - err = get_v4l2_create32(&karg.v2crt, up); + ALLOC_AND_GET(bufsize_v4l2_create32, get_v4l2_create32, v4l2_create_buffers); compatible_arg = 0; break; @@ -917,36 +1060,41 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = get_v4l2_buffer32(&karg.v2b, up); + ALLOC_AND_GET(bufsize_v4l2_buffer32, get_v4l2_buffer32, v4l2_buffer); compatible_arg = 0; break; case VIDIOC_S_FBUF: - err = get_v4l2_framebuffer32(&karg.v2fb, up); + up_native = ALLOC_USER_SPACE(sizeof(struct v4l2_framebuffer)); + err = get_v4l2_framebuffer32(up_native, up); compatible_arg = 0; break; case VIDIOC_G_FBUF: + up_native = ALLOC_USER_SPACE(sizeof(struct v4l2_framebuffer)); compatible_arg = 0; break; case VIDIOC_ENUMSTD: - err = get_v4l2_standard32(&karg.v2s, up); + up_native = ALLOC_USER_SPACE(sizeof(struct v4l2_standard)); + err = get_v4l2_standard32(up_native, up); compatible_arg = 0; break; case VIDIOC_ENUMINPUT: - err = get_v4l2_input32(&karg.v2i, up); + up_native = ALLOC_USER_SPACE(sizeof(struct v4l2_input)); + err = get_v4l2_input32(up_native, up); compatible_arg = 0; break; case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(&karg.v2ecs, up); + ALLOC_AND_GET(bufsize_v4l2_ext_controls32, get_v4l2_ext_controls32, v4l2_ext_controls); compatible_arg = 0; break; case VIDIOC_DQEVENT: + up_native = ALLOC_USER_SPACE(sizeof(struct v4l2_event)); compatible_arg = 0; break; } @@ -955,13 +1103,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar if (compatible_arg) err = native_ioctl(file, cmd, (unsigned long)up); - else { - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - err = native_ioctl(file, cmd, (unsigned long)&karg); - set_fs(old_fs); - } + else + err = native_ioctl(file, cmd, (unsigned long)up_native); /* Special case: even after an error we need to put the results back for these ioctls since the error_idx will @@ -970,7 +1113,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - if (put_v4l2_ext_controls32(&karg.v2ecs, up)) + if (put_v4l2_ext_controls32(up_native, up)) err = -EFAULT; break; } @@ -982,44 +1125,45 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_S_OUTPUT: case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: - err = put_user(((s32)karg.vi), (s32 __user *)up); + err = convert_in_user(((unsigned __user *)up_native), + (compat_uint_t __user *)up); break; case VIDIOC_G_FBUF: - err = put_v4l2_framebuffer32(&karg.v2fb, up); + err = put_v4l2_framebuffer32(up_native, up); break; case VIDIOC_DQEVENT: - err = put_v4l2_event32(&karg.v2ev, up); + err = put_v4l2_event32(up_native, up); break; case VIDIOC_SUBDEV_G_EDID: case VIDIOC_SUBDEV_S_EDID: - err = put_v4l2_subdev_edid32(&karg.v2edid, up); + err = put_v4l2_subdev_edid32(up_native, up); break; case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = put_v4l2_format32(&karg.v2f, up); + err = put_v4l2_format32(up_native, up); break; case VIDIOC_CREATE_BUFS: - err = put_v4l2_create32(&karg.v2crt, up); + err = put_v4l2_create32(up_native, up); break; case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = put_v4l2_buffer32(&karg.v2b, up); + err = put_v4l2_buffer32(up_native, up); break; case VIDIOC_ENUMSTD: - err = put_v4l2_standard32(&karg.v2s, up); + err = put_v4l2_standard32(up_native, up); break; case VIDIOC_ENUMINPUT: - err = put_v4l2_input32(&karg.v2i, up); + err = put_v4l2_input32(up_native, up); break; } return err; diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 5afbcb1800c2..cb6365f7f4d5 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -4680,11 +4680,21 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, int ret = 0; uint32_t reqd_len_sb_in = 0; struct sglist_info *table = data->sglistinfo_ptr; + void *req_ptr = NULL; + void *resp_ptr = NULL; ret = __qseecom_qteec_validate_msg(data, req); if (ret) return ret; + req_ptr = req->req_ptr; + resp_ptr = req->resp_ptr; + + req->req_ptr = (void *)__qseecom_uvirt_to_kvirt(data, + (uintptr_t)req->req_ptr); + req->resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data, + (uintptr_t)req->resp_ptr); + if ((cmd_id == QSEOS_TEE_OPEN_SESSION) || (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) { ret = __qseecom_update_qteec_req_buf( @@ -4700,10 +4710,10 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, ireq.qsee_cmd_id = cmd_id; ireq.app_id = data->client.app_id; ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, - (uintptr_t)req->req_ptr); + (uintptr_t)req_ptr); ireq.req_len = req->req_len; ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, - (uintptr_t)req->resp_ptr); + (uintptr_t)resp_ptr); ireq.resp_len = req->resp_len; ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table); ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE; diff --git a/drivers/platform/msm/ipa/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_qmi_service.c index 53d3a3b535d1..3383e8d5cc4d 100644 --- a/drivers/platform/msm/ipa/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_qmi_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. 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 @@ -50,6 +50,7 @@ static bool is_load_uc; static uint32_t ipa_wan_platform; struct ipa_qmi_context *ipa_qmi_ctx; static bool workqueues_stopped; +struct mutex ipa_qmi_lock; /* QMI A5 service */ @@ -494,12 +495,17 @@ int qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) req->filter_spec_list_len); } - /* cache the qmi_filter_request */ - memcpy(&(ipa_qmi_ctx->ipa_install_fltr_rule_req_msg_cache[ - ipa_qmi_ctx->num_ipa_install_fltr_rule_req_msg]), - req, sizeof(struct ipa_install_fltr_rule_req_msg_v01)); - ipa_qmi_ctx->num_ipa_install_fltr_rule_req_msg++; - ipa_qmi_ctx->num_ipa_install_fltr_rule_req_msg %= 10; + mutex_lock(&ipa_qmi_lock); + if (ipa_qmi_ctx != NULL) { + /* cache the qmi_filter_request */ + memcpy(&(ipa_qmi_ctx->ipa_install_fltr_rule_req_msg_cache[ + ipa_qmi_ctx->num_ipa_install_fltr_rule_req_msg]), + req, + sizeof(struct ipa_install_fltr_rule_req_msg_v01)); + ipa_qmi_ctx->num_ipa_install_fltr_rule_req_msg++; + ipa_qmi_ctx->num_ipa_install_fltr_rule_req_msg %= 10; + } + mutex_unlock(&ipa_qmi_lock); req_desc.max_msg_len = QMI_IPA_INSTALL_FILTER_RULE_REQ_MAX_MSG_LEN_V01; req_desc.msg_id = QMI_IPA_INSTALL_FILTER_RULE_REQ_V01; @@ -639,12 +645,17 @@ int qmi_filter_notify_send(struct ipa_fltr_installed_notif_req_msg_v01 *req) return -EINVAL; } - /* cache the qmi_filter_request */ - memcpy(&(ipa_qmi_ctx->ipa_fltr_installed_notif_req_msg_cache[ - ipa_qmi_ctx->num_ipa_fltr_installed_notif_req_msg]), - req, sizeof(struct ipa_fltr_installed_notif_req_msg_v01)); - ipa_qmi_ctx->num_ipa_fltr_installed_notif_req_msg++; - ipa_qmi_ctx->num_ipa_fltr_installed_notif_req_msg %= 10; + mutex_lock(&ipa_qmi_lock); + if (ipa_qmi_ctx != NULL) { + /* cache the qmi_filter_request */ + memcpy(&(ipa_qmi_ctx->ipa_fltr_installed_notif_req_msg_cache[ + ipa_qmi_ctx->num_ipa_fltr_installed_notif_req_msg]), + req, + sizeof(struct ipa_fltr_installed_notif_req_msg_v01)); + ipa_qmi_ctx->num_ipa_fltr_installed_notif_req_msg++; + ipa_qmi_ctx->num_ipa_fltr_installed_notif_req_msg %= 10; + } + mutex_unlock(&ipa_qmi_lock); req_desc.max_msg_len = QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_MAX_MSG_LEN_V01; @@ -979,3 +990,13 @@ void ipa_qmi_stop_workqueues(void) cancel_delayed_work(&work_svc_arrive); cancel_delayed_work(&work_svc_exit); } + +void ipa_qmi_init(void) +{ + mutex_init(&ipa_qmi_lock); +} + +void ipa_qmi_cleanup(void) +{ + mutex_destroy(&ipa_qmi_lock); +} diff --git a/drivers/platform/msm/ipa/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_qmi_service.h index 7a265a152a00..07c987767fae 100644 --- a/drivers/platform/msm/ipa/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_qmi_service.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. 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 @@ -56,6 +56,10 @@ struct rmnet_mux_val { uint32_t hdr_hdl; }; +void ipa_qmi_init(void); + +void ipa_qmi_cleanup(void); + int ipa_qmi_service_init(bool load_uc, uint32_t wan_platform_type); void ipa_qmi_service_exit(void); diff --git a/drivers/platform/msm/ipa/rmnet_ipa.c b/drivers/platform/msm/ipa/rmnet_ipa.c index 0d6fb3319469..ba5426fd0e85 100644 --- a/drivers/platform/msm/ipa/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/rmnet_ipa.c @@ -2056,6 +2056,9 @@ static int __init ipa_wwan_init(void) atomic_set(&is_initialized, 0); atomic_set(&is_ssr, 0); mutex_init(&add_mux_channel_lock); + + ipa_qmi_init(); + /* Register for Modem SSR */ subsys = subsys_notif_register_notifier(SUBSYS_MODEM, &ssr_notifier); if (!IS_ERR(subsys)) @@ -2066,6 +2069,7 @@ static int __init ipa_wwan_init(void) static void __exit ipa_wwan_cleanup(void) { + ipa_qmi_cleanup(); mutex_destroy(&add_mux_channel_lock); platform_driver_unregister(&rmnet_ipa_driver); } diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 390855c4c804..c69d7c6a1360 100755..100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -128,6 +128,7 @@ static bool get_dload_mode(void) return dload_mode_enabled; } +#if 0 static void enable_emergency_dload_mode(void) { int ret; @@ -157,6 +158,7 @@ static void enable_emergency_dload_mode(void) if (ret) pr_err("Failed to set secure EDLOAD mode: %d\n", ret); } +#endif static int dload_set(const char *val, struct kernel_param *kp) { @@ -317,8 +319,10 @@ static void msm_restart_prepare(const char *cmd) if (!ret) __raw_writel(0x6f656d00 | (code & 0xff), restart_reason); +#if 0 } else if (!strncmp(cmd, "edl", 3)) { enable_emergency_dload_mode(); +#endif } else { __raw_writel(0x77665501, restart_reason); } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 9a600f05ab57..f40dbef23c31 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -382,6 +382,9 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) struct sg_header *old_hdr = NULL; int retval = 0; + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return -EINVAL; + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n", diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 3b890ab8411f..623622e295dd 100755 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -469,7 +469,7 @@ static struct ion_handle *pass_to_user(struct ion_handle *handle) /* Must hold the client lock */ static int user_ion_handle_put_nolock(struct ion_handle *handle) { - int ret; + int ret = 0; if (--handle->user_ref_count == 0) ret = ion_handle_put_nolock(handle); diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c index fad94862c309..a82b12b3a0b8 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_edid.c +++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. 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 @@ -212,9 +212,11 @@ static ssize_t hdmi_edid_sysfs_wta_res_info(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int rc, page_id; + u32 i = 0, j, page; ssize_t ret = strnlen(buf, PAGE_SIZE); struct hdmi_edid_ctrl *edid_ctrl = hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID); + struct msm_hdmi_mode_timing_info info = {0}; if (!edid_ctrl) { DEV_ERR("%s: invalid input\n", __func__); @@ -227,7 +229,22 @@ static ssize_t hdmi_edid_sysfs_wta_res_info(struct device *dev, return rc; } - edid_ctrl->page_id = page_id; + if (page_id > MSM_HDMI_INIT_RES_PAGE) { + page = MSM_HDMI_INIT_RES_PAGE; + while (page < page_id) { + j = 1; + while (sizeof(info) * j < PAGE_SIZE) { + i++; + j++; + } + page++; + } + } + + if (i < HDMI_VFRMT_MAX) + edid_ctrl->page_id = page_id; + else + DEV_ERR("%s: invalid page id\n", __func__); DEV_DBG("%s: %d\n", __func__, edid_ctrl->page_id); return ret; diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c index 41ca5cd50044..5c6bfa77ba35 100644 --- a/drivers/video/msm/mdss/mdss_mdp_overlay.c +++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c @@ -3916,10 +3916,11 @@ static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd, ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps); break; case metadata_op_get_ion_fd: - if (mfd->fb_ion_handle) { + if (mfd->fb_ion_handle && mfd->fb_ion_client) { get_dma_buf(mfd->fbmem_buf); metadata->data.fbmem_ionfd = - dma_buf_fd(mfd->fbmem_buf, 0); + ion_share_dma_buf_fd(mfd->fb_ion_client, + mfd->fb_ion_handle); if (metadata->data.fbmem_ionfd < 0) { dma_buf_put(mfd->fbmem_buf); pr_err("fd allocation failed. fd = %d\n", diff --git a/fs/dcache.c b/fs/dcache.c index 25c0a1b5f6c0..69d12b2647ed 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -238,6 +238,43 @@ static void d_free(struct dentry *dentry) call_rcu(&dentry->d_u.d_rcu, __d_free); } +void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry) +{ + spin_lock(&dentry->d_lock); + if (unlikely(dname_external(dentry))) { + u32 len; + char *p; + + for (;;) { + len = dentry->d_name.len; + spin_unlock(&dentry->d_lock); + + p = kmalloc(len + 1, GFP_KERNEL | __GFP_NOFAIL); + + spin_lock(&dentry->d_lock); + if (dentry->d_name.len <= len) + break; + kfree(p); + } + memcpy(p, dentry->d_name.name, dentry->d_name.len + 1); + spin_unlock(&dentry->d_lock); + + name->name = p; + } else { + memcpy(name->inline_name, dentry->d_iname, DNAME_INLINE_LEN); + spin_unlock(&dentry->d_lock); + name->name = name->inline_name; + } +} +EXPORT_SYMBOL(take_dentry_name_snapshot); + +void release_dentry_name_snapshot(struct name_snapshot *name) +{ + if (unlikely(name->name != name->inline_name)) + kfree(name->name); +} +EXPORT_SYMBOL(release_dentry_name_snapshot); + /** * dentry_rcuwalk_barrier - invalidate in-progress rcu-walk lookups * @dentry: the target dentry diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 5397ca6a2097..ff066c69a376 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -602,7 +602,7 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, { int error; struct dentry *dentry = NULL, *trap; - const char *old_name; + struct name_snapshot old_name; trap = lock_rename(new_dir, old_dir); /* Source or destination directories don't exist? */ @@ -617,19 +617,19 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, if (IS_ERR(dentry) || dentry == trap || dentry->d_inode) goto exit; - old_name = fsnotify_oldname_init(old_dentry->d_name.name); + take_dentry_name_snapshot(&old_name, old_dentry); error = simple_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, dentry); if (error) { - fsnotify_oldname_free(old_name); + release_dentry_name_snapshot(&old_name); goto exit; } d_move(old_dentry, dentry); - fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name, + fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name.name, S_ISDIR(old_dentry->d_inode->i_mode), NULL, old_dentry); - fsnotify_oldname_free(old_name); + release_dentry_name_snapshot(&old_name); unlock_rename(new_dir, old_dir); dput(dentry); return old_dentry; diff --git a/fs/namei.c b/fs/namei.c index 5778b514e1c8..3d48d1193ddb 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3881,7 +3881,7 @@ int vfs_rename2(struct vfsmount *mnt, { int error; int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); - const unsigned char *old_name; + struct name_snapshot old_name; if (old_dentry->d_inode == new_dentry->d_inode) return 0; @@ -3900,16 +3900,16 @@ int vfs_rename2(struct vfsmount *mnt, if (!old_dir->i_op->rename) return -EPERM; - old_name = fsnotify_oldname_init(old_dentry->d_name.name); + take_dentry_name_snapshot(&old_name, old_dentry); if (is_dir) error = vfs_rename_dir(mnt, old_dir,old_dentry,new_dir,new_dentry); else error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); if (!error) - fsnotify_move(old_dir, new_dir, old_name, is_dir, + fsnotify_move(old_dir, new_dir, old_name.name, is_dir, new_dentry->d_inode, old_dentry); - fsnotify_oldname_free(old_name); + take_dentry_name_snapshot(&old_name, old_dentry); return error; } diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 4bb21d67d9b1..aaba571cdfb0 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -105,16 +105,20 @@ int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) if (unlikely(!fsnotify_inode_watches_children(p_inode))) __fsnotify_update_child_dentry_flags(p_inode); else if (p_inode->i_fsnotify_mask & mask) { + struct name_snapshot name; + /* we are notifying a parent so come up with the new mask which * specifies these are events which came from a child. */ mask |= FS_EVENT_ON_CHILD; + take_dentry_name_snapshot(&name, dentry); if (path) ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH, - dentry->d_name.name, 0); + name.name, 0); else ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE, - dentry->d_name.name, 0); + name.name, 0); + release_dentry_name_snapshot(&name); } dput(parent); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index df1f7093a0ab..3d34f05c189f 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -430,4 +430,11 @@ static inline bool d_is_negative(const struct dentry *dentry) extern int sysctl_vfs_cache_pressure; +struct name_snapshot { + const char *name; + char inline_name[DNAME_INLINE_LEN]; +}; +void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *); +void release_dentry_name_snapshot(struct name_snapshot *); + #endif /* __LINUX_DCACHE_H */ diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 661c0aeef1c4..bfd4c93193cb 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -310,35 +310,4 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) } } -#if defined(CONFIG_FSNOTIFY) /* notify helpers */ - -/* - * fsnotify_oldname_init - save off the old filename before we change it - */ -static inline const unsigned char *fsnotify_oldname_init(const unsigned char *name) -{ - return kstrdup(name, GFP_KERNEL); -} - -/* - * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init - */ -static inline void fsnotify_oldname_free(const unsigned char *old_name) -{ - kfree(old_name); -} - -#else /* CONFIG_FSNOTIFY */ - -static inline const char *fsnotify_oldname_init(const unsigned char *name) -{ - return NULL; -} - -static inline void fsnotify_oldname_free(const unsigned char *old_name) -{ -} - -#endif /* CONFIG_FSNOTIFY */ - #endif /* _LINUX_FS_NOTIFY_H */ diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index e430b1abcd2f..e387e6719fa2 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -32,6 +32,7 @@ #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/l2cap.h> #include <net/bluetooth/hci_core.h> #include "bnep.h" @@ -539,6 +540,9 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) BT_DBG(""); + if (!l2cap_is_socket(sock)) + return -EBADFD; + baswap((void *) dst, &bt_sk(sock->sk)->dst); baswap((void *) src, &bt_sk(sock->sk)->src); diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index e0a6ebf2baa6..84460f623fc8 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -334,6 +334,9 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) BT_DBG(""); + if (!l2cap_is_socket(sock)) + return -EBADFD; + session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL); if (!session) return -ENOMEM; diff --git a/sound/core/timer.c b/sound/core/timer.c index 0641d14bc423..2e782cc32169 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -65,6 +65,7 @@ struct snd_timer_user { int qtail; int qused; int queue_size; + bool disconnected; struct snd_timer_read *queue; struct snd_timer_tread *tqueue; spinlock_t qlock; @@ -215,11 +216,13 @@ static void snd_timer_check_master(struct snd_timer_instance *master) slave->slave_id == master->slave_id) { list_move_tail(&slave->open_list, &master->slave_list_head); spin_lock_irq(&slave_active_lock); + spin_lock(&master->timer->lock); slave->master = master; slave->timer = master->timer; if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) list_add_tail(&slave->active_list, &master->slave_active_head); + spin_unlock(&master->timer->lock); spin_unlock_irq(&slave_active_lock); } } @@ -287,6 +290,9 @@ int snd_timer_open(struct snd_timer_instance **ti, mutex_unlock(®ister_mutex); return -ENOMEM; } + /* take a card refcount for safe disconnection */ + if (timer->card) + get_device(timer->card->card_dev); timeri->slave_class = tid->dev_sclass; timeri->slave_id = slave_id; if (list_empty(&timer->open_list_head) && timer->hw.open) @@ -298,9 +304,6 @@ int snd_timer_open(struct snd_timer_instance **ti, return 0; } -static int _snd_timer_stop(struct snd_timer_instance *timeri, - int keep_flag, int event); - /* * close a timer instance */ @@ -341,19 +344,25 @@ int snd_timer_close(struct snd_timer_instance *timeri) spin_unlock_irq(&timer->lock); mutex_lock(®ister_mutex); list_del(&timeri->open_list); - if (timer && list_empty(&timer->open_list_head) && + if (list_empty(&timer->open_list_head) && timer->hw.close) timer->hw.close(timer); /* remove slave links */ + spin_lock_irq(&slave_active_lock); + spin_lock(&timer->lock); list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) { - spin_lock_irq(&slave_active_lock); - _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); list_move_tail(&slave->open_list, &snd_timer_slave_list); slave->master = NULL; slave->timer = NULL; - spin_unlock_irq(&slave_active_lock); + list_del_init(&slave->ack_list); + list_del_init(&slave->active_list); } + spin_unlock(&timer->lock); + spin_unlock_irq(&slave_active_lock); + /* release a card refcount for safe disconnection */ + if (timer->card) + put_device(timer->card->card_dev); mutex_unlock(®ister_mutex); } out: @@ -383,7 +392,6 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) static void snd_timer_notify1(struct snd_timer_instance *ti, int event) { struct snd_timer *timer; - unsigned long flags; unsigned long resolution = 0; struct snd_timer_instance *ts; struct timespec tstamp; @@ -407,97 +415,111 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) return; if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) return; - spin_lock_irqsave(&timer->lock, flags); list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) - ts->ccallback(ti, event + 100, &tstamp, resolution); - spin_unlock_irqrestore(&timer->lock, flags); + ts->ccallback(ts, event + 100, &tstamp, resolution); } -static int snd_timer_start1(struct snd_timer *timer, struct snd_timer_instance *timeri, - unsigned long sticks) +/* start/continue a master timer */ +static int snd_timer_start1(struct snd_timer_instance *timeri, + bool start, unsigned long ticks) { + struct snd_timer *timer; + int result; + unsigned long flags; + + timer = timeri->timer; + if (!timer) + return -EINVAL; + + spin_lock_irqsave(&timer->lock, flags); + if (timer->card && timer->card->shutdown) { + result = -ENODEV; + goto unlock; + } + if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | + SNDRV_TIMER_IFLG_START)) { + result = -EBUSY; + goto unlock; + } + + if (start) + timeri->ticks = timeri->cticks = ticks; + else if (!timeri->cticks) + timeri->cticks = 1; + timeri->pticks = 0; + list_move_tail(&timeri->active_list, &timer->active_list_head); if (timer->running) { if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) goto __start_now; timer->flags |= SNDRV_TIMER_FLG_RESCHED; timeri->flags |= SNDRV_TIMER_IFLG_START; - return 1; /* delayed start */ + result = 1; /* delayed start */ } else { - timer->sticks = sticks; + if (start) + timer->sticks = ticks; timer->hw.start(timer); __start_now: timer->running++; timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; - return 0; + result = 0; } + snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START : + SNDRV_TIMER_EVENT_CONTINUE); + unlock: + spin_unlock_irqrestore(&timer->lock, flags); + return result; } -static int snd_timer_start_slave(struct snd_timer_instance *timeri) +/* start/continue a slave timer */ +static int snd_timer_start_slave(struct snd_timer_instance *timeri, + bool start) { unsigned long flags; spin_lock_irqsave(&slave_active_lock, flags); + if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { + spin_unlock_irqrestore(&slave_active_lock, flags); + return -EBUSY; + } timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; - if (timeri->master) + if (timeri->master && timeri->timer) { + spin_lock(&timeri->timer->lock); list_add_tail(&timeri->active_list, &timeri->master->slave_active_head); + snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START : + SNDRV_TIMER_EVENT_CONTINUE); + spin_unlock(&timeri->timer->lock); + } spin_unlock_irqrestore(&slave_active_lock, flags); return 1; /* delayed start */ } -/* - * start the timer instance - */ -int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) -{ - struct snd_timer *timer; - int result = -EINVAL; - unsigned long flags; - - if (timeri == NULL || ticks < 1) - return -EINVAL; - if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - result = snd_timer_start_slave(timeri); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); - return result; - } - timer = timeri->timer; - if (timer == NULL) - return -EINVAL; - spin_lock_irqsave(&timer->lock, flags); - timeri->ticks = timeri->cticks = ticks; - timeri->pticks = 0; - result = snd_timer_start1(timer, timeri, ticks); - spin_unlock_irqrestore(&timer->lock, flags); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); - return result; -} - -static int _snd_timer_stop(struct snd_timer_instance * timeri, - int keep_flag, int event) +/* stop/pause a master timer */ +static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop) { struct snd_timer *timer; + int result = 0; unsigned long flags; - if (snd_BUG_ON(!timeri)) - return -ENXIO; - - if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - if (!keep_flag) { - spin_lock_irqsave(&slave_active_lock, flags); - timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; - spin_unlock_irqrestore(&slave_active_lock, flags); - } - goto __end; - } timer = timeri->timer; if (!timer) return -EINVAL; spin_lock_irqsave(&timer->lock, flags); + if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | + SNDRV_TIMER_IFLG_START))) { + result = -EBUSY; + goto unlock; + } list_del_init(&timeri->ack_list); list_del_init(&timeri->active_list); + if (timer->card && timer->card->shutdown) + goto unlock; + if (stop) { + timeri->cticks = timeri->ticks; + timeri->pticks = 0; + } if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && !(--timer->running)) { timer->hw.stop(timer); @@ -510,38 +532,61 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, } } } - if (!keep_flag) - timeri->flags &= - ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); + timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); + snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : + SNDRV_TIMER_EVENT_CONTINUE); + unlock: spin_unlock_irqrestore(&timer->lock, flags); - __end: - if (event != SNDRV_TIMER_EVENT_RESOLUTION) - snd_timer_notify1(timeri, event); + return result; +} + +/* stop/pause a slave timer */ +static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop) +{ + unsigned long flags; + + spin_lock_irqsave(&slave_active_lock, flags); + if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { + spin_unlock_irqrestore(&slave_active_lock, flags); + return -EBUSY; + } + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + if (timeri->timer) { + spin_lock(&timeri->timer->lock); + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); + snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : + SNDRV_TIMER_EVENT_CONTINUE); + spin_unlock(&timeri->timer->lock); + } + spin_unlock_irqrestore(&slave_active_lock, flags); return 0; } /* + * start the timer instance + */ +int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) +{ + if (timeri == NULL || ticks < 1) + return -EINVAL; + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) + return snd_timer_start_slave(timeri, true); + else + return snd_timer_start1(timeri, true, ticks); +} + +/* * stop the timer instance. * * do not call this from the timer callback! */ int snd_timer_stop(struct snd_timer_instance *timeri) { - struct snd_timer *timer; - unsigned long flags; - int err; - - err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP); - if (err < 0) - return err; - timer = timeri->timer; - if (!timer) - return -EINVAL; - spin_lock_irqsave(&timer->lock, flags); - timeri->cticks = timeri->ticks; - timeri->pticks = 0; - spin_unlock_irqrestore(&timer->lock, flags); - return 0; + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) + return snd_timer_stop_slave(timeri, true); + else + return snd_timer_stop1(timeri, true); } /* @@ -549,25 +594,10 @@ int snd_timer_stop(struct snd_timer_instance *timeri) */ int snd_timer_continue(struct snd_timer_instance *timeri) { - struct snd_timer *timer; - int result = -EINVAL; - unsigned long flags; - - if (timeri == NULL) - return result; if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) - return snd_timer_start_slave(timeri); - timer = timeri->timer; - if (! timer) - return -EINVAL; - spin_lock_irqsave(&timer->lock, flags); - if (!timeri->cticks) - timeri->cticks = 1; - timeri->pticks = 0; - result = snd_timer_start1(timer, timeri, timer->sticks); - spin_unlock_irqrestore(&timer->lock, flags); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); - return result; + return snd_timer_start_slave(timeri, false); + else + return snd_timer_start1(timeri, false, 0); } /* @@ -575,7 +605,10 @@ int snd_timer_continue(struct snd_timer_instance *timeri) */ int snd_timer_pause(struct snd_timer_instance * timeri) { - return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE); + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) + return snd_timer_stop_slave(timeri, false); + else + return snd_timer_stop1(timeri, false); } /* @@ -623,6 +656,9 @@ static void snd_timer_tasklet(unsigned long arg) unsigned long resolution, ticks; unsigned long flags; + if (timer->card && timer->card->shutdown) + return; + spin_lock_irqsave(&timer->lock, flags); /* now process all callbacks */ while (!list_empty(&timer->sack_list_head)) { @@ -663,6 +699,9 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) if (timer == NULL) return; + if (timer->card && timer->card->shutdown) + return; + spin_lock_irqsave(&timer->lock, flags); /* remember the current resolution */ @@ -875,11 +914,28 @@ static int snd_timer_dev_register(struct snd_device *dev) return 0; } +/* just for reference in snd_timer_dev_disconnect() below */ +static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, + int event, struct timespec *tstamp, + unsigned long resolution); + static int snd_timer_dev_disconnect(struct snd_device *device) { struct snd_timer *timer = device->device_data; + struct snd_timer_instance *ti; + mutex_lock(®ister_mutex); list_del_init(&timer->device_list); + /* wake up pending sleepers */ + list_for_each_entry(ti, &timer->open_list_head, open_list) { + /* FIXME: better to have a ti.disconnect() op */ + if (ti->ccallback == snd_timer_user_ccallback) { + struct snd_timer_user *tu = ti->callback_data; + + tu->disconnected = true; + wake_up(&tu->qchange_sleep); + } + } mutex_unlock(®ister_mutex); return 0; } @@ -890,6 +946,8 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam unsigned long resolution = 0; struct snd_timer_instance *ti, *ts; + if (timer->card && timer->card->shutdown) + return; if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) return; if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART || @@ -1050,6 +1108,8 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, mutex_lock(®ister_mutex); list_for_each_entry(timer, &snd_timer_list, device_list) { + if (timer->card && timer->card->shutdown) + continue; switch (timer->tmr_class) { case SNDRV_TIMER_CLASS_GLOBAL: snd_iprintf(buffer, "G%i: ", timer->tmr_device); @@ -1855,6 +1915,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, { struct snd_timer_user *tu; long result = 0, unit; + int qhead; int err = 0; tu = file->private_data; @@ -1867,7 +1928,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { err = -EAGAIN; - break; + goto _error; } set_current_state(TASK_INTERRUPTIBLE); @@ -1882,40 +1943,39 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, remove_wait_queue(&tu->qchange_sleep, &wait); + if (tu->disconnected) { + err = -ENODEV; + goto _error; + } if (signal_pending(current)) { err = -ERESTARTSYS; - break; + goto _error; } } + qhead = tu->qhead++; + tu->qhead %= tu->queue_size; spin_unlock_irq(&tu->qlock); - if (err < 0) - goto _error; if (tu->tread) { - if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], - sizeof(struct snd_timer_tread))) { + if (copy_to_user(buffer, &tu->tqueue[qhead], + sizeof(struct snd_timer_tread))) err = -EFAULT; - goto _error; - } } else { - if (copy_to_user(buffer, &tu->queue[tu->qhead++], - sizeof(struct snd_timer_read))) { + if (copy_to_user(buffer, &tu->queue[qhead], + sizeof(struct snd_timer_read))) err = -EFAULT; - goto _error; - } } - tu->qhead %= tu->queue_size; - - result += unit; - buffer += unit; - spin_lock_irq(&tu->qlock); tu->qused--; + if (err < 0) + goto _error; + result += unit; + buffer += unit; } - spin_unlock_irq(&tu->qlock); _error: + spin_unlock_irq(&tu->qlock); mutex_unlock(&tu->ioctl_lock); return result > 0 ? result : err; } @@ -1932,6 +1992,8 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) mask = 0; if (tu->qused) mask |= POLLIN | POLLRDNORM; + if (tu->disconnected) + mask |= POLLERR; return mask; } diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c index 2b9df4cecbdc..5b1656cba047 100644 --- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c +++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c @@ -604,7 +604,9 @@ done: return cal_block; err: kfree(cal_block->cal_info); + cal_block->cal_info = NULL; kfree(cal_block->client_info); + cal_block->client_info = NULL; kfree(cal_block); cal_block = NULL; return cal_block; |