Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions include/guest_shm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright 2018, QNX Software Systems Limited (“QSS”).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Additional Patent Grant
*
* QSS hereby grants to you a perpetual, worldwide, non-exclusive,
* no-charge, irrevocable (except as stated in this section) patent
* license to make, have made, use, offer to sell, sell, import,
* transfer, and otherwise run, modify and propagate the contents of this
* header file (“Implementation”) , where such license applies
* only to those patent claims, both currently owned by QSS and
* acquired in the future, licensable by QSS that are necessarily
* infringed by this Implementation. This grant does
* not include claims that would be infringed only as a consequence of
* further modification of this Implementation. If you or your agent or
* exclusive licensee institute or order or agree to the institution of
* patent litigation against any entity (including a cross-claim or
* counterclaim in a lawsuit) alleging that this Implementation constitutes
* direct or contributory patent infringement, or inducement of patent
* infringement, then any patent rights granted to you under this license for
* this Implementation shall terminate as of the date such litigation is filed.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*/

/**
* @file
* definitions guest shared memory device
*/

#ifndef _QVM_GUEST_SHM_H
#define _QVM_GUEST_SHM_H

#include <stdint.h>

/*
* Temporary VID definition until the updated <pci/pci_id.h> propogates around
*/
#define PCI_VID_BlackBerry_QNX 0x1C05

#define PCI_DID_QNX_GUEST_SHM 0x0001

/** status of last creation request */
enum guest_shm_status {
GSS_OK, /**< creation succeeded */
GSS_UNKNOWN_FAILURE, /**< creation failed for an unknown reason */
GSS_NOMEM, /**< creation failed due to lack of memory */
GSS_CLIENT_MAX, /**< creation failed due to region already being used by the maximum number of guests */
GSS_ILLEGAL_NAME, /**< creation failed due to illegal region name */
GSS_NO_PERMISSION, /**< creation failed due to lack of permission */
GSS_DOES_NOT_EXIST, /**< A find request failed */
};

/** Maximum number of clients allowed to connect to a shared memory region */
#define GUEST_SHM_MAX_CLIENTS 16
#define GUEST_INTR_STATUS_MASK ((1u << GUEST_SHM_MAX_CLIENTS) - 1u)

/** Maximum length allowed for region name */
#define GUEST_SHM_MAX_NAME 32

/** Signature value to verify that vdev is present */
#define GUEST_SHM_SIGNATURE_L 0x474d5651
#define GUEST_SHM_SIGNATURE_H 0x4d534732
#define GUEST_SHM_SIGNATURE 0x4d534732474d5651


/** Register layout for factory registers */
struct guest_shm_factory {
UINT64 signature; /**< == GUEST_SHM_SIGNATURE (R/O) */
UINT64 shmem; /**< shared memory paddr (R/O) */
UINT32 vector; /**< interrupt vector number (R/O) */
UINT32 status; /**< status of last creation (R/O) */
UINT32 size; /**< requested size in 4K pages, write causes creation */
CHAR8 name[GUEST_SHM_MAX_NAME]; /**< name of shared memory region */
UINT32 find; /**< find an existing shared memory connection */
} __packed;

/** Register layout for a region control page */
struct guest_shm_control {
UINT32 status; /**< lower 16 bits: pending notification bitset, upper 16 bits: current active clients (R/O) */
UINT32 idx; /**< connection index for this client (R/O) */
UINT32 notify; /**< write a bitset of clients to notify */
UINT32 detach; /**< write here to detach from the shared memory region */
};


static inline void
guest_shm_create(volatile struct guest_shm_factory *const __factory, UINT32 const __size) {
/* Surround the size assignment with memory barriers so that
* the compiler doesn't try to shift the assignment before/after
* necessary bits (e.g. setting the name of the region) */
asm volatile( "" ::: "memory");
__factory->size = __size;
asm volatile( "" ::: "memory");
}


static inline void
guest_shm_find(volatile struct guest_shm_factory *const __factory, UINT32 const __find_num) {
/* Surround the find assignment with memory barriers so that
* the compiler doesn't try to shift the assignment before/after
* necessary bits (e.g. setting the name of the region) */
asm volatile( "" ::: "memory");
__factory->find = __find_num;
asm volatile( "" ::: "memory");
}

#endif
12 changes: 12 additions & 0 deletions include/ivshmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@
#define TEE_TPM2_SHOW_INDEX 0x0000000A
#define TEE_TPM2_DELETE_INDEX 0x0000000B

