Skip to content

Commit

Permalink
lib: add implementation of virtIO MMIO
Browse files Browse the repository at this point in the history
Co-authored-by: Jingyao Zhou <[email protected]>
  • Loading branch information
Ivan-Velickovic and abrandnewusername committed Nov 10, 2023
1 parent 585b090 commit 0bedada
Show file tree
Hide file tree
Showing 9 changed files with 832 additions and 7 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:
steps:
- name: Checkout VMM repository
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Download Microkit SDK
run: ./ci/acquire_sdk.sh microkit-sdk.zip ${{ secrets.GITHUB_TOKEN }} linux-x86-64
shell: bash
Expand Down Expand Up @@ -58,6 +60,8 @@ jobs:
steps:
- name: Checkout VMM repository
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Download Microkit SDK
run: ./ci/acquire_sdk.sh microkit-sdk.zip ${{ secrets.GITHUB_TOKEN }} macos-x86-64
shell: bash
Expand Down Expand Up @@ -88,6 +92,8 @@ jobs:
steps:
- name: Checkout VMM repository
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Download Microkit SDK
run: ./ci/acquire_sdk.sh microkit-sdk.zip ${{ secrets.GITHUB_TOKEN }} linux-x86-64
shell: bash
Expand All @@ -109,6 +115,8 @@ jobs:
steps:
- name: Checkout VMM repository
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Download Microkit SDK
run: ./ci/acquire_sdk.sh microkit-sdk.zip ${{ secrets.GITHUB_TOKEN }} macos-x86-64
shell: bash
Expand Down
21 changes: 16 additions & 5 deletions src/arch/aarch64/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ uint64_t fault_emulate(seL4_UserContext *regs, uint64_t reg, uint64_t addr, uint
}
}

void fault_emulate_write(seL4_UserContext *regs, size_t addr, size_t fsr, size_t reg_val) {
// @ivanv: audit
/* Get register opearand */
int rt = get_rt(fsr);
seL4_Word *reg_ctx = decode_rt(rt, regs);
*reg_ctx = fault_emulate(regs, *reg_ctx, addr, fsr, reg_val);
}

bool fault_advance(size_t vcpu_id, seL4_UserContext *regs, uint64_t addr, uint64_t fsr, uint64_t reg_val)
{
/* Get register opearand */
Expand Down Expand Up @@ -294,12 +302,13 @@ struct vm_exception_handler {
uintptr_t base;
uintptr_t end;
vm_exception_handler_t callback;
void *data;
};
#define MAX_VM_EXCEPTION_HANDLERS 16
struct vm_exception_handler registered_vm_exception_handlers[MAX_VM_EXCEPTION_HANDLERS];
size_t vm_exception_handler_index = 0;

bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_exception_handler_t callback) {
bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_exception_handler_t callback, void *data) {
// @ivanv audit necessary here since this code was written very quickly. Other things to check such
// as the region of memory is not overlapping with other regions, also should have GIC_DIST regions
// use this API.
Expand All @@ -316,18 +325,21 @@ bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_excepti
.base = base,
.end = base + size,
.callback = callback,
.data = data,
};
vm_exception_handler_index += 1;

return true;
}

