Loading drivers/soc/qcom/hab/ghs_comm.c +21 −12 Original line number Diff line number Diff line Loading @@ -20,19 +20,28 @@ int physical_channel_read(struct physical_channel *pchan, { struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data; if (!payload || !dev->read_data) { pr_err("invalid parameters %pK %pK offset %d read %zd\n", payload, dev->read_data, dev->read_offset, read_size); return 0; } /* size in header is only for payload excluding the header itself */ if (dev->read_size < read_size + sizeof(struct hab_header)) { pr_warn("read %zd is less than requested %zd plus header %zd\n", dev->read_size, read_size, sizeof(struct hab_header)); read_size = dev->read_size; if (dev->read_size < read_size + sizeof(struct hab_header) + dev->read_offset) { pr_warn("read %zd is less than requested %zd header %zd offset %d\n", dev->read_size, read_size, sizeof(struct hab_header), dev->read_offset); read_size = dev->read_size - dev->read_offset - sizeof(struct hab_header); } /* always skip the header */ memcpy(payload, (unsigned char *)dev->read_data + sizeof(struct hab_header) + dev->read_offset, read_size); dev->read_offset += read_size; dev->read_offset += (int)read_size; return read_size; return (int)read_size; } int physical_channel_send(struct physical_channel *pchan, Loading @@ -41,8 +50,8 @@ int physical_channel_send(struct physical_channel *pchan, { size_t sizebytes = HAB_HEADER_GET_SIZE(*header); struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data; GIPC_Result result; uint8_t *msg; GIPC_Result result = GIPC_Success; uint8_t *msg = NULL; spin_lock_bh(&dev->io_lock); Loading @@ -61,7 +70,7 @@ int physical_channel_send(struct physical_channel *pchan, } if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_PROFILE) { struct timeval tv; struct timeval tv = {0}; struct habmm_xing_vm_stat *pstat = (struct habmm_xing_vm_stat *)payload; Loading Loading @@ -90,11 +99,11 @@ int physical_channel_send(struct physical_channel *pchan, void physical_channel_rx_dispatch(unsigned long physical_channel) { struct hab_header header; struct hab_header header = {0}; struct physical_channel *pchan = (struct physical_channel *)physical_channel; struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data; GIPC_Result result; GIPC_Result result = GIPC_Success; uint32_t events; unsigned long flags; Loading @@ -119,7 +128,7 @@ void physical_channel_rx_dispatch(unsigned long physical_channel) dev->read_data, GIPC_RECV_BUFF_SIZE_BYTES, &dev->read_size, &header.id_type_size); (uint32_t *)&header.id_type_size); if (result == GIPC_Success || dev->read_size > 0) { /* handle corrupted msg? */ Loading drivers/soc/qcom/hab/hab.c +153 −60 Original line number Diff line number Diff line /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2019, 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 Loading @@ -21,7 +21,7 @@ .openlock = __SPIN_LOCK_UNLOCKED(&hab_devices[__num__].openlock)\ } static const char hab_info_str[] = "Change: 17280941 Revision: #81"; static const char hab_info_str[] = "Change: 19231400 Revision: #95"; /* * The following has to match habmm definitions, order does not matter if Loading Loading @@ -60,7 +60,7 @@ struct hab_driver hab_driver = { struct uhab_context *hab_ctx_alloc(int kernel) { struct uhab_context *ctx; struct uhab_context *ctx = NULL; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) Loading @@ -79,6 +79,9 @@ struct uhab_context *hab_ctx_alloc(int kernel) rwlock_init(&ctx->exp_lock); rwlock_init(&ctx->ctx_lock); INIT_LIST_HEAD(&ctx->forbidden_chans); spin_lock_init(&ctx->forbidden_lock); INIT_LIST_HEAD(&ctx->pending_open); kref_init(&ctx->refcount); ctx->import_ctx = habmem_imp_hyp_open(); Loading Loading @@ -106,18 +109,29 @@ void hab_ctx_free(struct kref *ref) { struct uhab_context *ctx = container_of(ref, struct uhab_context, refcount); struct hab_export_ack_recvd *ack_recvd, *tmp; struct virtual_channel *vchan; struct physical_channel *pchan; int i; struct uhab_context *ctxdel, *ctxtmp; struct hab_open_node *node; struct export_desc *exp, *exp_tmp; struct hab_export_ack_recvd *ack_recvd = NULL, *tmp = NULL; struct virtual_channel *vchan = NULL; struct physical_channel *pchan = NULL; int i = 0; struct uhab_context *ctxdel = NULL, *ctxtmp = NULL; struct hab_open_node *node = NULL; struct export_desc *exp = NULL, *exp_tmp = NULL; struct hab_forbidden_node *forbidden = NULL, *forbidden_tmp = NULL; spin_lock_bh(&ctx->forbidden_lock); list_for_each_entry_safe(forbidden, forbidden_tmp, &ctx->forbidden_chans, node) { list_del(&forbidden->node); pr_debug("Remove mmid 0x%x from forbidden list, ctx %p\n", forbidden->mmid, ctx); kfree(forbidden); } spin_unlock_bh(&ctx->forbidden_lock); /* garbage-collect exp/imp buffers */ write_lock_bh(&ctx->exp_lock); list_for_each_entry_safe(exp, exp_tmp, &ctx->exp_whse, node) { list_del(&exp->node); list_del((struct list_head *)&exp->node); pr_debug("potential leak exp %d vcid %X recovered\n", exp->export_id, exp->vcid_local); habmem_hyp_revoke(exp->payload, exp->payload_count); Loading @@ -127,7 +141,7 @@ void hab_ctx_free(struct kref *ref) spin_lock_bh(&ctx->imp_lock); list_for_each_entry_safe(exp, exp_tmp, &ctx->imp_whse, node) { list_del(&exp->node); list_del((struct list_head *)&exp->node); ctx->import_total--; pr_debug("leaked imp %d vcid %X for ctx is collected total %d\n", exp->export_id, exp->vcid_local, Loading Loading @@ -211,7 +225,7 @@ void hab_ctx_free(struct kref *ref) struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, struct uhab_context *ctx, int ignore_remote) { struct virtual_channel *vchan; struct virtual_channel *vchan = NULL; read_lock(&ctx->ctx_lock); list_for_each_entry(vchan, &ctx->vchannels, node) { Loading @@ -236,7 +250,7 @@ struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, struct hab_device *find_hab_device(unsigned int mm_id) { int i; int i = 0; for (i = 0; i < hab_driver.ndevices; i++) { if (hab_driver.devp[i].id == HAB_MMID_GET_MAJOR(mm_id)) Loading @@ -259,13 +273,13 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx, unsigned int mm_id, int dom_id) { int ret, ret2, open_id = 0; int ret = 0, ret2 = 0, open_id = 0; struct physical_channel *pchan = NULL; struct hab_device *dev; struct hab_device *dev = NULL; struct virtual_channel *vchan = NULL; static atomic_t open_id_counter = ATOMIC_INIT(0); struct hab_open_request request; struct hab_open_request *recv_request; struct hab_open_request request = {0}; struct hab_open_request *recv_request = NULL; int sub_id = HAB_MMID_GET_MINOR(mm_id); struct hab_open_node pending_open = { { 0 } }; Loading @@ -284,7 +298,7 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx, goto err; } open_id = atomic_inc_return(&open_id_counter); open_id = (int)atomic_inc_return(&open_id_counter); vchan = hab_vchan_alloc(ctx, pchan, open_id); if (!vchan) { pr_err("vchan alloc failed\n"); Loading Loading @@ -336,7 +350,7 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx, vchan->id); hab_open_pending_exit(ctx, pchan, &pending_open); if (ret != -EINTR) if (ret != -EINTR && ret != -ENXIO) ret = -EINVAL; goto err; } Loading Loading @@ -377,15 +391,15 @@ err: struct virtual_channel *backend_listen(struct uhab_context *ctx, unsigned int mm_id, int timeout) { int ret, ret2; int open_id, ver_fe; int ret = 0, ret2 = 0; int open_id = 0, ver_fe = 0; int sub_id = HAB_MMID_GET_MINOR(mm_id); struct physical_channel *pchan = NULL; struct hab_device *dev; struct hab_device *dev = NULL; struct virtual_channel *vchan = NULL; struct hab_open_request request; struct hab_open_request *recv_request; uint32_t otherend_vchan_id; struct hab_open_request request = {0}; struct hab_open_request *recv_request = NULL; uint32_t otherend_vchan_id = 0; struct hab_open_node pending_open = { { 0 } }; dev = find_hab_device(mm_id); Loading @@ -407,6 +421,8 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx, ret = -EINVAL; if (-EAGAIN == ret) { ret = -ETIMEDOUT; } else if (-ENXIO == ret) { pr_warn("open request canceling\n"); } else { /* device is closed */ pr_err("open request wait failed ctx closing %d\n", Loading @@ -416,7 +432,7 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx, } else if (!ret && recv_request && ((recv_request->xdata.ver_fe & 0xFFFF0000) != (HAB_API_VER & 0xFFFF0000))) { int ret2; int ret2 = 0; /* version check */ pr_err("version mismatch fe %X be %X on mmid %d\n", recv_request->xdata.ver_fe, HAB_API_VER, mm_id); Loading Loading @@ -467,11 +483,11 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx, hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT_DONE, pchan, 0, sub_id, open_id); ret = hab_open_listen(ctx, dev, &request, &recv_request, HAB_HS_TIMEOUT); HAB_HS_INIT_DONE_TIMEOUT); hab_open_pending_exit(ctx, pchan, &pending_open); if (ret && recv_request && if (!ret && recv_request && recv_request->type == HAB_PAYLOAD_TYPE_INIT_CANCEL) { pr_err("listen cancelled vcid %x subid %d openid %d ret %d\n", pr_warn("open rmt cancelled vcid %x subid %d openid %d ret %d\n", request.xdata.vchan_id, request.xdata.sub_id, request.xdata.open_id, ret); Loading @@ -487,9 +503,12 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx, ret2, vchan->id); hab_open_pending_exit(ctx, pchan, &pending_open); ret = -ENODEV; /* open request cancelled remotely */ ret = -ENODEV; /* open request FE cancelled remotely */ break; } else if (ret != -EAGAIN) { } else if (-ENXIO == ret) { pr_warn("backend mmid %d listen canceling\n", mm_id); goto err; } else if (ret != -EAGAIN && ret != -EINTR) { hab_open_pending_exit(ctx, pchan, &pending_open); break; /* received something. good case! */ } Loading Loading @@ -540,8 +559,8 @@ long hab_vchan_send(struct uhab_context *ctx, void *data, unsigned int flags) { struct virtual_channel *vchan; int ret; struct virtual_channel *vchan = NULL; int ret = 0; struct hab_header header = HAB_HEADER_INITIALIZER; int nonblocking_flag = flags & HABMM_SOCKET_SEND_FLAGS_NON_BLOCKING; Loading @@ -557,7 +576,7 @@ long hab_vchan_send(struct uhab_context *ctx, goto err; } HAB_HEADER_SET_SIZE(header, sizebytes); HAB_HEADER_SET_SIZE(header, (uint32_t)sizebytes); if (flags & HABMM_SOCKET_SEND_FLAGS_XING_VM_STAT) { HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_PROFILE); if (sizebytes < sizeof(struct habmm_xing_vm_stat)) { Loading Loading @@ -602,11 +621,11 @@ int hab_vchan_recv(struct uhab_context *ctx, int *rsize, unsigned int flags) { struct virtual_channel *vchan; struct virtual_channel *vchan = NULL; int ret = 0; int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING; vchan = hab_get_vchan_fromvcid(vcid, ctx, 1); vchan = hab_get_vchan_fromvcid(vcid, ctx, 1); /* to drain local q */ if (!vchan) { pr_err("vcid %X vchan 0x%pK ctx %pK\n", vcid, vchan, ctx); return -ENODEV; Loading Loading @@ -640,6 +659,68 @@ bool hab_is_loopback(void) return hab_driver.b_loopback; } static int hab_stop(struct uhab_context *ctx, unsigned int mmid) { struct hab_forbidden_node *node = NULL, *tmp = NULL; struct hab_device *dev = NULL; dev = find_hab_device(mmid); if (dev == NULL) { pr_err("failed to find dev based on id 0x%x\n", mmid); return -EINVAL; } spin_lock_bh(&ctx->forbidden_lock); list_for_each_entry_safe(node, tmp, &ctx->forbidden_chans, node) { if (node->mmid == mmid) { pr_info("mmid 0x%x has been in forbidden list, ctx %p\n", mmid, ctx); spin_unlock_bh(&ctx->forbidden_lock); return 0; } } pr_info("Add mmid 0x%x into forbidden list, ctx %p\n", mmid, ctx); node = kzalloc(sizeof(*node), GFP_ATOMIC); if (!node) { spin_unlock_bh(&ctx->forbidden_lock); return -ENOMEM; } node->mmid = mmid; list_add_tail(&node->node, &ctx->forbidden_chans); spin_unlock_bh(&ctx->forbidden_lock); wake_up_interruptible(&dev->openq); return 0; } int hab_is_forbidden(struct uhab_context *ctx, struct hab_device *dev, uint32_t sub_id) { struct hab_forbidden_node *node = NULL, *tmp = NULL; if (!dev) return 0; spin_lock_bh(&ctx->forbidden_lock); list_for_each_entry_safe(node, tmp, &ctx->forbidden_chans, node) { if ((HAB_MMID_GET_MAJOR(node->mmid) == dev->id) && (HAB_MMID_GET_MINOR(node->mmid) == sub_id)) { spin_unlock_bh(&ctx->forbidden_lock); return 1; } } spin_unlock_bh(&ctx->forbidden_lock); return 0; } int hab_vchan_open(struct uhab_context *ctx, unsigned int mmid, int32_t *vcid, Loading @@ -647,8 +728,9 @@ int hab_vchan_open(struct uhab_context *ctx, uint32_t flags) { struct virtual_channel *vchan = NULL; struct hab_device *dev; struct hab_device *dev = NULL; (void)flags; pr_debug("Open mmid=%d, loopback mode=%d, loopback be ctx %d\n", mmid, hab_driver.b_loopback, ctx->lb_be); Loading @@ -664,6 +746,13 @@ int hab_vchan_open(struct uhab_context *ctx, } else { dev = find_hab_device(mmid); if (hab_is_forbidden(ctx, dev, HAB_MMID_GET_MINOR(mmid))) { pr_err("mmid 0x%x has been forbidden", mmid); return -ENXIO; } if (dev) { struct physical_channel *pchan = hab_pchan_find_domid(dev, Loading @@ -689,7 +778,7 @@ int hab_vchan_open(struct uhab_context *ctx, if (IS_ERR(vchan)) { if (-ETIMEDOUT != PTR_ERR(vchan) && -EAGAIN != PTR_ERR(vchan)) pr_err("vchan open failed mmid=%d\n", mmid); return PTR_ERR(vchan); return (int)PTR_ERR(vchan); } pr_debug("vchan id %x remote id %x session %d\n", vchan->id, Loading Loading @@ -720,7 +809,8 @@ void hab_send_close_msg(struct virtual_channel *vchan) void hab_vchan_close(struct uhab_context *ctx, int32_t vcid) { struct virtual_channel *vchan, *tmp; struct virtual_channel *vchan = NULL, *tmp = NULL; int vchan_found = 0; if (!ctx) return; Loading @@ -744,10 +834,14 @@ void hab_vchan_close(struct uhab_context *ctx, int32_t vcid) hab_vchan_stop_notify(vchan); hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); vchan_found = 1; break; } } write_unlock(&ctx->ctx_lock); if (!vchan_found) hab_stop(ctx, vcid); } /* Loading @@ -760,9 +854,9 @@ void hab_vchan_close(struct uhab_context *ctx, int32_t vcid) static int hab_initialize_pchan_entry(struct hab_device *mmid_device, int vmid_local, int vmid_remote, int is_be) { char pchan_name[MAX_VMID_NAME_SIZE]; char pchan_name[MAX_VMID_NAME_SIZE] = {0}; struct physical_channel *pchan = NULL; int ret; int ret = 0; int vmid = is_be ? vmid_remote : vmid_local; /* used for naming only */ if (!mmid_device) { Loading Loading @@ -799,7 +893,7 @@ static int hab_initialize_pchan_entry(struct hab_device *mmid_device, */ static int hab_generate_pchan(struct local_vmid *settings, int i, int j) { int k, ret = 0; int k = 0, ret = 0; pr_debug("%d as mmid %d in vmid %d\n", HABCFG_GET_MMID(settings, i, j), j, i); Loading Loading @@ -922,13 +1016,13 @@ static int hab_generate_pchan(struct local_vmid *settings, int i, int j) */ static int hab_generate_pchan_list(struct local_vmid *settings) { int i, j, ret = 0; int i = 0, j = 0, ret = 0; /* scan by valid VMs, then mmid */ pr_debug("self vmid is %d\n", settings->self); for (i = 0; i < HABCFG_VMID_MAX; i++) { if (HABCFG_GET_VMID(settings, i) != HABCFG_VMID_INVALID && HABCFG_GET_VMID(settings, i) != settings->self) { if (HABCFG_GET_VMID(settings, i) != HABCFG_VMID_INVALID && HABCFG_GET_VMID(settings, i) != settings->self) { pr_debug("create pchans for vm %d\n", i); for (j = 1; j <= HABCFG_MMID_AREA_MAX; j++) { Loading @@ -954,9 +1048,9 @@ static int hab_generate_pchan_list(struct local_vmid *settings) int do_hab_parse(void) { int result; int i; struct hab_device *device; int result = 0; int i = 0; struct hab_device *device = NULL; /* single GVM is 2, multigvm is 2 or 3. GHS LV-GVM 2, LA-GVM 3 */ int default_gvmid = DEFAULT_GVMID; Loading @@ -966,7 +1060,8 @@ int do_hab_parse(void) /* first check if hypervisor plug-in is ready */ result = hab_hypervisor_register(); if (result) { pr_err("register HYP plug-in failed, ret %d\n", result); pr_err("register HYP plug-in failed, ret %d driver version %s\n", result, hab_info_str); return result; } Loading Loading @@ -1014,13 +1109,13 @@ int get_refcnt(struct kref ref) void hab_hypervisor_unregister_common(void) { int status, i; struct uhab_context *ctx; struct virtual_channel *vchan; int status = 0, i = 0; struct uhab_context *ctx = NULL; struct virtual_channel *vchan = NULL; for (i = 0; i < hab_driver.ndevices; i++) { struct hab_device *habdev = &hab_driver.devp[i]; struct physical_channel *pchan, *pchan_tmp; struct physical_channel *pchan = NULL, *pchan_tmp = NULL; list_for_each_entry_safe(pchan, pchan_tmp, &habdev->pchannels, node) { Loading Loading @@ -1194,13 +1289,11 @@ static long hab_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) recv_param->sizebytes = 0; ret = -EFAULT; } } else if (ret && msg) { pr_warn("vcid %X recv failed %d and msg is still of %zd bytes\n", recv_param->vcid, (int)ret, msg->sizebytes); } if (msg) hab_msg_free(msg); } else pr_warn("vcid %X recv failed %d buf size %d\n", recv_param->vcid, (int)ret, recv_param->sizebytes); break; case IOCTL_HAB_VC_EXPORT: ret = hab_mem_export(ctx, (struct hab_export *)data, 0); Loading drivers/soc/qcom/hab/hab.h +17 −4 Original line number Diff line number Diff line /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2019, 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 Loading Loading @@ -46,6 +46,7 @@ #include <linux/kobject.h> #include <linux/sysfs.h> #include <linux/delay.h> #include <linux/version.h> #include <soc/qcom/boot_stats.h> enum hab_payload_type { Loading Loading @@ -161,13 +162,13 @@ struct hab_header { #define HAB_HEADER_SET_SIZE(header, size) \ ((header).id_type_size = ((header).id_type_size & \ (~HAB_HEADER_SIZE_MASK)) | \ (uint32_t)(~HAB_HEADER_SIZE_MASK)) | \ (((size) << HAB_HEADER_SIZE_SHIFT) & \ HAB_HEADER_SIZE_MASK)) #define HAB_HEADER_SET_TYPE(header, type) \ ((header).id_type_size = ((header).id_type_size & \ (~HAB_HEADER_TYPE_MASK)) | \ (uint32_t)(~HAB_HEADER_TYPE_MASK)) | \ (((type) << HAB_HEADER_TYPE_SHIFT) & \ HAB_HEADER_TYPE_MASK)) Loading @@ -192,6 +193,7 @@ struct hab_header { #define HAB_HEADER_GET_SESSION_ID(header) ((header).session_id) #define HAB_HS_TIMEOUT (10*1000*1000) #define HAB_HS_INIT_DONE_TIMEOUT (3*1000) struct physical_channel { struct list_head node; Loading Loading @@ -265,6 +267,11 @@ struct hab_message { uint32_t data[]; }; struct hab_forbidden_node { struct list_head node; uint32_t mmid; }; /* for all the pchans of same kind */ struct hab_device { char name[MAX_VMID_NAME_SIZE]; Loading Loading @@ -302,6 +309,9 @@ struct uhab_context { struct list_head pending_open; /* sent to remote */ int pending_cnt; struct list_head forbidden_chans; spinlock_t forbidden_lock; rwlock_t ctx_lock; int closing; int kernel; Loading Loading @@ -403,6 +413,9 @@ struct export_desc { unsigned char payload[1]; } __packed; int hab_is_forbidden(struct uhab_context *ctx, struct hab_device *dev, uint32_t sub_id); int hab_vchan_open(struct uhab_context *ctx, unsigned int mmid, int32_t *vcid, int32_t timeout, uint32_t flags); Loading Loading @@ -521,7 +534,7 @@ static inline void hab_ctx_get(struct uhab_context *ctx) static inline void hab_ctx_put(struct uhab_context *ctx) { if (ctx) kref_put(&ctx->refcount, hab_ctx_free); kref_put(&ctx->refcount, &hab_ctx_free); } void hab_send_close_msg(struct virtual_channel *vchan); Loading drivers/soc/qcom/hab/hab_ghs.c +2 −2 Original line number Diff line number Diff line /* Copyright (c) 2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2018-2019, 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 Loading Loading @@ -93,7 +93,7 @@ static int get_dt_name_idx(int vmid_base, int mmid, struct ghs_vmm_plugin_info_s *plugin_info) { int idx = -1; int i; int i = 0; if (vmid_base < 0 || vmid_base > plugin_info->probe_cnt / GIPC_VM_SET_CNT) { Loading drivers/soc/qcom/hab/hab_mem_linux.c +3 −0 Original line number Diff line number Diff line Loading @@ -598,6 +598,9 @@ static int hab_mem_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) vma->vm_private_data = pglist; vma->vm_flags |= VM_MIXEDMAP; if (!(pglist->userflags & HABMM_IMPORT_FLAGS_CACHED)) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); return 0; } Loading Loading
drivers/soc/qcom/hab/ghs_comm.c +21 −12 Original line number Diff line number Diff line Loading @@ -20,19 +20,28 @@ int physical_channel_read(struct physical_channel *pchan, { struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data; if (!payload || !dev->read_data) { pr_err("invalid parameters %pK %pK offset %d read %zd\n", payload, dev->read_data, dev->read_offset, read_size); return 0; } /* size in header is only for payload excluding the header itself */ if (dev->read_size < read_size + sizeof(struct hab_header)) { pr_warn("read %zd is less than requested %zd plus header %zd\n", dev->read_size, read_size, sizeof(struct hab_header)); read_size = dev->read_size; if (dev->read_size < read_size + sizeof(struct hab_header) + dev->read_offset) { pr_warn("read %zd is less than requested %zd header %zd offset %d\n", dev->read_size, read_size, sizeof(struct hab_header), dev->read_offset); read_size = dev->read_size - dev->read_offset - sizeof(struct hab_header); } /* always skip the header */ memcpy(payload, (unsigned char *)dev->read_data + sizeof(struct hab_header) + dev->read_offset, read_size); dev->read_offset += read_size; dev->read_offset += (int)read_size; return read_size; return (int)read_size; } int physical_channel_send(struct physical_channel *pchan, Loading @@ -41,8 +50,8 @@ int physical_channel_send(struct physical_channel *pchan, { size_t sizebytes = HAB_HEADER_GET_SIZE(*header); struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data; GIPC_Result result; uint8_t *msg; GIPC_Result result = GIPC_Success; uint8_t *msg = NULL; spin_lock_bh(&dev->io_lock); Loading @@ -61,7 +70,7 @@ int physical_channel_send(struct physical_channel *pchan, } if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_PROFILE) { struct timeval tv; struct timeval tv = {0}; struct habmm_xing_vm_stat *pstat = (struct habmm_xing_vm_stat *)payload; Loading Loading @@ -90,11 +99,11 @@ int physical_channel_send(struct physical_channel *pchan, void physical_channel_rx_dispatch(unsigned long physical_channel) { struct hab_header header; struct hab_header header = {0}; struct physical_channel *pchan = (struct physical_channel *)physical_channel; struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data; GIPC_Result result; GIPC_Result result = GIPC_Success; uint32_t events; unsigned long flags; Loading @@ -119,7 +128,7 @@ void physical_channel_rx_dispatch(unsigned long physical_channel) dev->read_data, GIPC_RECV_BUFF_SIZE_BYTES, &dev->read_size, &header.id_type_size); (uint32_t *)&header.id_type_size); if (result == GIPC_Success || dev->read_size > 0) { /* handle corrupted msg? */ Loading
drivers/soc/qcom/hab/hab.c +153 −60 Original line number Diff line number Diff line /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2019, 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 Loading @@ -21,7 +21,7 @@ .openlock = __SPIN_LOCK_UNLOCKED(&hab_devices[__num__].openlock)\ } static const char hab_info_str[] = "Change: 17280941 Revision: #81"; static const char hab_info_str[] = "Change: 19231400 Revision: #95"; /* * The following has to match habmm definitions, order does not matter if Loading Loading @@ -60,7 +60,7 @@ struct hab_driver hab_driver = { struct uhab_context *hab_ctx_alloc(int kernel) { struct uhab_context *ctx; struct uhab_context *ctx = NULL; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) Loading @@ -79,6 +79,9 @@ struct uhab_context *hab_ctx_alloc(int kernel) rwlock_init(&ctx->exp_lock); rwlock_init(&ctx->ctx_lock); INIT_LIST_HEAD(&ctx->forbidden_chans); spin_lock_init(&ctx->forbidden_lock); INIT_LIST_HEAD(&ctx->pending_open); kref_init(&ctx->refcount); ctx->import_ctx = habmem_imp_hyp_open(); Loading Loading @@ -106,18 +109,29 @@ void hab_ctx_free(struct kref *ref) { struct uhab_context *ctx = container_of(ref, struct uhab_context, refcount); struct hab_export_ack_recvd *ack_recvd, *tmp; struct virtual_channel *vchan; struct physical_channel *pchan; int i; struct uhab_context *ctxdel, *ctxtmp; struct hab_open_node *node; struct export_desc *exp, *exp_tmp; struct hab_export_ack_recvd *ack_recvd = NULL, *tmp = NULL; struct virtual_channel *vchan = NULL; struct physical_channel *pchan = NULL; int i = 0; struct uhab_context *ctxdel = NULL, *ctxtmp = NULL; struct hab_open_node *node = NULL; struct export_desc *exp = NULL, *exp_tmp = NULL; struct hab_forbidden_node *forbidden = NULL, *forbidden_tmp = NULL; spin_lock_bh(&ctx->forbidden_lock); list_for_each_entry_safe(forbidden, forbidden_tmp, &ctx->forbidden_chans, node) { list_del(&forbidden->node); pr_debug("Remove mmid 0x%x from forbidden list, ctx %p\n", forbidden->mmid, ctx); kfree(forbidden); } spin_unlock_bh(&ctx->forbidden_lock); /* garbage-collect exp/imp buffers */ write_lock_bh(&ctx->exp_lock); list_for_each_entry_safe(exp, exp_tmp, &ctx->exp_whse, node) { list_del(&exp->node); list_del((struct list_head *)&exp->node); pr_debug("potential leak exp %d vcid %X recovered\n", exp->export_id, exp->vcid_local); habmem_hyp_revoke(exp->payload, exp->payload_count); Loading @@ -127,7 +141,7 @@ void hab_ctx_free(struct kref *ref) spin_lock_bh(&ctx->imp_lock); list_for_each_entry_safe(exp, exp_tmp, &ctx->imp_whse, node) { list_del(&exp->node); list_del((struct list_head *)&exp->node); ctx->import_total--; pr_debug("leaked imp %d vcid %X for ctx is collected total %d\n", exp->export_id, exp->vcid_local, Loading Loading @@ -211,7 +225,7 @@ void hab_ctx_free(struct kref *ref) struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, struct uhab_context *ctx, int ignore_remote) { struct virtual_channel *vchan; struct virtual_channel *vchan = NULL; read_lock(&ctx->ctx_lock); list_for_each_entry(vchan, &ctx->vchannels, node) { Loading @@ -236,7 +250,7 @@ struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, struct hab_device *find_hab_device(unsigned int mm_id) { int i; int i = 0; for (i = 0; i < hab_driver.ndevices; i++) { if (hab_driver.devp[i].id == HAB_MMID_GET_MAJOR(mm_id)) Loading @@ -259,13 +273,13 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx, unsigned int mm_id, int dom_id) { int ret, ret2, open_id = 0; int ret = 0, ret2 = 0, open_id = 0; struct physical_channel *pchan = NULL; struct hab_device *dev; struct hab_device *dev = NULL; struct virtual_channel *vchan = NULL; static atomic_t open_id_counter = ATOMIC_INIT(0); struct hab_open_request request; struct hab_open_request *recv_request; struct hab_open_request request = {0}; struct hab_open_request *recv_request = NULL; int sub_id = HAB_MMID_GET_MINOR(mm_id); struct hab_open_node pending_open = { { 0 } }; Loading @@ -284,7 +298,7 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx, goto err; } open_id = atomic_inc_return(&open_id_counter); open_id = (int)atomic_inc_return(&open_id_counter); vchan = hab_vchan_alloc(ctx, pchan, open_id); if (!vchan) { pr_err("vchan alloc failed\n"); Loading Loading @@ -336,7 +350,7 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx, vchan->id); hab_open_pending_exit(ctx, pchan, &pending_open); if (ret != -EINTR) if (ret != -EINTR && ret != -ENXIO) ret = -EINVAL; goto err; } Loading Loading @@ -377,15 +391,15 @@ err: struct virtual_channel *backend_listen(struct uhab_context *ctx, unsigned int mm_id, int timeout) { int ret, ret2; int open_id, ver_fe; int ret = 0, ret2 = 0; int open_id = 0, ver_fe = 0; int sub_id = HAB_MMID_GET_MINOR(mm_id); struct physical_channel *pchan = NULL; struct hab_device *dev; struct hab_device *dev = NULL; struct virtual_channel *vchan = NULL; struct hab_open_request request; struct hab_open_request *recv_request; uint32_t otherend_vchan_id; struct hab_open_request request = {0}; struct hab_open_request *recv_request = NULL; uint32_t otherend_vchan_id = 0; struct hab_open_node pending_open = { { 0 } }; dev = find_hab_device(mm_id); Loading @@ -407,6 +421,8 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx, ret = -EINVAL; if (-EAGAIN == ret) { ret = -ETIMEDOUT; } else if (-ENXIO == ret) { pr_warn("open request canceling\n"); } else { /* device is closed */ pr_err("open request wait failed ctx closing %d\n", Loading @@ -416,7 +432,7 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx, } else if (!ret && recv_request && ((recv_request->xdata.ver_fe & 0xFFFF0000) != (HAB_API_VER & 0xFFFF0000))) { int ret2; int ret2 = 0; /* version check */ pr_err("version mismatch fe %X be %X on mmid %d\n", recv_request->xdata.ver_fe, HAB_API_VER, mm_id); Loading Loading @@ -467,11 +483,11 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx, hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT_DONE, pchan, 0, sub_id, open_id); ret = hab_open_listen(ctx, dev, &request, &recv_request, HAB_HS_TIMEOUT); HAB_HS_INIT_DONE_TIMEOUT); hab_open_pending_exit(ctx, pchan, &pending_open); if (ret && recv_request && if (!ret && recv_request && recv_request->type == HAB_PAYLOAD_TYPE_INIT_CANCEL) { pr_err("listen cancelled vcid %x subid %d openid %d ret %d\n", pr_warn("open rmt cancelled vcid %x subid %d openid %d ret %d\n", request.xdata.vchan_id, request.xdata.sub_id, request.xdata.open_id, ret); Loading @@ -487,9 +503,12 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx, ret2, vchan->id); hab_open_pending_exit(ctx, pchan, &pending_open); ret = -ENODEV; /* open request cancelled remotely */ ret = -ENODEV; /* open request FE cancelled remotely */ break; } else if (ret != -EAGAIN) { } else if (-ENXIO == ret) { pr_warn("backend mmid %d listen canceling\n", mm_id); goto err; } else if (ret != -EAGAIN && ret != -EINTR) { hab_open_pending_exit(ctx, pchan, &pending_open); break; /* received something. good case! */ } Loading Loading @@ -540,8 +559,8 @@ long hab_vchan_send(struct uhab_context *ctx, void *data, unsigned int flags) { struct virtual_channel *vchan; int ret; struct virtual_channel *vchan = NULL; int ret = 0; struct hab_header header = HAB_HEADER_INITIALIZER; int nonblocking_flag = flags & HABMM_SOCKET_SEND_FLAGS_NON_BLOCKING; Loading @@ -557,7 +576,7 @@ long hab_vchan_send(struct uhab_context *ctx, goto err; } HAB_HEADER_SET_SIZE(header, sizebytes); HAB_HEADER_SET_SIZE(header, (uint32_t)sizebytes); if (flags & HABMM_SOCKET_SEND_FLAGS_XING_VM_STAT) { HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_PROFILE); if (sizebytes < sizeof(struct habmm_xing_vm_stat)) { Loading Loading @@ -602,11 +621,11 @@ int hab_vchan_recv(struct uhab_context *ctx, int *rsize, unsigned int flags) { struct virtual_channel *vchan; struct virtual_channel *vchan = NULL; int ret = 0; int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING; vchan = hab_get_vchan_fromvcid(vcid, ctx, 1); vchan = hab_get_vchan_fromvcid(vcid, ctx, 1); /* to drain local q */ if (!vchan) { pr_err("vcid %X vchan 0x%pK ctx %pK\n", vcid, vchan, ctx); return -ENODEV; Loading Loading @@ -640,6 +659,68 @@ bool hab_is_loopback(void) return hab_driver.b_loopback; } static int hab_stop(struct uhab_context *ctx, unsigned int mmid) { struct hab_forbidden_node *node = NULL, *tmp = NULL; struct hab_device *dev = NULL; dev = find_hab_device(mmid); if (dev == NULL) { pr_err("failed to find dev based on id 0x%x\n", mmid); return -EINVAL; } spin_lock_bh(&ctx->forbidden_lock); list_for_each_entry_safe(node, tmp, &ctx->forbidden_chans, node) { if (node->mmid == mmid) { pr_info("mmid 0x%x has been in forbidden list, ctx %p\n", mmid, ctx); spin_unlock_bh(&ctx->forbidden_lock); return 0; } } pr_info("Add mmid 0x%x into forbidden list, ctx %p\n", mmid, ctx); node = kzalloc(sizeof(*node), GFP_ATOMIC); if (!node) { spin_unlock_bh(&ctx->forbidden_lock); return -ENOMEM; } node->mmid = mmid; list_add_tail(&node->node, &ctx->forbidden_chans); spin_unlock_bh(&ctx->forbidden_lock); wake_up_interruptible(&dev->openq); return 0; } int hab_is_forbidden(struct uhab_context *ctx, struct hab_device *dev, uint32_t sub_id) { struct hab_forbidden_node *node = NULL, *tmp = NULL; if (!dev) return 0; spin_lock_bh(&ctx->forbidden_lock); list_for_each_entry_safe(node, tmp, &ctx->forbidden_chans, node) { if ((HAB_MMID_GET_MAJOR(node->mmid) == dev->id) && (HAB_MMID_GET_MINOR(node->mmid) == sub_id)) { spin_unlock_bh(&ctx->forbidden_lock); return 1; } } spin_unlock_bh(&ctx->forbidden_lock); return 0; } int hab_vchan_open(struct uhab_context *ctx, unsigned int mmid, int32_t *vcid, Loading @@ -647,8 +728,9 @@ int hab_vchan_open(struct uhab_context *ctx, uint32_t flags) { struct virtual_channel *vchan = NULL; struct hab_device *dev; struct hab_device *dev = NULL; (void)flags; pr_debug("Open mmid=%d, loopback mode=%d, loopback be ctx %d\n", mmid, hab_driver.b_loopback, ctx->lb_be); Loading @@ -664,6 +746,13 @@ int hab_vchan_open(struct uhab_context *ctx, } else { dev = find_hab_device(mmid); if (hab_is_forbidden(ctx, dev, HAB_MMID_GET_MINOR(mmid))) { pr_err("mmid 0x%x has been forbidden", mmid); return -ENXIO; } if (dev) { struct physical_channel *pchan = hab_pchan_find_domid(dev, Loading @@ -689,7 +778,7 @@ int hab_vchan_open(struct uhab_context *ctx, if (IS_ERR(vchan)) { if (-ETIMEDOUT != PTR_ERR(vchan) && -EAGAIN != PTR_ERR(vchan)) pr_err("vchan open failed mmid=%d\n", mmid); return PTR_ERR(vchan); return (int)PTR_ERR(vchan); } pr_debug("vchan id %x remote id %x session %d\n", vchan->id, Loading Loading @@ -720,7 +809,8 @@ void hab_send_close_msg(struct virtual_channel *vchan) void hab_vchan_close(struct uhab_context *ctx, int32_t vcid) { struct virtual_channel *vchan, *tmp; struct virtual_channel *vchan = NULL, *tmp = NULL; int vchan_found = 0; if (!ctx) return; Loading @@ -744,10 +834,14 @@ void hab_vchan_close(struct uhab_context *ctx, int32_t vcid) hab_vchan_stop_notify(vchan); hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); vchan_found = 1; break; } } write_unlock(&ctx->ctx_lock); if (!vchan_found) hab_stop(ctx, vcid); } /* Loading @@ -760,9 +854,9 @@ void hab_vchan_close(struct uhab_context *ctx, int32_t vcid) static int hab_initialize_pchan_entry(struct hab_device *mmid_device, int vmid_local, int vmid_remote, int is_be) { char pchan_name[MAX_VMID_NAME_SIZE]; char pchan_name[MAX_VMID_NAME_SIZE] = {0}; struct physical_channel *pchan = NULL; int ret; int ret = 0; int vmid = is_be ? vmid_remote : vmid_local; /* used for naming only */ if (!mmid_device) { Loading Loading @@ -799,7 +893,7 @@ static int hab_initialize_pchan_entry(struct hab_device *mmid_device, */ static int hab_generate_pchan(struct local_vmid *settings, int i, int j) { int k, ret = 0; int k = 0, ret = 0; pr_debug("%d as mmid %d in vmid %d\n", HABCFG_GET_MMID(settings, i, j), j, i); Loading Loading @@ -922,13 +1016,13 @@ static int hab_generate_pchan(struct local_vmid *settings, int i, int j) */ static int hab_generate_pchan_list(struct local_vmid *settings) { int i, j, ret = 0; int i = 0, j = 0, ret = 0; /* scan by valid VMs, then mmid */ pr_debug("self vmid is %d\n", settings->self); for (i = 0; i < HABCFG_VMID_MAX; i++) { if (HABCFG_GET_VMID(settings, i) != HABCFG_VMID_INVALID && HABCFG_GET_VMID(settings, i) != settings->self) { if (HABCFG_GET_VMID(settings, i) != HABCFG_VMID_INVALID && HABCFG_GET_VMID(settings, i) != settings->self) { pr_debug("create pchans for vm %d\n", i); for (j = 1; j <= HABCFG_MMID_AREA_MAX; j++) { Loading @@ -954,9 +1048,9 @@ static int hab_generate_pchan_list(struct local_vmid *settings) int do_hab_parse(void) { int result; int i; struct hab_device *device; int result = 0; int i = 0; struct hab_device *device = NULL; /* single GVM is 2, multigvm is 2 or 3. GHS LV-GVM 2, LA-GVM 3 */ int default_gvmid = DEFAULT_GVMID; Loading @@ -966,7 +1060,8 @@ int do_hab_parse(void) /* first check if hypervisor plug-in is ready */ result = hab_hypervisor_register(); if (result) { pr_err("register HYP plug-in failed, ret %d\n", result); pr_err("register HYP plug-in failed, ret %d driver version %s\n", result, hab_info_str); return result; } Loading Loading @@ -1014,13 +1109,13 @@ int get_refcnt(struct kref ref) void hab_hypervisor_unregister_common(void) { int status, i; struct uhab_context *ctx; struct virtual_channel *vchan; int status = 0, i = 0; struct uhab_context *ctx = NULL; struct virtual_channel *vchan = NULL; for (i = 0; i < hab_driver.ndevices; i++) { struct hab_device *habdev = &hab_driver.devp[i]; struct physical_channel *pchan, *pchan_tmp; struct physical_channel *pchan = NULL, *pchan_tmp = NULL; list_for_each_entry_safe(pchan, pchan_tmp, &habdev->pchannels, node) { Loading Loading @@ -1194,13 +1289,11 @@ static long hab_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) recv_param->sizebytes = 0; ret = -EFAULT; } } else if (ret && msg) { pr_warn("vcid %X recv failed %d and msg is still of %zd bytes\n", recv_param->vcid, (int)ret, msg->sizebytes); } if (msg) hab_msg_free(msg); } else pr_warn("vcid %X recv failed %d buf size %d\n", recv_param->vcid, (int)ret, recv_param->sizebytes); break; case IOCTL_HAB_VC_EXPORT: ret = hab_mem_export(ctx, (struct hab_export *)data, 0); Loading
drivers/soc/qcom/hab/hab.h +17 −4 Original line number Diff line number Diff line /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2019, 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 Loading Loading @@ -46,6 +46,7 @@ #include <linux/kobject.h> #include <linux/sysfs.h> #include <linux/delay.h> #include <linux/version.h> #include <soc/qcom/boot_stats.h> enum hab_payload_type { Loading Loading @@ -161,13 +162,13 @@ struct hab_header { #define HAB_HEADER_SET_SIZE(header, size) \ ((header).id_type_size = ((header).id_type_size & \ (~HAB_HEADER_SIZE_MASK)) | \ (uint32_t)(~HAB_HEADER_SIZE_MASK)) | \ (((size) << HAB_HEADER_SIZE_SHIFT) & \ HAB_HEADER_SIZE_MASK)) #define HAB_HEADER_SET_TYPE(header, type) \ ((header).id_type_size = ((header).id_type_size & \ (~HAB_HEADER_TYPE_MASK)) | \ (uint32_t)(~HAB_HEADER_TYPE_MASK)) | \ (((type) << HAB_HEADER_TYPE_SHIFT) & \ HAB_HEADER_TYPE_MASK)) Loading @@ -192,6 +193,7 @@ struct hab_header { #define HAB_HEADER_GET_SESSION_ID(header) ((header).session_id) #define HAB_HS_TIMEOUT (10*1000*1000) #define HAB_HS_INIT_DONE_TIMEOUT (3*1000) struct physical_channel { struct list_head node; Loading Loading @@ -265,6 +267,11 @@ struct hab_message { uint32_t data[]; }; struct hab_forbidden_node { struct list_head node; uint32_t mmid; }; /* for all the pchans of same kind */ struct hab_device { char name[MAX_VMID_NAME_SIZE]; Loading Loading @@ -302,6 +309,9 @@ struct uhab_context { struct list_head pending_open; /* sent to remote */ int pending_cnt; struct list_head forbidden_chans; spinlock_t forbidden_lock; rwlock_t ctx_lock; int closing; int kernel; Loading Loading @@ -403,6 +413,9 @@ struct export_desc { unsigned char payload[1]; } __packed; int hab_is_forbidden(struct uhab_context *ctx, struct hab_device *dev, uint32_t sub_id); int hab_vchan_open(struct uhab_context *ctx, unsigned int mmid, int32_t *vcid, int32_t timeout, uint32_t flags); Loading Loading @@ -521,7 +534,7 @@ static inline void hab_ctx_get(struct uhab_context *ctx) static inline void hab_ctx_put(struct uhab_context *ctx) { if (ctx) kref_put(&ctx->refcount, hab_ctx_free); kref_put(&ctx->refcount, &hab_ctx_free); } void hab_send_close_msg(struct virtual_channel *vchan); Loading
drivers/soc/qcom/hab/hab_ghs.c +2 −2 Original line number Diff line number Diff line /* Copyright (c) 2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2018-2019, 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 Loading Loading @@ -93,7 +93,7 @@ static int get_dt_name_idx(int vmid_base, int mmid, struct ghs_vmm_plugin_info_s *plugin_info) { int idx = -1; int i; int i = 0; if (vmid_base < 0 || vmid_base > plugin_info->probe_cnt / GIPC_VM_SET_CNT) { Loading
drivers/soc/qcom/hab/hab_mem_linux.c +3 −0 Original line number Diff line number Diff line Loading @@ -598,6 +598,9 @@ static int hab_mem_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) vma->vm_private_data = pglist; vma->vm_flags |= VM_MIXEDMAP; if (!(pglist->userflags & HABMM_IMPORT_FLAGS_CACHED)) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); return 0; } Loading