struct optee_vm_ids {
uint32_t ree_id;
uint32_t tee_id;
} __packed;

typedef enum {
EVENT_KERNEL = 1,
EVENT_ROT,
EVENT_ROLLBACK,
} event_src;

EFI_STATUS ivshmem_init(void);

void ivshmem_rot_interrupt(void);
Expand All @@ -60,5 +71,6 @@ struct tpm2_int_req {
};

void ivshmem_rollback_index_interrupt(struct tpm2_int_req* req);
void ivshmem_detach(void);

#endif /* _IVSHMEM_H_ */
1 change: 1 addition & 0 deletions include/lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,5 +273,6 @@ EFI_STATUS string_to_argv(char *str, INTN *argc, CHAR8 *argv[], UINTN max_argc,
const char *first_delim, const char *delim);

int is_running_on_kvm(void);
int is_running_on_qnx(void);
#endif

3 changes: 3 additions & 0 deletions libkernelflinger/android.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#include "android.h"
#include "efilinux.h"
#include "ivshmem.h"
#include "lib.h"
#include "security.h"
#include "vars.h"
Expand Down Expand Up @@ -437,6 +438,8 @@ static inline EFI_STATUS handover_jump(EFI_HANDLE image,

log(L"handover jump ...\n");

ivshmem_detach();

ret = setup_gdt();
if (EFI_ERROR(ret)) {
efi_perror(ret, L"Failed to setup GDT");
Expand Down
136 changes: 106 additions & 30 deletions libkernelflinger/ivshmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
*/

#include "ivshmem.h"
#include "guest_shm.h"

#define PCI_MAX_DEV_NUM 32
#define PCI_MAX_FUNC_NUM 8
Expand Down Expand Up @@ -171,11 +172,16 @@ struct ivshmem_device {
UINT32 bar1_len;
UINT32 bar2_addr;
UINT32 bar2_len;

volatile struct guest_shm_factory *fact;
volatile struct guest_shm_control *ctrl;
};

static struct ivshmem_device g_ivshmem_dev;

UINT64 g_ivshmem_rot_addr = 0;
volatile struct optee_vm_ids *smc_vm_ids = NULL;
volatile uint32_t *smc_evt_src = NULL;

static UINT8 hw_read_port_8(UINT16 port)
{
Expand Down Expand Up @@ -361,6 +367,12 @@ static UINT32 pci_resource_len(UINT8 bus, UINT8 device, UINT8 function,
static bool ivshmem_get_dev_func(void)
{
UINT8 device, function;
UINT32 expect;

if(is_running_on_qnx())
expect = PCI_VID_BlackBerry_QNX | (PCI_DID_QNX_GUEST_SHM << 16);
else
expect = IVSHMEM_VENDOR_ID | (IVSHMEM_DEVICE_ID << 16);

/*
* PCI devices reside in bus zero by default.
Expand All @@ -372,7 +384,9 @@ static bool ivshmem_get_dev_func(void)
for (device = 0; device < PCI_MAX_DEV_NUM; device++) {
for (function = 0; function < PCI_MAX_FUNC_NUM; function++) {
if (pci_read32(0, device, function, PCI_CONFIG_VENDOR_ID_OFFSET) ==
(IVSHMEM_VENDOR_ID | (IVSHMEM_DEVICE_ID << 16))) {
expect) {
if(device != 6)
continue;
g_ivshmem_dev.dev = device;
g_ivshmem_dev.func = function;
return true;
Expand All @@ -397,43 +411,96 @@ EFI_STATUS ivshmem_init(void)

dev = g_ivshmem_dev.dev;
func = g_ivshmem_dev.func;
g_ivshmem_dev.revision = pci_read8(0, dev, func, PCI_CONFIG_REVISION_OFFSET);
info(L"IVSHMEM device: revision=0x%x", g_ivshmem_dev.revision);

/* Enable BAR address MMIO support. */
val16 = pci_read16(0, dev, func, PCI_CONFIG_COMMAND_OFFSET);
val16 |= 1 << CMD_MEM_SPACE_BIT_POSITION;
pci_write16(0, dev, func, PCI_CONFIG_COMMAND_OFFSET, val16);

g_ivshmem_dev.bar0_addr = pci_resource_start(0, dev, func, PCI_CONFIG_BAR0_OFFSET);
g_ivshmem_dev.bar0_len = pci_resource_len(0, dev, func, PCI_CONFIG_BAR0_OFFSET);
info(L"IVSHMEM device: bar0 addr=0x%x, len=0x%x",
g_ivshmem_dev.bar0_addr, g_ivshmem_dev.bar0_len);

g_ivshmem_dev.bar2_addr = pci_resource_start(0, dev, func, PCI_CONFIG_BAR2_OFFSET);
g_ivshmem_dev.bar2_len = pci_resource_len(0, dev, func, PCI_CONFIG_BAR2_OFFSET);
info(L"IVSHMEM device: bar2 addr=0x%x, len=0x%x",
g_ivshmem_dev.bar2_addr, g_ivshmem_dev.bar2_len);
if (g_ivshmem_dev.bar2_len < IVSHMEM_DEFAULT_SIZE) {
error(L"IVSHMEM device: bar2 size too small");
return EFI_BUFFER_TOO_SMALL;
}
if(is_running_on_qnx()) {
g_ivshmem_dev.bar0_addr = pci_resource_start(0, dev, func, PCI_CONFIG_BAR0_OFFSET);
g_ivshmem_dev.bar0_len = pci_resource_len(0, dev, func, PCI_CONFIG_BAR0_OFFSET);
info(L"IVSHMEM device: bar0 addr=0x%x, len=0x%x",
g_ivshmem_dev.bar0_addr, g_ivshmem_dev.bar0_len);

g_ivshmem_dev.fact = (struct guest_shm_factory *)g_ivshmem_dev.bar0_addr;
if ((g_ivshmem_dev.fact->signature & 0xFFFFFFFF) != GUEST_SHM_SIGNATURE_L
|| (g_ivshmem_dev.fact->signature >> 32) != GUEST_SHM_SIGNATURE_H) {
error(L"IVSHMEM device: Invalid ivshmem device");
return EFI_NOT_FOUND;
}

info(L"IVSHMEM device: valid device signature");

g_ivshmem_rot_addr = g_ivshmem_dev.bar2_addr + IVSHMEM_ROT_OFFSET;
info(L"IVSHMEM device: rot_addr=0x%lx", g_ivshmem_rot_addr);
strcpy_s((CHAR8 *)g_ivshmem_dev.fact->name, GUEST_SHM_MAX_NAME, "tee_shmem");
guest_shm_create(g_ivshmem_dev.fact, 0x500);

if (g_ivshmem_dev.revision == 1) {
info(L"IVSHMEM device: ivposition=%d",
io_read_32((void *)((UINT64)(g_ivshmem_dev.bar0_addr + IVPOSITION_OFF))));
if (g_ivshmem_dev.fact->status != GSS_OK) {
error(L"IVSHMEM device: invalid device status");
return EFI_DEVICE_ERROR;
}

info(L"IVSHMEM device: valid device status");

g_ivshmem_dev.ctrl = (struct guest_shm_control *)g_ivshmem_dev.fact->shmem;
info(L"ivshmem region ctrl status is 0x%x", g_ivshmem_dev.ctrl->status);

info(L"IVSHMEM device: shmem addr=0x%x, len=0x%x",
g_ivshmem_dev.fact->shmem + 0x1000, g_ivshmem_dev.fact->size);

if (g_ivshmem_dev.fact->size * 0x1000 < IVSHMEM_DEFAULT_SIZE) {
error(L"IVSHMEM device: bar2 size too small");
return EFI_BUFFER_TOO_SMALL;
}
info(L"IVSHMEM device: shmem len=0x%x", g_ivshmem_dev.fact->size);

smc_evt_src = (uint32_t *)(g_ivshmem_dev.fact->shmem + 0x1000);
smc_vm_ids = (struct optee_vm_ids *)(g_ivshmem_dev.fact->shmem + 0x1000 +
sizeof(uint32_t));

smc_vm_ids->ree_id = g_ivshmem_dev.ctrl->idx;
info(L"IVSHMEM device: tee_id:%d ree_id:%d", smc_vm_ids->tee_id, smc_vm_ids->ree_id);

g_ivshmem_rot_addr = g_ivshmem_dev.fact->shmem + 0x1000 + IVSHMEM_ROT_OFFSET;
info(L"IVSHMEM device: rot_addr=0x%lx", g_ivshmem_rot_addr);

} else {
g_ivshmem_dev.revision = pci_read8(0, dev, func, PCI_CONFIG_REVISION_OFFSET);
info(L"IVSHMEM device: revision=0x%x", g_ivshmem_dev.revision);

/* Enable BAR address MMIO support. */
val16 = pci_read16(0, dev, func, PCI_CONFIG_COMMAND_OFFSET);
val16 |= 1 << CMD_MEM_SPACE_BIT_POSITION;
pci_write16(0, dev, func, PCI_CONFIG_COMMAND_OFFSET, val16);

g_ivshmem_dev.bar0_addr = pci_resource_start(0, dev, func, PCI_CONFIG_BAR0_OFFSET);
g_ivshmem_dev.bar0_len = pci_resource_len(0, dev, func, PCI_CONFIG_BAR0_OFFSET);
info(L"IVSHMEM device: bar0 addr=0x%x, len=0x%x",
g_ivshmem_dev.bar0_addr, g_ivshmem_dev.bar0_len);

g_ivshmem_dev.bar2_addr = pci_resource_start(0, dev, func, PCI_CONFIG_BAR2_OFFSET);
g_ivshmem_dev.bar2_len = pci_resource_len(0, dev, func, PCI_CONFIG_BAR2_OFFSET);
info(L"IVSHMEM device: bar2 addr=0x%x, len=0x%x",
g_ivshmem_dev.bar2_addr, g_ivshmem_dev.bar2_len);
if (g_ivshmem_dev.bar2_len < IVSHMEM_DEFAULT_SIZE) {
error(L"IVSHMEM device: bar2 size too small");
return EFI_BUFFER_TOO_SMALL;
}

g_ivshmem_rot_addr = g_ivshmem_dev.bar2_addr + IVSHMEM_ROT_OFFSET;
info(L"IVSHMEM device: rot_addr=0x%lx", g_ivshmem_rot_addr);

if (g_ivshmem_dev.revision == 1) {
info(L"IVSHMEM device: ivposition=%d",
io_read_32((void *)((UINT64)(g_ivshmem_dev.bar0_addr + IVPOSITION_OFF))));
}
}

return EFI_SUCCESS;
}

void ivshmem_rot_interrupt(void)
{
io_write_32((void *)((UINT64)(g_ivshmem_dev.bar0_addr + DOORBELL_OFF)),
ROT_INTERRUPT);
if(is_running_on_qnx()) {
*smc_evt_src = EVENT_ROT;
g_ivshmem_dev.ctrl->notify = 1 << smc_vm_ids->tee_id;
} else
io_write_32((void *)((UINT64)(g_ivshmem_dev.bar0_addr + DOORBELL_OFF)),
ROT_INTERRUPT);
}

#define NOT_READY_MAGIC 0x12ABCDEF
Expand All @@ -460,7 +527,12 @@ void ivshmem_rollback_index_interrupt(struct tpm2_int_req* req)
}
memcpy(p_req, req, req_size);

io_write_32((void *)((UINT64)(g_ivshmem_dev.bar0_addr + DOORBELL_OFF)), ROLLBACK_INDEX_INTERRUPT);
if(is_running_on_qnx()) {
*smc_evt_src = EVENT_ROLLBACK;
g_ivshmem_dev.ctrl->notify = 1 << smc_vm_ids->tee_id;
} else
io_write_32((void *)((UINT64)(g_ivshmem_dev.bar0_addr + DOORBELL_OFF)),
ROLLBACK_INDEX_INTERRUPT);

while (NOT_READY_MAGIC == p_req->ret) {
//just wait for int handler return
Expand All @@ -471,3 +543,7 @@ void ivshmem_rollback_index_interrupt(struct tpm2_int_req* req)
return;
}

void ivshmem_detach(void) {
if(is_running_on_qnx())
g_ivshmem_dev.ctrl->detach = 1 << smc_vm_ids->ree_id;
}
11 changes: 11 additions & 0 deletions libkernelflinger/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1730,5 +1730,16 @@ int is_running_on_kvm(void)
return 0;
}

int is_running_on_qnx(void)
{
UINT32 reg[4];

cpuid(0x40000000, reg);
if (reg[0] == 0x40000002 && reg[1] == 0x51584e51 && reg[2] == 0x53424d56 && reg[3] == 0x4751)
return 1;

return 0;
}

/* vim: softtabstop=8:shiftwidth=8:expandtab
*/