static bool fault_handle_registered_vm_exceptions(size_t vcpu_id, uintptr_t addr) {
static bool fault_handle_registered_vm_exceptions(size_t vcpu_id, uintptr_t addr, size_t fsr, seL4_UserContext *regs) {
for (int i = 0; i < MAX_VM_EXCEPTION_HANDLERS; i++) {
uintptr_t base = registered_vm_exception_handlers[i].base;
uintptr_t end = registered_vm_exception_handlers[i].end;
vm_exception_handler_t callback = registered_vm_exception_handlers[i].callback;
void *data = registered_vm_exception_handlers[i].data;
if (addr >= base && addr < end) {
bool success = registered_vm_exception_handlers[i].callback(vcpu_id, addr);
bool success = callback(vcpu_id, addr - base, fsr, regs, data);
if (!success) {
// @ivanv: improve error message
LOG_VMM_ERR("registered virtual memory exception handler for region [0x%lx..0x%lx) at address 0x%lx failed\n", base, end, addr);
Expand Down Expand Up @@ -361,8 +373,7 @@ bool fault_handle_vm_exception(size_t vcpu_id)
return handle_vgic_redist_fault(vcpu_id, addr, fsr, &regs);
#endif
default: {
LOG_VMM("calling fault handle vm exception\n");
bool success = fault_handle_registered_vm_exceptions(vcpu_id ,addr);
bool success = fault_handle_registered_vm_exceptions(vcpu_id, addr, fsr, &regs);
if (!success) {
/*
* We could not find a registered handler for the address, meaning that the fault
Expand Down
6 changes: 4 additions & 2 deletions src/arch/aarch64/fault.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <microkit.h>

/* Fault-handling functions */
Expand All @@ -19,15 +20,16 @@ bool fault_handle_user_exception(size_t vcpu_id);
bool fault_handle_unknown_syscall(size_t vcpu_id);
bool fault_handle_vm_exception(size_t vcpu_id);

typedef bool (*vm_exception_handler_t)(size_t vcpu_id, uintptr_t addr);
bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_exception_handler_t callback);
typedef bool (*vm_exception_handler_t)(size_t vcpu_id, size_t offset, size_t fsr, seL4_UserContext *regs, void *data);
bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_exception_handler_t callback, void *data);

/* Helpers for emulating the fault and getting fault details */
bool fault_advance_vcpu(size_t vcpu_id, seL4_UserContext *regs);
bool fault_advance(size_t vcpu_id, seL4_UserContext *regs, uint64_t addr, uint64_t fsr, uint64_t reg_val);
uint64_t fault_get_data_mask(uint64_t addr, uint64_t fsr);
uint64_t fault_get_data(seL4_UserContext *regs, uint64_t fsr);
uint64_t fault_emulate(seL4_UserContext *regs, uint64_t reg, uint64_t addr, uint64_t fsr, uint64_t reg_val);
void fault_emulate_write(seL4_UserContext *regs, size_t addr, size_t fsr, size_t reg_val);

/* Take the fault label given by the kernel and convert it to a string. */
char *fault_to_string(seL4_Word fault_label);
Expand Down
107 changes: 107 additions & 0 deletions src/virtio/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/* SPDX-License-Identifier: BSD-3-Clause
Copyright Linux */

#pragma once
/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
* anyone can use the definitions to implement compatible drivers/servers.
*
* 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 IBM 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 IBM 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. */

/* Virtio devices use a standardized configuration space to define their
* features and pass configuration information, but each implementation can
* store and access that space differently. */

/* Status byte for guest to report progress, and synchronize features. */
/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
/* the guest OS triggers a device reset*/
#define VIRTIO_CONFIG_S_RESET 0
/* the guest OS has noticed the device. */
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
/* the guest OS has found a driver for the device. */
#define VIRTIO_CONFIG_S_DRIVER 2
/* Driver has used its parts of the config, and is happy */
#define VIRTIO_CONFIG_S_DRIVER_OK 4
/* Driver has finished configuring features */
#define VIRTIO_CONFIG_S_FEATURES_OK 8
/* Device entered invalid state, driver must reset it */
#define VIRTIO_CONFIG_S_NEEDS_RESET 0x40
/* We've given up on this device. */
#define VIRTIO_CONFIG_S_FAILED 0x80

/*
* Virtio feature bits VIRTIO_TRANSPORT_F_START through
* VIRTIO_TRANSPORT_F_END are reserved for the transport
* being used (e.g. virtio_ring, virtio_pci etc.), the
* rest are per-device feature bits.
*/
#define VIRTIO_TRANSPORT_F_START 28
#define VIRTIO_TRANSPORT_F_END 41

#ifndef VIRTIO_CONFIG_NO_LEGACY
/* Do we get callbacks when the ring is completely used, even if we've
* suppressed them? */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24

/* Can the device handle any descriptor layout? */
#define VIRTIO_F_ANY_LAYOUT 27
#endif /* VIRTIO_CONFIG_NO_LEGACY */

/* v1.0 compliant. */
#define VIRTIO_F_VERSION_1 32

/*
* If clear - device has the platform DMA (e.g. IOMMU) bypass quirk feature.
* If set - use platform DMA tools to access the memory.
*
* Note the reverse polarity (compared to most other features),
* this is for compatibility with legacy systems.
*/
#define VIRTIO_F_ACCESS_PLATFORM 33
/* Legacy name for VIRTIO_F_ACCESS_PLATFORM (for compatibility with old userspace) */
#define VIRTIO_F_IOMMU_PLATFORM VIRTIO_F_ACCESS_PLATFORM

/* This feature indicates support for the packed virtqueue layout. */
#define VIRTIO_F_RING_PACKED 34

/*
* Inorder feature indicates that all buffers are used by the device
* in the same order in which they have been made available.
*/
#define VIRTIO_F_IN_ORDER 35

/*
* This feature indicates that memory accesses by the driver and the
* device are ordered in a way described by the platform.
*/
#define VIRTIO_F_ORDER_PLATFORM 36

/*
* Does the device support Single Root I/O Virtualization?
*/
#define VIRTIO_F_SR_IOV 37

/*
* This feature indicates that the driver can reset a queue individually.
*/
#define VIRTIO_F_RING_RESET 40
Loading

0 comments on commit 0bedada

Please sign in to comment.