[guest][machina] Remove sources.
These have been migrated to garnet.
> //zircon/system/ulib/machina -> //garnet/lib/machina
> //zircon/system/utest/machina -> //garnet/lib/machina/tests
> //zircon/system/uapp/guest -> //garnet/bin/guest
Change-Id: I4e3dd59447d33af8e9e78d2f313dacffdb195d27
diff --git a/system/uapp/guest/BUILD.gn b/system/uapp/guest/BUILD.gn
deleted file mode 100644
index e41c4af..0000000
--- a/system/uapp/guest/BUILD.gn
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2016 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/package.gni")
-
-executable("bin") {
- output_name = "garnet-guest"
-
- sources = [
- "guest.cpp",
- "linux.cpp",
- "zircon.cpp",
- ]
-
- deps = [
- "//zircon/system/ulib/fbl",
- "//zircon/system/ulib/machina",
- ]
-}
-
-package("guest") {
- system_image = true
-
- deps = [
- ":bin",
- ]
-
- binaries = [{
- name = "garnet-guest"
- }]
-}
diff --git a/system/uapp/guest/guest.cpp b/system/uapp/guest/guest.cpp
deleted file mode 100644
index c9799e6..0000000
--- a/system/uapp/guest/guest.cpp
+++ /dev/null
@@ -1,391 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <fbl/unique_ptr.h>
-#include <hypervisor/address.h>
-#include <hypervisor/guest.h>
-#include <hypervisor/vcpu.h>
-#include <machina/balloon.h>
-#include <machina/block.h>
-#include <machina/gpu.h>
-#include <machina/input.h>
-#include <machina/interrupt_controller.h>
-#include <machina/pci.h>
-#include <machina/uart.h>
-#include <virtio/balloon.h>
-#include <zircon/process.h>
-#include <zircon/syscalls.h>
-#include <zircon/syscalls/hypervisor.h>
-
-#include "linux.h"
-#include "zircon.h"
-
-#if __aarch64__
-static const size_t kNumUarts = 1;
-static const uint64_t kUartBases[kNumUarts] = {
- // TODO(abdulla): Considering parsing this from the MDI.
- PL011_PHYS_BASE,
-};
-#elif __x86_64__
-#include <hypervisor/x86/acpi.h>
-#include <hypervisor/x86/local_apic.h>
-#include <machina/io_port.h>
-#include <machina/tpm.h>
-
-static const size_t kNumUarts = 4;
-static const uint64_t kUartBases[kNumUarts] = {
- I8250_BASE0, I8250_BASE1, I8250_BASE2, I8250_BASE3,
-};
-
-static zx_status_t create_vmo(uint64_t size, uintptr_t* addr, zx_handle_t* vmo) {
- zx_status_t status = zx_vmo_create(size, 0, vmo);
- if (status != ZX_OK)
- return status;
- return zx_vmar_map(zx_vmar_root_self(), 0, *vmo, 0, size,
- ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, addr);
-}
-#endif
-
-static const uint64_t kVmoSize = 1u << 30;
-
-// Unused memory above this threshold may be reclaimed by the balloon.
-static uint32_t balloon_threshold_pages = 1024;
-
-static zx_status_t usage(const char* cmd) {
- fprintf(stderr, "usage: %s [OPTIONS] kernel.bin\n", cmd);
- fprintf(stderr, "\n");
- fprintf(stderr, "OPTIONS:\n");
- fprintf(stderr, "\t-b [block.bin] Use file 'block.bin' as a virtio-block device\n");
- fprintf(stderr, "\t-r [ramdisk.bin] Use file 'ramdisk.bin' as a ramdisk\n");
- fprintf(stderr, "\t-c [cmdline] Use string 'cmdline' as the kernel command line\n");
- fprintf(stderr, "\t-m [seconds] Poll the virtio-balloon device every 'seconds' seconds\n"
- "\t and adjust the balloon size based on the amount of\n"
- "\t unused guest memory\n");
- fprintf(stderr, "\t-p [pages] Number of unused pages to allow the guest to\n"
- "\t retain. Has no effect unless -m is also used\n");
- fprintf(stderr, "\t-d Demand-page balloon deflate requests\n");
- fprintf(stderr, "\t-g Enable graphics output to the framebuffer.\n");
- fprintf(stderr, "\n");
- return ZX_ERR_INVALID_ARGS;
-}
-
-static void balloon_stats_handler(VirtioBalloon* balloon, const virtio_balloon_stat_t* stats,
- size_t len) {
- for (size_t i = 0; i < len; ++i) {
- if (stats[i].tag != VIRTIO_BALLOON_S_AVAIL)
- continue;
-
- uint32_t current_pages = balloon->num_pages();
- uint32_t available_pages = static_cast<uint32_t>(stats[i].val / VirtioBalloon::kPageSize);
- uint32_t target_pages = current_pages + (available_pages - balloon_threshold_pages);
- if (current_pages == target_pages)
- return;
-
- printf("virtio-balloon: adjusting target pages %#x -> %#x\n",
- current_pages, target_pages);
- zx_status_t status = balloon->UpdateNumPages(target_pages);
- if (status != ZX_OK)
- fprintf(stderr, "Error %d updating balloon size\n", status);
- return;
- }
-}
-
-typedef struct balloon_task_args {
- VirtioBalloon* balloon;
- zx_duration_t interval;
-} balloon_task_args_t;
-
-static int balloon_stats_task(void* ctx) {
- fbl::unique_ptr<balloon_task_args_t> args(static_cast<balloon_task_args_t*>(ctx));
- VirtioBalloon* balloon = args->balloon;
- while (true) {
- zx_nanosleep(zx_deadline_after(args->interval));
- args->balloon->RequestStats([balloon](const virtio_balloon_stat_t* stats, size_t len) {
- balloon_stats_handler(balloon, stats, len);
- });
- }
- return ZX_OK;
-}
-
-static zx_status_t poll_balloon_stats(VirtioBalloon* balloon, zx_duration_t interval) {
- thrd_t thread;
- auto args = new balloon_task_args_t{balloon, interval};
-
- int ret = thrd_create(&thread, balloon_stats_task, args);
- if (ret != thrd_success) {
- fprintf(stderr, "Failed to create balloon thread %d\n", ret);
- delete args;
- return ZX_ERR_INTERNAL;
- }
-
- ret = thrd_detach(thread);
- if (ret != thrd_success) {
- fprintf(stderr, "Failed to detach balloon thread %d\n", ret);
- return ZX_ERR_INTERNAL;
- }
-
- return ZX_OK;
-}
-
-int main(int argc, char** argv) {
- const char* cmd = basename(argv[0]);
- const char* block_path = NULL;
- const char* ramdisk_path = NULL;
- const char* cmdline = NULL;
- zx_duration_t balloon_poll_interval = 0;
- bool balloon_deflate_on_demand = false;
- bool use_gpu = false;
- int opt;
- while ((opt = getopt(argc, argv, "b:r:c:m:dp:g")) != -1) {
- switch (opt) {
- case 'b':
- block_path = optarg;
- break;
- case 'r':
- ramdisk_path = optarg;
- break;
- case 'c':
- cmdline = optarg;
- break;
- case 'm':
- balloon_poll_interval = ZX_SEC(strtoul(optarg, nullptr, 10));
- if (balloon_poll_interval <= 0) {
- fprintf(stderr, "Invalid balloon interval %s. Must be an integer greater than 0\n",
- optarg);
- return ZX_ERR_INVALID_ARGS;
- }
- break;
- case 'd':
- balloon_deflate_on_demand = true;
- break;
- case 'p':
- balloon_threshold_pages = static_cast<uint32_t>(strtoul(optarg, nullptr, 10));
- if (balloon_threshold_pages <= 0) {
- fprintf(stderr, "Invalid balloon threshold %s. Must be an integer greater than 0\n",
- optarg);
- return ZX_ERR_INVALID_ARGS;
- }
- break;
- case 'g':
- use_gpu = true;
- break;
- default:
- return usage(cmd);
- }
- }
- if (optind >= argc)
- return usage(cmd);
-
- Guest guest;
- zx_status_t status = guest.Init(kVmoSize);
- if (status != ZX_OK)
- return status;
-
- uintptr_t physmem_addr = guest.phys_mem().addr();
- size_t physmem_size = guest.phys_mem().size();
- uintptr_t pt_end_off = 0;
-
-#if __x86_64__
- status = guest.CreatePageTable(&pt_end_off);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create page table\n");
- return status;
- }
- status = guest_create_acpi_table(physmem_addr, physmem_size, pt_end_off);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create ACPI table\n");
- return status;
- }
-#endif // __x86_64__
-
-
- // Prepare the OS image
- int fd = open(argv[optind], O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "Failed to open kernel image \"%s\"\n", argv[optind]);
- return ZX_ERR_IO;
- }
-
- // Load the first page in to allow OS detection without requiring
- // us to seek backwards later.
- uintptr_t first_page = physmem_addr + physmem_size - PAGE_SIZE;
- ssize_t ret = read(fd, (void*)first_page, PAGE_SIZE);
- if (ret != PAGE_SIZE) {
- fprintf(stderr, "Failed to read first page of kernel\n");
- return ZX_ERR_IO;
- }
-
- uintptr_t guest_ip;
- uintptr_t bootdata_off = 0;
-
- char guest_cmdline[PATH_MAX];
- const char* zircon_fmt_string = "TERM=uart %s";
- snprintf(guest_cmdline, PATH_MAX, zircon_fmt_string, cmdline ? cmdline : "");
- status = setup_zircon(physmem_addr, physmem_size, first_page, pt_end_off, fd, ramdisk_path,
- guest_cmdline, &guest_ip, &bootdata_off);
-
- if (status == ZX_ERR_NOT_SUPPORTED) {
- const char* linux_fmt_string = "earlyprintk=serial,ttyS,115200 console=ttyS0,115200 "
- "io_delay=none acpi_rsdp=%#lx clocksource=tsc %s";
- snprintf(guest_cmdline, PATH_MAX, linux_fmt_string, pt_end_off, cmdline ? cmdline : "");
- status = setup_linux(physmem_addr, physmem_size, first_page, fd, ramdisk_path,
- guest_cmdline, &guest_ip, &bootdata_off);
- }
- if (status == ZX_ERR_NOT_SUPPORTED) {
- fprintf(stderr, "Unknown kernel\n");
- return status;
- } else if (status != ZX_OK) {
- fprintf(stderr, "Failed to load kernel\n");
- return status;
- }
- close(fd);
-
-#if __x86_64__
- uintptr_t apic_addr;
- zx_handle_t apic_vmo;
- status = create_vmo(PAGE_SIZE, &apic_addr, &apic_vmo);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create VCPU local APIC memory\n");
- return status;
- }
-#endif // __x86_64__
-
- zx_vcpu_create_args_t args = {
- guest_ip,
-#if __x86_64__
- 0 /* cr3 */,
- apic_vmo,
-#endif // __x86_64__
- };
- Vcpu vcpu;
- status = vcpu.Init(guest, &args);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create VCPU\n");
- return status;
- }
-
- // Setup UARTs.
- Uart uart[kNumUarts];
- for (size_t i = 0; i < kNumUarts; i++) {
- status = uart[i].Init(&guest, kUartBases[i]);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create UART at %#lx\n", kUartBases[i]);
- return status;
- }
- }
- // Setup interrupt controller.
- InterruptController interrupt_controller;
- status = interrupt_controller.Init(&guest);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create interrupt controller\n");
- return status;
- }
-
-#if __x86_64__
- // Setup local APIC.
- LocalApic local_apic(&vcpu, apic_addr);
- status = local_apic.Init(&guest);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create local APIC\n");
- return status;
- }
- status = interrupt_controller.RegisterLocalApic(0, &local_apic);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to register local APIC with IO APIC\n");
- return status;
- }
- // Setup IO ports.
- IoPort io_port;
- status = io_port.Init(&guest);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create IO ports\n");
- return status;
- }
- // Setup TPM
- Tpm tpm;
- status = tpm.Init(&guest);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create TPM\n");
- return status;
- }
-#endif
-
- // Setup PCI.
- PciBus bus(&guest, &interrupt_controller);
- status = bus.Init();
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create PCI bus\n");
- return status;
- }
-
- // Setup block device.
- VirtioBlock block(physmem_addr, physmem_size);
- PciDevice& virtio_block = block.pci_device();
- if (block_path != NULL) {
- status = block.Init(block_path, guest.phys_mem());
- if (status != ZX_OK)
- return status;
-
- status = block.Start();
- if (status != ZX_OK)
- return status;
-
- status = bus.Connect(&virtio_block, PCI_DEVICE_VIRTIO_BLOCK);
- if (status != ZX_OK)
- return status;
- }
- // Setup memory balloon.
- VirtioBalloon balloon(physmem_addr, physmem_size, guest.phys_mem().vmo());
- balloon.set_deflate_on_demand(balloon_deflate_on_demand);
- status = bus.Connect(&balloon.pci_device(), PCI_DEVICE_VIRTIO_BALLOON);
- if (status != ZX_OK)
- return status;
- if (balloon_poll_interval > 0)
- poll_balloon_stats(&balloon, balloon_poll_interval);
- // Setup Virtio GPU.
- VirtioGpu gpu(physmem_addr, physmem_size);
- VirtioInput input(physmem_addr, physmem_size, "zircon-input", "serial-number");
- if (use_gpu) {
- status = gpu.Init("/dev/class/framebuffer/000");
- if (status != ZX_OK)
- return status;
-
- status = bus.Connect(&gpu.pci_device(), PCI_DEVICE_VIRTIO_GPU);
- if (status != ZX_OK)
- return status;
-
- // Setup input device.
- status = input.Start();
- if (status != ZX_OK)
- return status;
- status = bus.Connect(&input.pci_device(), PCI_DEVICE_VIRTIO_INPUT);
- if (status != ZX_OK)
- return status;
- }
-
- // Setup initial VCPU state.
- zx_vcpu_state_t vcpu_state = {};
-#if __aarch64__
- vcpu_state.x[0] = bootdata_off;
-#elif __x86_64__
- vcpu_state.rsi = bootdata_off;
-#endif
- status = vcpu.WriteState(ZX_VCPU_STATE, &vcpu_state, sizeof(vcpu_state));
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to write VCPU state\n");
- return status;
- }
-
- // Begin VCPU execution.
- return vcpu.Loop();
-}
diff --git a/system/uapp/guest/linux.cpp b/system/uapp/guest/linux.cpp
deleted file mode 100644
index f649712..0000000
--- a/system/uapp/guest/linux.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <hypervisor/guest.h>
-
-#include "linux.h"
-
-// clang-format off
-#define SECTOR_SIZE 512u
-
-#define ALIGN(x, alignment) (((x) + (alignment - 1)) & ~(alignment - 1))
-
-#define ZP8(p, off) (*((uint8_t*)((p) + (off))))
-#define ZP16(p, off) (*((uint16_t*)((p) + (off))))
-#define ZP32(p, off) (*((uint32_t*)((p) + (off))))
-#define ZP64(p, off) (*((uint64_t*)((p) + (off))))
-
-// See https://www.kernel.org/doc/Documentation/x86/boot.txt
-// and https://www.kernel.org/doc/Documentation/x86/zero-page.txt
-// for an explanation of the zero page, setup header and boot params.
-
-// Screen info offsets
-#define ZP_SI_8_VIDEO_MODE 0x0006 // Original video mode
-#define ZP_SI_8_VIDEO_COLS 0x0007 // Original video cols
-#define ZP_SI_8_VIDEO_LINES 0x000e // Original video lines
-
-// Setup header offsets
-#define ZP_SH_8_E820_COUNT 0x01e8 // Number of entries in e820 map
-#define ZP_SH_8_SETUP_SECTS 0x01f1 // Size of real mode kernel in sectors
-#define ZP_SH_8_LOADER_TYPE 0x0210 // Type of bootloader
-#define ZP_SH_8_LOAD_FLAGS 0x0211 // Boot protocol flags
-#define ZP_SH_8_RELOCATABLE 0x0234 // Is the kernel relocatable?
-#define ZP_SH_16_BOOTFLAG 0x01fe // Bootflag, should match BOOT_FLAG_MAGIC
-#define ZP_SH_16_VERSION 0x0206 // Boot protocol version
-#define ZP_SH_16_XLOADFLAGS 0x0236 // 64-bit and EFI load flags
-#define ZP_SH_32_SYSSIZE 0x01f4 // Size of protected-mode code + payload in 16-bytes
-#define ZP_SH_32_HEADER 0x0202 // Header, should match HEADER_MAGIC
-#define ZP_SH_32_RAMDISK_IMAGE 0x0218 // Ramdisk image address
-#define ZP_SH_32_RAMDISK_SIZE 0x021c // Ramdisk image size
-#define ZP_SH_32_COMMAND_LINE 0x0228 // Pointer to command line args string
-#define ZP_SH_32_KERNEL_ALIGN 0x0230 // Kernel alignment
-#define ZP_SH_64_PREF_ADDRESS 0x0258 // Preferred address for kernel to be loaded at
-#define ZP_SH_XX_E820_MAP 0x02d0 // The e820 memory map
-
-#define LF_LOAD_HIGH (1u << 0) // The protected mode code defaults to 0x100000
-#define XLF_KERNEL_64 (1u << 0) // Kernel has legacy 64-bit entry point at 0x200
-
-#define BOOT_FLAG_MAGIC 0xaa55 // Boot flag value to match for Linux
-#define HEADER_MAGIC 0x53726448 // Header value to match for Linux
-#define LEGACY_64_ENTRY_OFFSET 0x200 // Offset for the legacy 64-bit entry point
-#define LOADER_TYPE_UNSPECIFIED 0xff // We are bootloader that Linux knows nothing about
-#define MIN_BOOT_PROTOCOL 0x0200 // The minimum boot protocol we support (bzImage)
-#define MAX_E820_ENTRIES 128 // The space reserved for e820, in entries
-
-// clang-format off
-
-// Default address to load bzImage at
-static const uintptr_t kDefaultKernelOffset = 0x100000;
-static const uintptr_t kInitrdOffset = 0x800000;
-
-static bool is_linux(const uintptr_t zero_page) {
- return ZP16(zero_page, ZP_SH_16_BOOTFLAG) == BOOT_FLAG_MAGIC &&
- ZP32(zero_page, ZP_SH_32_HEADER) == HEADER_MAGIC;
-}
-
-zx_status_t setup_linux(const uintptr_t addr, const size_t size, const uintptr_t first_page,
- const int fd, const char* initrd_path, const char* cmdline,
- uintptr_t* guest_ip, uintptr_t* zero_page_addr) {
- if (!is_linux(first_page))
- return ZX_ERR_NOT_SUPPORTED;
-
- bool has_legacy_entry = ZP16(first_page, ZP_SH_16_XLOADFLAGS) & XLF_KERNEL_64;
- if (!has_legacy_entry) {
- fprintf(stderr, "Kernel lacks the legacy 64-bit entry point\n");
- return ZX_ERR_NOT_SUPPORTED;
- }
-
- uint16_t protocol = ZP16(first_page, ZP_SH_16_VERSION);
- uint8_t loadflags = ZP8(first_page, ZP_SH_8_LOAD_FLAGS);
- bool is_bzimage = (protocol >= MIN_BOOT_PROTOCOL) && (loadflags & LF_LOAD_HIGH);
- if (!is_bzimage) {
- fprintf(stderr, "Kernel is not a bzImage. Use a newer kernel\n");
- return ZX_ERR_NOT_SUPPORTED;
- }
-
- // Default to the preferred address, then change if we're relocatable
- uintptr_t runtime_start = ZP64(first_page, ZP_SH_64_PREF_ADDRESS);
- if (ZP8(first_page, ZP_SH_8_RELOCATABLE) > 0) {
- uint64_t kernel_alignment = ZP32(first_page, ZP_SH_32_KERNEL_ALIGN);
- uint64_t aligned_address = ALIGN(kDefaultKernelOffset, kernel_alignment);
- runtime_start = aligned_address;
- }
-
- // Move the zero-page. For a 64-bit kernel it can go almost anywhere,
- // so we'll put it just below the boot kernel.
- uintptr_t boot_params_off = runtime_start - PAGE_SIZE;
- uint8_t* zero_page = (uint8_t*)(addr + boot_params_off);
- memmove(zero_page, (void*)first_page, PAGE_SIZE);
-
- // Copy the command line string below the zero page.
- size_t cmdline_len = strlen(cmdline) + 1;
- uintptr_t cmdline_off = boot_params_off - cmdline_len;
- if (cmdline_off > UINT32_MAX) {
- fprintf(stderr, "Command line offset is outside of 32-bit range\n");
- return ZX_ERR_OUT_OF_RANGE;
- }
- memcpy((char*)(addr + cmdline_off), cmdline, cmdline_len);
- ZP32(zero_page, ZP_SH_32_COMMAND_LINE) = static_cast<uint32_t>(cmdline_off);
-
- // Set type of bootloader.
- ZP8(zero_page, ZP_SH_8_LOADER_TYPE) = LOADER_TYPE_UNSPECIFIED;
-
- // Zero video, columns and lines to skip early video init - just serial output for now.
- ZP8(zero_page, ZP_SI_8_VIDEO_MODE) = 0;
- ZP8(zero_page, ZP_SI_8_VIDEO_COLS) = 0;
- ZP8(zero_page, ZP_SI_8_VIDEO_LINES) = 0;
-
- // Setup e820 memory map.
- size_t e820_entries = guest_e820_size(size) / sizeof(e820entry_t);
- if (e820_entries > MAX_E820_ENTRIES) {
- fprintf(stderr, "Not enough space for e820 memory map\n");
- return ZX_ERR_BAD_STATE;
- }
- ZP8(zero_page, ZP_SH_8_E820_COUNT) = static_cast<uint8_t>(e820_entries);
-
- uintptr_t e820_off = boot_params_off + ZP_SH_XX_E820_MAP;
- zx_status_t status = guest_create_e820(addr, size, e820_off);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create the e820 memory map\n");
- return status;
- }
-
- int setup_sects = ZP8(zero_page, ZP_SH_8_SETUP_SECTS);
- if (setup_sects == 0) {
- // 0 here actually means 4, see boot.txt.
- setup_sects = 4;
- }
-
- // Read the rest of the bzImage into the protected_mode_kernel location.
- int protected_mode_off = (setup_sects + 1) * SECTOR_SIZE;
- off_t ret = lseek(fd, protected_mode_off, SEEK_SET);
- if (ret < 0) {
- fprintf(stderr, "Failed seek to protected mode kernel\n");
- return ZX_ERR_IO;
- }
-
- size_t remaining = ZP32(zero_page, ZP_SH_32_SYSSIZE) << 4;
- ret = read(fd, (void*)(addr + runtime_start), remaining);
- if ((size_t)ret != remaining) {
- fprintf(stderr, "Failed to read Linux kernel data\n");
- return ZX_ERR_IO;
- }
-
- if (initrd_path) {
- ZP32(zero_page, ZP_SH_32_RAMDISK_IMAGE) = kInitrdOffset;
- int initrd_fd = open(initrd_path, O_RDONLY);
- if (initrd_fd < 0) {
- fprintf(stderr, "Failed to open initial RAM disk\n");
- return ZX_ERR_IO;
- }
- struct stat initrd_stat;
- off_t ret = fstat(initrd_fd, &initrd_stat);
- if (ret < 0) {
- fprintf(stderr, "Failed to stat initial RAM disk\n");
- return ZX_ERR_IO;
- }
- if (initrd_stat.st_size > UINT32_MAX ||
- static_cast<size_t>(initrd_stat.st_size) > size - kInitrdOffset) {
- fprintf(stderr, "Initial RAM disk is too large\n");
- return ZX_ERR_OUT_OF_RANGE;
- }
- ZP32(zero_page, ZP_SH_32_RAMDISK_SIZE) = static_cast<uint32_t>(initrd_stat.st_size);
- ret = read(initrd_fd, (void*)(addr + kInitrdOffset), initrd_stat.st_size);
- if (ret != initrd_stat.st_size) {
- fprintf(stderr, "Failed to read initial RAM disk\n");
- return ZX_ERR_IO;
- }
- }
-
- *guest_ip = runtime_start + LEGACY_64_ENTRY_OFFSET;
- *zero_page_addr = boot_params_off;
- return ZX_OK;
-}
diff --git a/system/uapp/guest/linux.h b/system/uapp/guest/linux.h
deleted file mode 100644
index e7d2ec1..0000000
--- a/system/uapp/guest/linux.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <zircon/types.h>
-
-zx_status_t setup_linux(const uintptr_t addr, const size_t size, const uintptr_t first_page,
- const int fd, const char* initrd_path, const char* cmdline,
- uintptr_t* guest_ip, uintptr_t* zero_page);
diff --git a/system/uapp/guest/rules.mk b/system/uapp/guest/rules.mk
deleted file mode 100644
index 02df0e6..0000000
--- a/system/uapp/guest/rules.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2017 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-LOCAL_DIR := $(GET_LOCAL_DIR)
-
-MODULE := $(LOCAL_DIR)
-
-MODULE_TYPE := userapp
-MODULE_GROUP := misc
-
-MODULE_SRCS += \
- $(LOCAL_DIR)/guest.cpp \
- $(LOCAL_DIR)/linux.cpp \
- $(LOCAL_DIR)/zircon.cpp \
-
-MODULE_HEADER_DEPS := \
- system/ulib/hid \
- system/ulib/virtio \
-
-MODULE_LIBS := \
- system/ulib/c \
- system/ulib/fdio \
- system/ulib/machina \
- system/ulib/zircon \
-
-MODULE_STATIC_LIBS := \
- system/ulib/fbl \
- system/ulib/hypervisor \
- system/ulib/zx \
- system/ulib/zxcpp \
-
-MODULE_CPPFLAGS += \
- -Isystem/ulib/hypervisor/arch/$(ARCH)/include \
- -Isystem/ulib/machina/arch/$(ARCH)/include \
-
-include make/module.mk
diff --git a/system/uapp/guest/scripts/bootstrap-debian.sh b/system/uapp/guest/scripts/bootstrap-debian.sh
deleted file mode 100755
index d4f6dac..0000000
--- a/system/uapp/guest/scripts/bootstrap-debian.sh
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2017 The Fuchsia Authors
-#
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file or at
-# https://opensource.org/licenses/MIT
-
-set -e
-
-# List of packages to install into the system on top of the minimal base
-# image.
-EXTRA_PACKAGES=(
- # Make ourselves bootable
- linux-image-amd64
- grub-efi
-
- # Misc utilities
- ca-certificates
- cpuid
- curl
- debootstrap
- git
- less
- sudo
- tmux
- unzip
- vim
- wget
-
- # Allows mounting the root fs as RO with a ramdisk overlay for ephemeral
- # writes.
- bilibop-lockfs
-
- # Support zircon build deps:
- texinfo
- libglib2.0-dev
- autoconf
- libtool
- libsdl1.2-dev
- build-essential
-
- # Unixbench deps:
- libx11-dev
- libgl1-mesa-dev
- libxext-dev
- make
- perl
- perl-modules
-
- # hdparm benchmark
- hdparm
-
- # QEMU/KVM guest support.
- qemu-kvm
-)
-
-usage() {
- echo "usage: ${0} [mountpoint]"
- echo ""
- echo " Bootstraps a debian system image into the partition mounted at"
- echo " [mountpoint]. The built system will contain the minimal base Debian"
- echo " system along with whats needed for the following benchmarks:"
- echo ""
- echo " * hdparm"
- echo " * unixbench"
- echo ""
- echo " Additional packages can be manually added by chrooting into the"
- echo " created system and running apt directly. To use this partition"
- echo " in a guest system simply pass the block device file to guest."
- echo ""
- echo " This script creates a user with username/password of bench:password"
- echo " with sudo access."
- echo ""
- echo "Example:"
- echo ""
- echo " $ sudo mount /dev/sda1 /mnt"
- echo " $ sudo bootstrap-debian.sh /mnt"
- echo ""
- echo "Add additional packages:"
- echo " $ sudo chroot /mnt /bin/bash"
- echo " # apt install <package>"
- echo ""
- exit 1
-}
-
-# We expect a single positional argument specifying the mount point.
-check_args() {
- if [ "$#" -ne 1 ]; then
- usage
- fi
-}
-
-check_deps() {
- type -P debootstrap &>/dev/null && return 0
-
- echo "Required package debootstrap is not installed. (sudo apt install debootstrap)"
- exit 1
-}
-
-check_mountpoint() {
- mountpoint -q $1 && return 0
-
- echo "Provided path '$1' is not a mountpoint. Check your arguments."
- echo ""
- usage
-}
-
-# Stage2 is run from within the chroot of the new system so all system commands
-# modify the new system and not the host.
-bootstrap_stage2() {
- # Install additional packages.
- DEBIAN_FRONTEND=noninteractive apt-get -y --allow-unauthenticated install ${EXTRA_PACKAGES[*]}
-
- # Setup grub.
- grub-install --target x86_64-efi --efi-directory /boot --removable
- cat >> /etc/grub.d/40_custom << EOF
-menuentry "Zircon" {
- insmod chain
- echo "Loading gigaboot..."
- chainloader /EFI/BOOT/gigaboot.efi
-}
-EOF
- update-grub
-
- # Create default account.
- local username="bench"
- local default_password="password"
- useradd ${username} -G sudo
- echo "${username}:${default_password}" | chpasswd
- echo "Default login/password is ${username}:${default_password}" > /etc/issue
-
- # Setup home directory.
- local user_home=/home/${username}
- mkdir -p ${user_home}
-
- # Set login shell.
- chsh -s /bin/bash ${username}
-
- # Get unix-bench
- pushd ${user_home}
- local unixbench_zip="${user_home}/unixbench.zip"
- wget https://github.com/kdlucas/byte-unixbench/archive/master.zip -O "${unixbench_zip}"
- unzip "${unixbench_zip}"
- rm "${unixbench_zip}"
- popd
-
- # Setup hostname.
- echo "zircon-guest" > /etc/hostname
-
- # Make sure all created files have appropriate ownership.
- chown -R ${username}:${username} ${user_home}
-
- # Clear out the package cache.
- apt clean
-}
-
-if [ "${SECOND_STAGE}" != "true" ]; then
- check_args "$@"
-
- check_deps
-
- check_mountpoint "${1}"
-
- debootstrap testing "${1}" http://deb.debian.org/debian/
-
- # Copy ourselves into the chroot and run the second stage.
- cp "${BASH_SOURCE[0]}" "${1}/second-stage.sh"
- mount --bind /dev "${1}/dev"
- SECOND_STAGE=true chroot ${1} "/second-stage.sh"
- umount "${1}/dev"
-else
- bootstrap_stage2
-
- rm "/second-stage.sh"
-fi
diff --git a/system/uapp/guest/scripts/build-bootable-usb-multiboot.sh b/system/uapp/guest/scripts/build-bootable-usb-multiboot.sh
deleted file mode 100755
index 8ca0e7c..0000000
--- a/system/uapp/guest/scripts/build-bootable-usb-multiboot.sh
+++ /dev/null
@@ -1,246 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright 2017 The Fuchsia Authors
-#
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file or at
-# https://opensource.org/licenses/MIT
-
-set -eu
-
-GUEST_SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-ZIRCONDIR="${ZIRCON_DIR:-${GUEST_SCRIPTS_DIR}/../../../..}"
-ZIRCON_SCRIPTS_DIR="${ZIRCONDIR}/scripts"
-BUILDDIR="${ZIRCONDIR}/build-zircon-pc-x86-64"
-
-get_confirmation() {
- echo -n "Press 'y' to confirm: "
- read CONFIRM
- if [[ "$CONFIRM" != "y" ]]; then
- echo "[format_usb] Aborted due to invalid confirmation"
- exit 1
- fi
-}
-
-command -v sgdisk > /dev/null 2>&1 || {
- echo "[format_usb] Requires the sgdisk command"
- echo "sudo apt-get install gdisk"
- exit 1
-}
-
-usage() {
- echo "build-bootable-usb-multiboot.sh"
- echo ""
- echo "Formats a USB drive with a GRUB bootloader that can either boot"
- echo "Debian or Zircon (via gigaboot)."
-}
-
-lsblk
-echo "Enter the name of a block device to format: "
-echo " This will probably be of the form 'sd[letter]', like 'sdc'"
-echo -n "> "
-read DEVICE
-
-# Ensure that device exists
-echo -n "[format_usb] Checking that device exists: $DEVICE ..."
-DEVICE_PATH="/dev/$DEVICE"
-if [[ ! -e "$DEVICE_PATH" ]]; then
- echo " FAILED"
- echo "[format_usb] ERROR: This device does not exist: $DEVICE_PATH"
- exit 1
-fi
-echo " SUCCESS"
-
-# Ensure that the device is a real block device
-echo -n "[format_usb] Checking that device is a known block device..."
-if [[ ! -e "/sys/block/$DEVICE" ]]; then
- echo " FAILED"
- echo "[format_usb] ERROR: /sys/block/$DEVICE does not exist."
- echo " Does $DEVICE refer to a partition?"
- exit 1
-fi
-echo " SUCCESS"
-
-# Try to check that the device is a USB stick
-echo -n "[format_usb] Checking if device is USB: $DEVICE ..."
-READLINK_USB=$(readlink -f "/sys/class/block/$DEVICE/device" | { grep -i "usb" || true; })
-if [[ -z "$READLINK_USB" ]]; then
- echo " FAILED"
- echo "[format_usb] ERROR: Cannot confirm that device is a USB stick"
- echo "[format_usb] ERROR: Please insert USB stick and retry"
- exit 1
-fi
-echo " SUCCESS"
-
-# Ensure the device is not mounted
-echo -n "[format_usb] Checking that device is not mounted: $DEVICE ..."
-if [[ -n $(df -Hl | grep "$DEVICE") ]]; then
- echo " FAILED"
- echo "[format_usb] ERROR: Your device appears to be mounted: "
- echo "..."
- df -Hl | grep "$DEVICE"
- echo "..."
- echo "[format_usb] ERROR: Please unmount your device and retry"
- exit 1
-fi
-echo " SUCCESS"
-
-echo -n "Building zircon..."
-${ZIRCON_SCRIPTS_DIR}/build-zircon-x86-64
-${GUEST_SCRIPTS_DIR}/mkbootfs.sh zircon-pc-x86-64
-echo " SUCCESS"
-
-echo -n "Building zircon-guest kernel..."
-$GUEST_SCRIPTS_DIR/mklinux.sh
-echo " SUCCESS"
-
-# Confirm that the user knows what they are doing
-sudo -v -p "[sudo] Enter password to confirm information about device: "
-sudo sgdisk -p "$DEVICE_PATH"
-echo "[format_usb] ABOUT TO COMPLETELY WIPE / FORMAT: $DEVICE_PATH"
-get_confirmation
-echo "[format_usb] ARE YOU 100% SURE?"
-get_confirmation
-
-echo "[format_usb] Deleting all partition info on USB, creating new GPT"
-sudo sgdisk -og "$DEVICE_PATH"
-
-SECTOR_SIZE=`cat "/sys/block/$DEVICE/queue/hw_sector_size"`
-
-echo "[format_usb] Creating 200MB EFI System Partition"
-sudo sgdisk -n 1:0:+200M -c 1:"EFI System Partition" -t 1:ef00 "$DEVICE_PATH"
-EFI_PARTITION_PATH="${DEVICE_PATH}1"
-sudo mkfs.vfat "$EFI_PARTITION_PATH"
-
-echo "[format_usb] Creating 5GB Linux Root Partition"
-sudo sgdisk -n 2:0:+5G -c 2:"Root" "$DEVICE_PATH"
-ROOT_PARTITION_PATH="${DEVICE_PATH}2"
-sudo mkfs.ext4 "$ROOT_PARTITION_PATH"
-
-echo "[format_usb] Creating 2GB Linux Home Partition"
-sudo sgdisk -n 3:0:+2G -c 3:"Home" "$DEVICE_PATH"
-HOME_PARTITION_PATH="${DEVICE_PATH}3"
-sudo mkfs.ext4 "$HOME_PARTITION_PATH"
-
-# Function to attempt unmounting a mount point up to three times, sleeping
-# a couple of seconds between attempts.
-function umount_retry() {
- set +e
- TRIES=0
- while (! sudo umount $1); do
- ((TRIES++))
- if [[ ${TRIES} > 2 ]]; then
- echo "[format_usb] Unable to umount $0"
- exit 1
- fi
- sleep 2
- done
- set -e
-}
-
-MOUNT_PATH=`mktemp -d`
-EFI_MOUNT_PATH="${MOUNT_PATH}/boot"
-HOME_MOUNT_PATH="${MOUNT_PATH}/home"
-sudo mount "${ROOT_PARTITION_PATH}" "${MOUNT_PATH}"
-sudo mkdir -p "${EFI_MOUNT_PATH}"
-sudo mkdir -p "${HOME_MOUNT_PATH}"
-sudo mkdir -p "${MOUNT_PATH}/dev"
-sudo mkdir -p "${MOUNT_PATH}/sys"
-sudo mkdir -p "${MOUNT_PATH}/proc"
-
-sudo mount "${EFI_PARTITION_PATH}" "${EFI_MOUNT_PATH}"
-sudo mount "${HOME_PARTITION_PATH}" "${HOME_MOUNT_PATH}"
-sudo mount --bind /sys "${MOUNT_PATH}/sys"
-sudo mount --bind /proc "${MOUNT_PATH}/proc"
-
-unmount_all() {
- umount_retry "${EFI_MOUNT_PATH}"
- umount_retry "${HOME_MOUNT_PATH}"
- umount_retry "${MOUNT_PATH}/sys"
- umount_retry "${MOUNT_PATH}/proc"
- umount_retry "${MOUNT_PATH}"
-
- rm -rf "${MOUNT_PATH}"
- echo "Unmounted successfully"
-
-}
-trap "unmount_all" INT TERM EXIT
-
-echo -n "Installing Debian base system ..."
-sudo "${GUEST_SCRIPTS_DIR}/bootstrap-debian.sh" "${MOUNT_PATH}"
-echo " SUCCESS"
-
-sudo mkdir -p "${EFI_MOUNT_PATH}/EFI/BOOT"
-echo -n "Copying Bootloader..."
-sudo cp "${BUILDDIR}/bootloader/bootx64.efi" "${EFI_MOUNT_PATH}/EFI/BOOT/gigaboot.efi"
-echo " SUCCESS"
-
-echo -n "Copying zircon.bin..."
-sudo cp "${BUILDDIR}/zircon.bin" "${EFI_MOUNT_PATH}/zircon.bin"
-sudo cp "${BUILDDIR}/bootdata-with-guest.bin" "${EFI_MOUNT_PATH}/ramdisk.bin"
-echo " SUCCESS"
-
-echo -n "Copying fstab..."
-ROOT_UUID=$(sudo blkid -s UUID -o value "${ROOT_PARTITION_PATH}")
-EFI_UUID=$(sudo blkid -s UUID -o value "${EFI_PARTITION_PATH}")
-HOME_UUID=$(sudo blkid -s UUID -o value "${HOME_PARTITION_PATH}")
-FSTAB=$(mktemp)
-echo "" > "${FSTAB}"
-echo "UUID=${EFI_UUID} /boot vfat defaults,iversion,nofail 0 1" > "${FSTAB}"
-sudo cp "${FSTAB}" "${MOUNT_PATH}/etc/fstab"
-rm "${FSTAB}"
-echo "SUCCESS"
-
-echo -n "Copying run-qemu.sh..."
-sudo cp /tmp/linux/arch/x86/boot/bzImage "${MOUNT_PATH}/opt/bzImage"
-RUN_QEMU=$(mktemp)
-
-###############################################################################
-# Emit run-qemu.sh.
-###############################################################################
-cat > "${RUN_QEMU}" << EOF
-#!/bin/sh
-
-KERNEL_CMDLINE="root=/dev/vda ro lockfs console=ttyS0 io_delay=none"
-CPU_SPEC="host,migratable=no"
-KVM_DISABLE_PARAVIRT_FEATURES="-kvmclock,-kvm-nopiodelay,-kvm-asyncpf,-kvm-steal-time,-kvm-pv-eoi,-kvmclock-stable-bit,-kvm-pv-unhalt"
-
-usage() {
- echo "usage: run-qemu.sh [options]"
- echo ""
- echo " -p Disable KVM paravirt features."
-}
-
-while getopts "p" opt; do
- case "\${opt}" in
- p) CPU_SPEC="\${CPU_SPEC},\${KVM_DISABLE_PARAVIRT_FEATURES}" ;;
- *) usage ;;
- esac
-done
-
-qemu-system-x86_64 \\
- -nographic \\
- -drive file=/dev/disk/by-uuid/${ROOT_UUID},readonly=on,format=raw,if=none,cache=none,id=root \\
- -device virtio-blk-pci,drive=root \\
- -drive file=/dev/disk/by-uuid/${HOME_UUID},format=raw,if=none,cache=none,id=home \\
- -device virtio-blk-pci,drive=home \\
- -device virtio-serial-pci \\
- -net none \\
- -machine q35 \\
- -m 1G \\
- -smp 1 \\
- -enable-kvm \\
- -cpu "\${CPU_SPEC}" \\
- -initrd /initrd.img \\
- -kernel /opt/bzImage \\
- -append "\${KERNEL_CMDLINE}"
-EOF
-###############################################################################
-# End run-qemu.sh
-###############################################################################
-sudo cp "${RUN_QEMU}" "${MOUNT_PATH}/opt/run-qemu.sh"
-sudo chmod +x "${MOUNT_PATH}/opt/run-qemu.sh"
-rm "${RUN_QEMU}"
-echo " SUCCESS"
-
-# Filesystems will be unmounted at exit by the trap set above.
diff --git a/system/uapp/guest/scripts/mkbootfs.sh b/system/uapp/guest/scripts/mkbootfs.sh
deleted file mode 100755
index eb01281..0000000
--- a/system/uapp/guest/scripts/mkbootfs.sh
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2017 The Fuchsia Authors
-#
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file or at
-# https://opensource.org/licenses/MIT
-
-set -e
-
-usage() {
- echo "usage: ${0} build-dir [options]"
- echo ""
- echo " -f user.bootfs Fuchsia bootfs"
- echo " -z zircon.bin Zircon kernel"
- echo " -b bootdata.bin Zircon bootfs"
- echo " -g zircon.gpt Zircon GPT disk image"
- echo " -l bzImage Linux kernel"
- echo " -i initrd Linux initrd"
- echo " -r rootfs.ext2 Linux EXT2 root filesystem image"
- echo ""
- exit 1
-}
-
-GUEST_SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-ZIRCON_DIR="$GUEST_SCRIPTS_DIR/../../../.."
-
-while getopts "f:z:b:l:i:r:g:" opt; do
- case "${opt}" in
- f) HOST_BOOTFS="${OPTARG}" ;;
- z) ZIRCON="${OPTARG}" ;;
- b) BOOTDATA="${OPTARG}" ;;
- g) ZIRCON_DISK="${OPTARG}" ;;
- l) BZIMAGE="${OPTARG}" ;;
- i) INITRD="${OPTARG}" ;;
- r) ROOTFS="${OPTARG}" ;;
- *) usage ;;
- esac
-done
-shift $((OPTIND-1))
-
-if [ ! -d "$1" ]; then
- echo "Build directory '$1' does not exit."
- usage
-fi
-
-declare -r HOST_BOOTFS=${HOST_BOOTFS:-$1/bootdata.bin}
-declare -r ZIRCON=${ZIRCON:-$1/zircon.bin}
-declare -r BOOTDATA=${BOOTDATA:-$1/bootdata.bin}
-declare -r ZIRCON_DISK=${ZIRCON_DISK:-$1/zircon.gpt}
-declare -r BZIMAGE=${BZIMAGE:-/tmp/linux/arch/x86/boot/bzImage}
-declare -r INITRD=${INITRD:-/tmp/toybox/initrd.gz}
-declare -r ROOTFS=${ROOTFS:-/tmp/toybox/rootfs.ext2}
-
-echo "
-data/dsdt.aml=$ZIRCON_DIR/system/ulib/hypervisor/arch/x86/acpi/dsdt.aml
-data/madt.aml=$ZIRCON_DIR/system/ulib/hypervisor/arch/x86/acpi/madt.aml
-data/mcfg.aml=$ZIRCON_DIR/system/ulib/hypervisor/arch/x86/acpi/mcfg.aml
-data/zircon.bin=$ZIRCON
-data/bootdata.bin=$BOOTDATA" > /tmp/guest.manifest
-
-if [ -f "$ZIRCON_DISK" ]; then
- echo "data/zircon.gpt=$ZIRCON_DISK" >> /tmp/guest.manifest
-fi
-
-if [ -f "$BZIMAGE" ]; then
- echo "data/bzImage=$BZIMAGE" >> /tmp/guest.manifest
-fi
-
-if [ -f "$INITRD" ]; then
- echo "data/initrd=$INITRD" >> /tmp/guest.manifest
-fi
-
-if [ -f "$ROOTFS" ]; then
- echo "data/rootfs.ext2=$ROOTFS" >> /tmp/guest.manifest
-fi
-
-$1/tools/mkbootfs \
- --target=boot \
- -o bootdata-with-guest.bin \
- "${HOST_BOOTFS}" \
- /tmp/guest.manifest
diff --git a/system/uapp/guest/scripts/mkgpt.sh b/system/uapp/guest/scripts/mkgpt.sh
deleted file mode 100755
index 1ba0059..0000000
--- a/system/uapp/guest/scripts/mkgpt.sh
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2017 The Fuchsia Authors
-#
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file or at
-# https://opensource.org/licenses/MIT
-#
-# Create a GPT disk image for zircon guests.
-
-set -eo pipefail
-
-GUEST_SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-ZIRCONDIR="${ZIRCON_DIR:-${GUEST_SCRIPTS_DIR}/../../../..}"
-BUILDDIR="${ZIRCON_BUILD_DIR:-$ZIRCONDIR/build-zircon-pc-x86-64}"
-MINFS="${BUILDDIR}/tools/minfs"
-
-# Zircon's block-watcher will auto mount GPT partitions with this GUID as
-# the system partition.
-ZIRCON_SYSTEM_GUID="606B000B-B7C7-4653-A7D5-B737332C899D"
-ZIRCON_GPT_IMAGE="${BUILDDIR}/zircon.gpt"
-ZIRCON_SYSTEM_IMAGE="${BUILDDIR}/system.minfs"
-
-usage() {
- echo "usage: ${0} [-f]"
- echo ""
- echo " -f Force a rebuild even if the artifact already exists."
- echo ""
- exit 1
-}
-
-# sgdisk is used to manipulate GPT partition tables.
-check_sgdisk() {
- type -P sgdisk &>/dev/null && return 0
-
- # sgdisk is provided by the gdisk package.
- echo "Required package gdisk is not installed. (sudo apt install gdisk)"
- exit 1
-}
-
-# Create a minfs system image file.
-#
-# $1 - Image filename.
-# $2 - Integer number of MB to make the partition.
-generate_system_image() {
- local image=${1}
- local sys_part_size_mb=${2}
-
- dd if=/dev/zero of="${image}" bs=1M count="${sys_part_size_mb}"
- ${MINFS} ${image} create
- ${MINFS} ${image} mkdir ::/bin
-
- # Copy binaries from system/uapp into the system image.
- for app_path in `find "${BUILDDIR}/system/uapp" -iname "*.elf"`; do
- local exe_name=`basename "${app_path}"`
- # Strip the '.elf' file extension.
- local app="${exe_name%.*}"
- ${MINFS} ${image} cp "${app_path}" ::/bin/${app}
- done
-}
-
-# Creates a GPT disk image file with a single system partition.
-#
-# $1 - GPT image name.
-# $2 - System partition image path.
-generate_gpt_image() {
- local image=${1}
- local system_image=${2}
-
- # sgdisk operates on 512 byte sector addresses.
- local sys_part_size=`du --block-size 512 ${system_image} | cut -f 1`
- local sys_start_sector=2048
- local sys_end_sector=$((${sys_part_size} + ${sys_start_sector}))
-
- dd if=/dev/zero of="${image}" bs=512 count="$((${sys_end_sector} + 2048))"
-
- sgdisk --new 1:${sys_start_sector}:${sys_end_sector} ${image}
- sgdisk --typecode 1:${ZIRCON_SYSTEM_GUID} ${image}
- sgdisk --print ${image}
-
- # Copy bytes from the system image into the correct location in the GPT
- # image.
- dd if="${system_image}" \
- of="${image}" \
- bs=512 \
- seek="${sys_start_sector}" \
- count=${sys_part_size} \
- conv=notrunc
-}
-
-declare FORCE="${FORCE:-false}"
-
-while getopts "f" opt; do
- case "${opt}" in
- f) FORCE="true" ;;
- *) usage ;;
- esac
-done
-
-readonly "${FORCE}"
-
-check_sgdisk
-
-# Are the requested targets up-to-date?
-if [ "${FORCE}" != "true" ] && [ -f "${ZIRCON_GPT_IMAGE}" ]; then
- echo "GPT image already exists. Pass -f to force a rebuild."
- exit 0
-fi
-
-generate_system_image "${ZIRCON_SYSTEM_IMAGE}" "20"
-generate_gpt_image "${ZIRCON_GPT_IMAGE}" "${ZIRCON_SYSTEM_IMAGE}"
diff --git a/system/uapp/guest/scripts/mklinux.sh b/system/uapp/guest/scripts/mklinux.sh
deleted file mode 100755
index 3e0e1d5..0000000
--- a/system/uapp/guest/scripts/mklinux.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2017 The Fuchsia Authors
-#
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file or at
-# https://opensource.org/licenses/MIT
-#
-# Clone and build a Linux kernel for use as a guest.
-
-set -e
-
-LINUXDIR=/tmp/linux
-DEFCONFIG=machina_defconfig
-
-while getopts "c:d:" OPT; do
- case $OPT in
- c) DEFCONFIG="$OPTARG" ;;
- d) LINUXDIR="$OPTARG" ;;
- esac
-done
-
-echo "Building linux with $DEFCONFIG in $LINUXDIR"
-
-# Shallow clone the repository.
-if [ ! -d "$LINUXDIR" ]; then
- git clone --depth 1 https://zircon-guest.googlesource.com/third_party/linux "$LINUXDIR"
-fi
-
-# Update the repository.
-cd "$LINUXDIR"
-git pull
-
-# Build Linux.
-make "$DEFCONFIG"
-make -j $(getconf _NPROCESSORS_ONLN)
diff --git a/system/uapp/guest/scripts/mksysroot.sh b/system/uapp/guest/scripts/mksysroot.sh
deleted file mode 100755
index d25c5cb..0000000
--- a/system/uapp/guest/scripts/mksysroot.sh
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2017 The Fuchsia Authors
-#
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file or at
-# https://opensource.org/licenses/MIT
-#
-# Download and build toybox to be an initrd for linux
-# and download and build dash as the system shell.
-#
-# More additions to come as and when desired / needed.
-
-set -eo pipefail
-
-GUEST_SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-
-# Where the toybox sources are expected to be.
-TOYBOX_SRC_DIR="/tmp/toybox"
-
-# Toybox initrd file.
-TOYBOX_INITRD="$TOYBOX_SRC_DIR/initrd.gz"
-
-# Toybox root filesystem image.
-TOYBOX_ROOTFS="$TOYBOX_SRC_DIR/rootfs.ext2"
-
-# Where to prep the toybox directory structure.
-TOYBOX_SYSROOT="$TOYBOX_SRC_DIR/fs"
-
-# Where the dash sources are expected to be.
-DASH_SRC_DIR="/tmp/dash"
-
-usage() {
- echo "usage: ${0} [-rif] [-d toybox_dir] [-s dash_dir]"
- echo ""
- echo " -r Build ext2 filesystem image."
- echo " -i Build initrd CPIO archive."
- echo " -f Force a rebuild even if the artifact already exists."
- echo " -d Directory to clone toybox into."
- echo " -s Directory to clone dash into."
- echo ""
- exit 1
-}
-
-# Ensures the toybox sources are downloaded.
-#
-# $1 - Directory to unpack the sources into.
-get_toybox_source() {
- local toybox_src=$1
-
- if [ ! -d "$toybox_src" ]; then
- git clone --depth 1 https://zircon-guest.googlesource.com/third_party/toybox "$toybox_src"
- fi
-}
-
-# Build toybox and create a sysroot.
-#
-# $1 - Toybox source directory.
-# $2 - Directory to build the toybox sysroot with the toybox binary and symlinks.
-build_toybox() {
- local toybox_src=$1
- local sysroot_dir="$2"
-
- make -C "$toybox_src" defconfig
-
- LDFLAGS="--static" make -C "$toybox_src" -j100
-
- mkdir -p "$sysroot_dir"/{bin,sbin,etc,proc,sys,usr/{bin,sbin},dev,tmp}
- PREFIX=$sysroot_dir make -C "$toybox_src" install
-}
-
-# Ensures the dash sources are downloaded.
-#
-# $1 - Directory to unpack the sources into.
-get_dash_source() {
- local dash_src=$1
-
- if [ ! -d "$dash_src" ]; then
- git clone --depth 1 https://zircon-guest.googlesource.com/third_party/dash "$dash_src"
- fi
-}
-
-# Build dash, copy it to sysroot and make it sh.
-#
-# $1 - Dash source directory.
-# $2 - Directory of toybox sysroot.
-build_dash() {
- local dash_src=$1
- local sysroot_dir="$2"
-
- ( cd $dash_src && ./autogen.sh && ./configure LDFLAGS="-static" && make )
- mkdir -p "$sysroot_dir/bin"
- # TODO(andymutton): Remove the -f when we can disable toysh in the toybox repo
- cp -f "$dash_src/src/dash" "$sysroot_dir/bin/sh"
-}
-
-# Generate a simple init script at /init in the target sysroot.
-#
-# $1 - Toybox source directory.
-# $2 - Toybox sysroot directory.
-generate_init() {
- local toybox_src="$1"
- local sysroot_dir="$2"
-
- # Write an init script for toybox.
- cat > "$sysroot_dir/init" <<'_EOF'
-#!/bin/sh
-mount -t proc none /proc
-mount -t sysfs none /sys
-mount -t devtmpfs none /dev
-echo Launched toybox
-/bin/sh
-_EOF
-
- chmod +x "$sysroot_dir/init"
-}
-
-# Generate a gzipped CPIO archive of the toybox sysroot.
-#
-# $1 - Toybox sysroot directory.
-# $2 - Filepath of the created initrd.
-package_initrd() {
- local sysroot="$1"
- local initrd="$2"
- (cd "$sysroot" && find . -print0 \
- | cpio --null -o --format=newc \
- | gzip -9 > $initrd)
-}
-
-# e2tools provides utilities for manipulating EXT2 filesystems.
-check_e2tools() {
- type -P e2cp &>/dev/null && return 0
-
- echo "Required package e2tools is not installed. (sudo apt install e2tools)"
- exit 1
-}
-
-# Generate an EXT2 filesystem image of the toybox sysroot.
-#
-# $1 - Toybox sysroot directory.
-# $2 - Filepath of the created EXT2 image file.
-package_rootfs() {
- local sysroot="$1"
- local rootfs="$2"
-
- dd if=/dev/zero of=$rootfs bs=1M count=20
- mkfs.ext2 -F $rootfs
-
- for dir in `find "${sysroot}" -type d -printf '%P\n'`; do
- e2mkdir "${rootfs}:/${dir}"
- done
-
- for file in `find "${sysroot}" -type f -printf '%P\n'`; do
- e2cp -p -G 0 -O 0 "${sysroot}/${file}" "${rootfs}:/${file}"
- done
-
- # e2cp follows symlinks which would create a copy of the toybox binary for
- # every link. To work around this we enumerate all the symlinks in the
- # sysroot and create a corresponding hardlink in the ext2 filesystem (e2ln
- # does not currently support soft links).
- for link in `find "${sysroot}" -type l -printf '%P\n'`; do
- local dirname=`dirname ${link}`
- local target=`readlink "${sysroot}/${link}"`
- e2ln "${rootfs}:${dirname}/${target}" "/${link}"
- done
-}
-
-declare FORCE="${FORCE:-false}"
-declare BUILD_INITRD="${BUILD_INITRD:-false}"
-declare BUILD_ROOTFS="${BUILD_ROOTFS:-false}"
-
-while getopts "fird:s:" opt; do
- case "${opt}" in
- f) FORCE="true" ;;
- i) BUILD_INITRD="true" ;;
- r) BUILD_ROOTFS="true" ;;
- d) TOYBOX_SRC_DIR="${OPTARG}" ;;
- s) DASH_SRC_DIR="${OPTARG}" ;;
- *) usage ;;
- esac
-done
-
-# Do we have something to build?
-if [[ ! "${BUILD_INITRD}" = "true" ]] && [[ ! "${BUILD_ROOTFS}" = "true" ]]; then
- echo "Either -r or -i is required."
- usage
-fi
-
-# Are the requested targets up-to-date?
-if [[ ! "${FORCE}" = "true" ]]; then
- if [[ -f "${TOYBOX_INITRD}" ]]; then
- BUILD_INITRD="false"
- fi
- if [[ -f "${TOYBOX_ROOTFS}" ]]; then
- BUILD_ROOTFS="false"
- fi
-fi
-if [[ ! "${BUILD_INITRD}" = "true" ]] && [[ ! "${BUILD_ROOTFS}" = "true" ]]; then
- echo "All targets up to date. Pass -f to force a rebuild."
- exit 0
-fi
-
-readonly "${FORCE}" "${BUILD_INITRD}" "${BUILD_ROOTFS}"
-
-if [[ "${BUILD_ROOTFS}" = "true" ]]; then
- check_e2tools
-fi
-
-get_toybox_source "${TOYBOX_SRC_DIR}"
-
-build_toybox "${TOYBOX_SRC_DIR}" "${TOYBOX_SYSROOT}"
-
-get_dash_source "${DASH_SRC_DIR}"
-
-build_dash "${DASH_SRC_DIR}" "${TOYBOX_SYSROOT}"
-
-generate_init "${TOYBOX_SRC_DIR}" "${TOYBOX_SYSROOT}"
-
-if [[ "${BUILD_INITRD}" = "true" ]]; then
- package_initrd "${TOYBOX_SYSROOT}" "${TOYBOX_INITRD}"
- echo "initrd at ${TOYBOX_INITRD}"
-fi
-
-if [[ "${BUILD_ROOTFS}" = "true" ]]; then
- package_rootfs "${TOYBOX_SYSROOT}" "${TOYBOX_ROOTFS}"
- echo "filesystem image at ${TOYBOX_ROOTFS}"
-fi
diff --git a/system/uapp/guest/zircon.cpp b/system/uapp/guest/zircon.cpp
deleted file mode 100644
index a7bc7a9..0000000
--- a/system/uapp/guest/zircon.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <hypervisor/guest.h>
-#include <zircon/assert.h>
-#include <zircon/boot/bootdata.h>
-
-#include "zircon.h"
-
-static const uintptr_t kKernelOffset = 0x100000;
-static const uintptr_t kBootdataOffset = 0x800000;
-
-#if __aarch64__
-static const uint16_t kMzSignature = 0x5a4d; // MZ
-static const uint32_t kMzMagic = 0x644d5241; // ARM\x64
-
-// MZ header used to boot ARM64 kernels.
-//
-// See: https://www.kernel.org/doc/Documentation/arm64/booting.txt.
-struct MzHeader {
- uint32_t code0;
- uint32_t code1;
- uint64_t kernel_off;
- uint64_t kernel_len;
- uint64_t flags;
- uint64_t reserved0;
- uint64_t reserved1;
- uint64_t reserved2;
- uint32_t magic;
- uint32_t pe_off;
-} __PACKED;
-static_assert(sizeof(MzHeader) == 64, "");
-
-static bool is_mz(const MzHeader* header) {
- return (header->code0 & UINT16_MAX) == kMzSignature &&
- header->kernel_len > sizeof(MzHeader) &&
- header->magic == kMzMagic &&
- header->pe_off >= sizeof(MzHeader);
-}
-#endif
-
-static bool is_bootdata(const bootdata_t* header) {
- return header->type == BOOTDATA_CONTAINER &&
- header->length > sizeof(bootdata_t) &&
- header->extra == BOOTDATA_MAGIC &&
- header->flags & BOOTDATA_FLAG_V2 &&
- header->magic == BOOTITEM_MAGIC;
-}
-
-static void set_bootdata(bootdata_t* header, uint32_t type, uint32_t len) {
- // Guest memory is initially zeroed, so we skip fields that must be zero.
- header->type = type;
- header->length = len;
- header->flags = BOOTDATA_FLAG_V2;
- header->magic = BOOTITEM_MAGIC;
- header->crc32 = BOOTITEM_NO_CRC32;
-}
-
-static zx_status_t load_zircon(const int fd, const uintptr_t addr, const uintptr_t first_page,
- const uintptr_t kernel_off, const uintptr_t kernel_len) {
- // Move the first page to the kernel offset.
- memmove(reinterpret_cast<void*>(addr + kernel_off), reinterpret_cast<void*>(first_page),
- PAGE_SIZE);
-
- // Read in the rest of the kernel.
- const uintptr_t data_off = kernel_off + PAGE_SIZE;
- const size_t data_len = kernel_len - PAGE_SIZE;
- const ssize_t ret = read(fd, reinterpret_cast<void*>(addr + data_off), data_len);
- if (ret < 0 || (size_t)ret != data_len) {
- fprintf(stderr, "Failed to read Zircon kernel data\n");
- return ZX_ERR_IO;
- }
-
- return ZX_OK;
-}
-
-static zx_status_t load_cmdline(const char* cmdline, const uintptr_t addr,
- const uintptr_t bootdata_off) {
- const size_t cmdline_len = strlen(cmdline) + 1;
- if (cmdline_len > UINT32_MAX) {
- fprintf(stderr, "Command line is too long\n");
- return ZX_ERR_OUT_OF_RANGE;
- }
-
- bootdata_t* container_hdr = reinterpret_cast<bootdata_t*>(addr + bootdata_off);
- uintptr_t data_off = bootdata_off + sizeof(bootdata_t) + BOOTDATA_ALIGN(container_hdr->length);
-
- bootdata_t* cmdline_hdr = reinterpret_cast<bootdata_t*>(addr + data_off);
- set_bootdata(cmdline_hdr, BOOTDATA_CMDLINE, static_cast<uint32_t>(cmdline_len));
- memcpy(cmdline_hdr + 1, cmdline, cmdline_len);
-
- container_hdr->length += static_cast<uint32_t>(sizeof(bootdata_t)) +
- BOOTDATA_ALIGN(cmdline_hdr->length);
- return ZX_OK;
-}
-
-static zx_status_t load_bootfs(const int fd, const uintptr_t addr, const uintptr_t bootdata_off) {
- bootdata_t ramdisk_hdr;
- ssize_t ret = read(fd, &ramdisk_hdr, sizeof(bootdata_t));
- if (ret != sizeof(bootdata_t)) {
- fprintf(stderr, "Failed to read BOOTFS image header\n");
- return ZX_ERR_IO;
- }
- if (!is_bootdata(&ramdisk_hdr)) {
- fprintf(stderr, "Invalid BOOTFS image header\n");
- return ZX_ERR_IO_DATA_INTEGRITY;
- }
-
- bootdata_t* container_hdr = reinterpret_cast<bootdata_t*>(addr + bootdata_off);
- uintptr_t data_off = bootdata_off + sizeof(bootdata_t) + BOOTDATA_ALIGN(container_hdr->length);
-
- ret = read(fd, reinterpret_cast<void*>(addr + data_off), ramdisk_hdr.length);
- if (ret < 0 || (size_t)ret != ramdisk_hdr.length) {
- fprintf(stderr, "Failed to read BOOTFS image data\n");
- return ZX_ERR_IO;
- }
-
- container_hdr->length += BOOTDATA_ALIGN(ramdisk_hdr.length) +
- static_cast<uint32_t>(sizeof(bootdata_t));
- return ZX_OK;
-}
-
-static zx_status_t create_bootdata(const uintptr_t addr, const size_t size,
- const uintptr_t acpi_off, uintptr_t bootdata_off) {
- if (BOOTDATA_ALIGN(bootdata_off) != bootdata_off)
- return ZX_ERR_INVALID_ARGS;
-
- const size_t e820_size = guest_e820_size(size);
- const size_t bootdata_len = sizeof(bootdata_t) + BOOTDATA_ALIGN(sizeof(uint64_t)) +
- sizeof(bootdata_t) + BOOTDATA_ALIGN(e820_size);
- if (bootdata_off + bootdata_len > size)
- return ZX_ERR_BUFFER_TOO_SMALL;
- if (bootdata_len > UINT32_MAX)
- return ZX_ERR_OUT_OF_RANGE;
-
- // Bootdata container.
- bootdata_t* container_hdr = reinterpret_cast<bootdata_t*>(addr + bootdata_off);
- set_bootdata(container_hdr, BOOTDATA_CONTAINER, static_cast<uint32_t>(bootdata_len));
- container_hdr->extra = BOOTDATA_MAGIC;
-
- // ACPI root table pointer.
- bootdata_off += sizeof(bootdata_t);
- bootdata_t* acpi_rsdp_hdr = reinterpret_cast<bootdata_t*>(addr + bootdata_off);
- set_bootdata(acpi_rsdp_hdr, BOOTDATA_ACPI_RSDP, sizeof(uint64_t));
- bootdata_off += sizeof(bootdata_t);
- *reinterpret_cast<uint64_t*>(addr + bootdata_off) = acpi_off;
-
- // E820 memory map.
- bootdata_off += BOOTDATA_ALIGN(sizeof(uint64_t));
- bootdata_t* e820_table_hdr = reinterpret_cast<bootdata_t*>(addr + bootdata_off);
- set_bootdata(e820_table_hdr, BOOTDATA_E820_TABLE, static_cast<uint32_t>(e820_size));
- bootdata_off += sizeof(bootdata_t);
- return guest_create_e820(addr, size, bootdata_off);
-}
-
-static zx_status_t is_zircon(const size_t size, const uintptr_t first_page, uintptr_t* guest_ip,
- uintptr_t* kernel_off, uintptr_t* kernel_len) {
- zircon_kernel_t* kernel_header = reinterpret_cast<zircon_kernel_t*>(first_page);
- if (is_bootdata(&kernel_header->hdr_file)) {
- if (kernel_header->hdr_kernel.type != BOOTDATA_KERNEL) {
- fprintf(stderr, "Invalid Zircon kernel header\n");
- return ZX_ERR_IO_DATA_INTEGRITY;
- }
- *guest_ip = kernel_header->data_kernel.entry64;
- *kernel_off = kKernelOffset;
- *kernel_len = sizeof(bootdata_t) + BOOTDATA_ALIGN(kernel_header->hdr_file.length);
- return ZX_OK;
- }
-
-#if __aarch64__
- MzHeader* mz_header = reinterpret_cast<MzHeader*>(first_page);
- if (is_mz(mz_header)) {
- *guest_ip = mz_header->kernel_off;
- *kernel_off = mz_header->kernel_off;
- *kernel_len = mz_header->kernel_len;
- return ZX_OK;
- }
-#endif
-
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-static bool is_within(uintptr_t x, uintptr_t addr, uintptr_t size) {
- return x >= addr && x < addr + size;
-}
-
-zx_status_t setup_zircon(const uintptr_t addr, const size_t size, const uintptr_t first_page,
- const uintptr_t acpi_off, const int fd, const char* bootdata_path,
- const char* cmdline, uintptr_t* guest_ip, uintptr_t* bootdata_off) {
- uintptr_t kernel_off = 0;
- uintptr_t kernel_len = 0;
- zx_status_t status = is_zircon(size, first_page, guest_ip, &kernel_off, &kernel_len);
- if (status != ZX_OK)
- return status;
-
- if (!is_within(*guest_ip, kernel_off, kernel_len)) {
- fprintf(stderr, "Kernel entry point is outside of kernel location\n");
- return ZX_ERR_IO_DATA_INTEGRITY;
- }
- if (kernel_off + kernel_len >= size) {
- fprintf(stderr, "Kernel location is outside of guest physical memory\n");
- return ZX_ERR_IO_DATA_INTEGRITY;
- }
- if (is_within(kBootdataOffset, kernel_off, kernel_len)) {
- fprintf(stderr, "Kernel location overlaps BOOTFS location\n");
- return ZX_ERR_IO_DATA_INTEGRITY;
- }
-
- status = create_bootdata(addr, size, acpi_off, kBootdataOffset);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to create BOOTDATA\n");
- return status;
- }
-
- status = load_zircon(fd, addr, first_page, kernel_off, kernel_len);
- if (status != ZX_OK)
- return status;
-
- // If we have a command line, load it.
- if (cmdline != NULL) {
- status = load_cmdline(cmdline, addr, kBootdataOffset);
- if (status != ZX_OK)
- return status;
- }
-
- // If we have been provided a BOOTFS image, load it.
- if (bootdata_path) {
- int boot_fd = open(bootdata_path, O_RDONLY);
- if (boot_fd < 0) {
- fprintf(stderr, "Failed to open BOOTFS image \"%s\"\n", bootdata_path);
- return ZX_ERR_IO;
- }
-
- status = load_bootfs(boot_fd, addr, kBootdataOffset);
- close(boot_fd);
- if (status != ZX_OK)
- return status;
- }
-
- *bootdata_off = kBootdataOffset;
- return ZX_OK;
-}
diff --git a/system/uapp/guest/zircon.h b/system/uapp/guest/zircon.h
deleted file mode 100644
index c08e1ea..0000000
--- a/system/uapp/guest/zircon.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <zircon/types.h>
-
-zx_status_t setup_zircon(const uintptr_t addr, const size_t vmo_size, const uintptr_t first_page,
- const uintptr_t acpi_off, const int fd, const char* bootdata_path,
- const char* cmdline, uintptr_t* guest_ip, uintptr_t* bootdata_off);
diff --git a/system/ulib/machina/BUILD.gn b/system/ulib/machina/BUILD.gn
deleted file mode 100644
index f23945d..0000000
--- a/system/ulib/machina/BUILD.gn
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2016 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/package.gni")
-
-config("machina_config") {
- include_dirs = ["include"]
- if (current_cpu == "x64") {
- include_dirs += ["arch/x86/include"]
- } else if (current_cpu == "arm64") {
- include_dirs += ["arch/arm64/include"]
- }
-}
-
-source_set("machina") {
- sources = [
- "balloon.cpp",
- "block.cpp",
- "gpu.cpp",
- "input.cpp",
- "pci.cpp",
- "virtio.cpp",
- "virtio_pci.cpp",
- "include/machina/balloon.h",
- "include/machina/block.h",
- "include/machina/gpu.h",
- "include/machina/input.h",
- "include/machina/pci.h",
- "include/machina/virtio.h",
- "include/machina/virtio_pci.h",
- ]
-
- if (current_cpu == "arm64") {
- sources += [
- "arch/arm64/gic_distributor.cpp",
- "arch/arm64/pl011.cpp",
- "arch/arm64/include/machina/interrupt_controller.h",
- "arch/arm64/include/machina/uart.h",
- ]
- }
-
- if (current_cpu == "x64") {
- sources += [
- "arch/x86/i8250.cpp",
- "arch/x86/io_apic.cpp",
- "arch/x86/io_port.cpp",
- "arch/x86/include/machina/interrupt_controller.h",
- "arch/x86/include/machina/io_port.h",
- "arch/x86/include/machina/tpm.h",
- "arch/x86/include/machina/uart.h",
- ]
- }
-
- public_deps = [
- "//zircon/system/ulib/zx",
- ]
-
- deps = [
- "//zircon/system/ulib/block-client",
- "//zircon/system/ulib/fbl",
- ]
-
- libs = [
- "hid",
- "hypervisor",
- "sync",
- "virtio",
- ]
-
- public_configs = [":machina_config"]
-}
diff --git a/system/ulib/machina/arch/arm64/gic_distributor.cpp b/system/ulib/machina/arch/arm64/gic_distributor.cpp
deleted file mode 100644
index 04d1386..0000000
--- a/system/ulib/machina/arch/arm64/gic_distributor.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/interrupt_controller.h>
-
-#include <hypervisor/address.h>
-#include <hypervisor/bits.h>
-#include <hypervisor/guest.h>
-
-static const uint64_t kMaxInterrupts = 128;
-static const uint64_t kGicRevision = 2;
-
-// clang-format off
-
-enum class GicdRegister : uint64_t {
- CTL = 0x000,
- TYPE = 0x004,
- ISENABLE0 = 0x100,
- ISENABLE15 = 0x13c,
- ICENABLE0 = 0x180,
- ICENABLE15 = 0x1bc,
- ICPEND0 = 0x280,
- ICPEND15 = 0x2bc,
- ICFG0 = 0xc00,
- ICFG31 = 0xc7c,
- PID2 = 0xfe8,
-};
-
-// clang-format on
-
-static inline uint32_t typer_it_lines(uint32_t num_interrupts) {
- return set_bits((num_interrupts >> 5) - 1, 4, 0);
-}
-
-static inline uint32_t pidr2_arch_rev(uint32_t revision) {
- return set_bits(revision, 7, 4);
-}
-
-zx_status_t GicDistributor::Init(Guest* guest) {
- return guest->CreateMapping(TrapType::MMIO_SYNC, GIC_DISTRIBUTOR_PHYS_BASE,
- GIC_DISTRIBUTOR_SIZE, 0, this);
-}
-
-zx_status_t GicDistributor::Read(uint64_t addr, IoValue* value) const {
- if (value->access_size != 4)
- return ZX_ERR_IO_DATA_INTEGRITY;
-
- switch (static_cast<GicdRegister>(addr)) {
- case GicdRegister::TYPE:
- // TODO(abdulla): Set the number of VCPUs.
- value->u32 = typer_it_lines(kMaxInterrupts);
- return ZX_OK;
- case GicdRegister::ICFG0... GicdRegister::ICFG31:
- if (addr % 4)
- return ZX_ERR_IO_DATA_INTEGRITY;
- value->u32 = 0;
- return ZX_OK;
- case GicdRegister::PID2:
- value->u32 = pidr2_arch_rev(kGicRevision);
- return ZX_OK;
- default:
- fprintf(stderr, "Unhandled GIC distributor address %#lx\n", addr);
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t GicDistributor::Write(uint64_t addr, const IoValue& value) {
- switch (static_cast<GicdRegister>(addr)) {
- case GicdRegister::CTL:
- return ZX_OK;
- case GicdRegister::ISENABLE0... GicdRegister::ISENABLE15:
- case GicdRegister::ICENABLE0... GicdRegister::ICENABLE15:
- case GicdRegister::ICPEND0... GicdRegister::ICPEND15:
- case GicdRegister::ICFG0... GicdRegister::ICFG31:
- if (addr % 4)
- return ZX_ERR_IO_DATA_INTEGRITY;
- return ZX_OK;
- default:
- fprintf(stderr, "Unhandled GIC distributor address %#lx\n", addr);
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t GicDistributor::Interrupt(uint32_t global_irq) const {
- return ZX_ERR_NOT_SUPPORTED;
-}
diff --git a/system/ulib/machina/arch/arm64/include/machina/interrupt_controller.h b/system/ulib/machina/arch/arm64/include/machina/interrupt_controller.h
deleted file mode 100644
index d29cb9c..0000000
--- a/system/ulib/machina/arch/arm64/include/machina/interrupt_controller.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <hypervisor/io.h>
-
-class Guest;
-
-// Implements GIC distributor.
-class GicDistributor : public IoHandler {
-public:
- zx_status_t Init(Guest* guest);
-
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-
- zx_status_t Interrupt(uint32_t global_irq) const;
-};
-
-using InterruptController = GicDistributor;
diff --git a/system/ulib/machina/arch/arm64/include/machina/uart.h b/system/ulib/machina/arch/arm64/include/machina/uart.h
deleted file mode 100644
index 8d3e55b..0000000
--- a/system/ulib/machina/arch/arm64/include/machina/uart.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <hypervisor/io.h>
-
-class Guest;
-
-// Implements the PL011 UART.
-class Pl011 : public IoHandler {
-public:
- zx_status_t Init(Guest* guest, uint64_t addr);
-
- // IoHandler interface.
- zx_status_t Read(uint64_t addr, IoValue* io) const override;
- zx_status_t Write(uint64_t addr, const IoValue& io) override;
-
-private:
- static const size_t kBufferSize = 128;
-
- uint8_t tx_buffer_[kBufferSize] = {};
- uint16_t tx_offset_ = 0;
-
- void Print(uint8_t ch);
-};
-
-using Uart = Pl011;
diff --git a/system/ulib/machina/arch/arm64/pl011.cpp b/system/ulib/machina/arch/arm64/pl011.cpp
deleted file mode 100644
index 21bedb4..0000000
--- a/system/ulib/machina/arch/arm64/pl011.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/uart.h>
-
-#include <stdio.h>
-
-#include <hypervisor/address.h>
-#include <hypervisor/guest.h>
-
-// PL011 registers.
-enum class Pl011Register : uint64_t {
- DR = 0x00,
- FR = 0x18,
- CR = 0x30,
-};
-
-zx_status_t Pl011::Init(Guest* guest, uint64_t addr) {
- return guest->CreateMapping(TrapType::MMIO_SYNC, addr, PL011_SIZE, 0, this);
-}
-
-zx_status_t Pl011::Read(uint64_t addr, IoValue* io) const {
- switch (static_cast<Pl011Register>(addr)) {
- case Pl011Register::FR:
- if (io->access_size != 4)
- return ZX_ERR_IO_DATA_INTEGRITY;
- io->u32 = 0;
- return ZX_OK;
- default:
- fprintf(stderr, "Unhandled PL011 address %#lx\n", addr);
- return ZX_ERR_IO;
- }
-}
-
-zx_status_t Pl011::Write(uint64_t addr, const IoValue& io) {
- switch (static_cast<Pl011Register>(addr)) {
- case Pl011Register::DR:
- Print(io.u8);
- return ZX_OK;
- case Pl011Register::CR:
- return ZX_OK;
- default:
- fprintf(stderr, "Unhandled PL011 address %#lx\n", addr);
- return ZX_ERR_IO;
- }
-}
-
-void Pl011::Print(uint8_t ch) {
- tx_buffer_[tx_offset_++] = ch;
- if (tx_offset_ < kBufferSize && ch != '\r')
- return;
- fprintf(stdout, "%.*s", tx_offset_, tx_buffer_);
- fflush(stdout);
- tx_offset_ = 0;
-}
diff --git a/system/ulib/machina/arch/arm64/rules.mk b/system/ulib/machina/arch/arm64/rules.mk
deleted file mode 100644
index 4cb5d1a..0000000
--- a/system/ulib/machina/arch/arm64/rules.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2017 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-ARCH_DIR := $(GET_LOCAL_DIR)
-
-MODULE_SRCS += \
- $(ARCH_DIR)/gic_distributor.cpp \
- $(ARCH_DIR)/pl011.cpp \
diff --git a/system/ulib/machina/arch/x86/i8250.cpp b/system/ulib/machina/arch/x86/i8250.cpp
deleted file mode 100644
index 7b3b8f6..0000000
--- a/system/ulib/machina/arch/x86/i8250.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/uart.h>
-
-#include <stdio.h>
-
-#include <hypervisor/address.h>
-#include <hypervisor/guest.h>
-
-// Use an async trap for the first port (TX port) only.
-static const uint64_t kI8250AsyncBase = 0;
-static const uint64_t kI8250AsyncSize = 1;
-static const uint64_t kI8250AsyncOffset = 0;
-static const uint64_t kI8250SyncBase = kI8250AsyncSize;
-static const uint64_t kI8250SyncSize = I8250_SIZE - kI8250AsyncSize;
-static const uint64_t kI8250SyncOffset = kI8250AsyncSize;
-
-// I8250 state flags.
-static const uint64_t kI8250LineStatusEmpty = 1u << 5;
-static const uint64_t kI8250LineStatusIdle = 1u << 6;
-
-// clang-format off
-
-// I8250 registers.
-enum class I8250Register : uint64_t {
- RECEIVE = 0x0,
- TRANSMIT = 0x0,
- INTERRUPT_ENABLE = 0x1,
- INTERRUPT_ID = 0x2,
- LINE_CONTROL = 0x3,
- MODEM_CONTROL = 0x4,
- LINE_STATUS = 0x5,
- MODEM_STATUS = 0x6,
- SCRATCH = 0x7,
-};
-
-// clang-format on
-
-zx_status_t I8250::Init(Guest* guest, uint64_t addr) {
- zx_status_t status = guest->CreateMapping(TrapType::PIO_ASYNC, addr + kI8250AsyncBase,
- kI8250AsyncSize, kI8250AsyncOffset, this);
- if (status != ZX_OK)
- return status;
- return guest->CreateMapping(TrapType::PIO_SYNC, addr + kI8250SyncBase,
- kI8250SyncSize, kI8250SyncOffset, this);
-}
-
-zx_status_t I8250::Read(uint64_t addr, IoValue* io) const {
- switch (static_cast<I8250Register>(addr)) {
- case I8250Register::INTERRUPT_ENABLE:
- io->access_size = 1;
- io->u8 = interrupt_enable_;
- return ZX_OK;
- case I8250Register::LINE_CONTROL:
- io->access_size = 1;
- io->u8 = line_control_;
- return ZX_OK;
- case I8250Register::LINE_STATUS:
- io->access_size = 1;
- io->u8 = kI8250LineStatusIdle | kI8250LineStatusEmpty;
- return ZX_OK;
- case I8250Register::RECEIVE:
- case I8250Register::INTERRUPT_ID:
- case I8250Register::MODEM_CONTROL:
- case I8250Register::MODEM_STATUS... I8250Register::SCRATCH:
- io->access_size = 1;
- io->u8 = 0;
- return ZX_OK;
- default:
- fprintf(stderr, "Unhandled I8250 address %#lx\n", addr);
- return ZX_ERR_IO;
- }
-}
-
-zx_status_t I8250::Write(uint64_t addr, const IoValue& io) {
- switch (static_cast<I8250Register>(addr)) {
- case I8250Register::TRANSMIT:
- for (int i = 0; i < io.access_size; i++) {
- Print(io.data[i]);
- }
- return ZX_OK;
- case I8250Register::INTERRUPT_ENABLE:
- if (io.access_size != 1)
- return ZX_ERR_IO_DATA_INTEGRITY;
- interrupt_enable_ = io.u8;
- return ZX_OK;
- case I8250Register::LINE_CONTROL:
- if (io.access_size != 1)
- return ZX_ERR_IO_DATA_INTEGRITY;
- line_control_ = io.u8;
- return ZX_OK;
- case I8250Register::INTERRUPT_ID:
- case I8250Register::MODEM_CONTROL... I8250Register::SCRATCH:
- return ZX_OK;
- default:
- fprintf(stderr, "Unhandled I8250 address %#lx\n", addr);
- return ZX_ERR_IO;
- }
-}
-
-void I8250::Print(uint8_t ch) {
- tx_buffer_[tx_offset_++] = ch;
- if (tx_offset_ < kBufferSize && ch != '\r')
- return;
- fprintf(stdout, "%.*s", tx_offset_, tx_buffer_);
- fflush(stdout);
- tx_offset_ = 0;
-}
diff --git a/system/ulib/machina/arch/x86/include/machina/interrupt_controller.h b/system/ulib/machina/arch/x86/include/machina/interrupt_controller.h
deleted file mode 100644
index d279db8..0000000
--- a/system/ulib/machina/arch/x86/include/machina/interrupt_controller.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <fbl/mutex.h>
-#include <hypervisor/io.h>
-#include <zircon/compiler.h>
-
-class Guest;
-class LocalApic;
-
-// Implements the IO APIC.
-class IoApic : public IoHandler {
-public:
- static constexpr size_t kNumRedirects = 48u;
- static constexpr size_t kNumRedirectOffsets = kNumRedirects * 2;
- static constexpr size_t kMaxLocalApics = 16u;
-
- // An entry in the redirect table.
- struct RedirectEntry {
- uint32_t upper;
- uint32_t lower;
- };
-
- zx_status_t Init(Guest* guest);
-
- // IoHandler interface.
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-
- // Associate a local APIC with an IO APIC.
- zx_status_t RegisterLocalApic(uint8_t local_apic_id, LocalApic* local_apic);
-
- // Writes the redirect entry for a global IRQ.
- zx_status_t SetRedirect(uint32_t global_irq, RedirectEntry& redirect);
-
- // Signals the given global IRQ.
- zx_status_t Interrupt(uint32_t global_irq) const;
-
-private:
- zx_status_t ReadRegister(uint32_t select_register, IoValue* value) const;
- zx_status_t WriteRegister(uint32_t select_register, const IoValue& value);
-
- mutable fbl::Mutex mutex_;
- // IO register-select register.
- uint32_t select_ __TA_GUARDED(mutex_) = 0;
- // IO APIC identification register.
- uint32_t id_ __TA_GUARDED(mutex_) = 0;
- // IO redirection table.
- RedirectEntry redirect_[kNumRedirects] __TA_GUARDED(mutex_) = {};
- // Connected local APICs.
- LocalApic* local_apic_[kMaxLocalApics] = {};
-};
-
-using InterruptController = IoApic;
diff --git a/system/ulib/machina/arch/x86/include/machina/io_port.h b/system/ulib/machina/arch/x86/include/machina/io_port.h
deleted file mode 100644
index 6805428..0000000
--- a/system/ulib/machina/arch/x86/include/machina/io_port.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <fbl/mutex.h>
-#include <hypervisor/guest.h>
-#include <hypervisor/io.h>
-#include <zircon/compiler.h>
-#include <zircon/types.h>
-
-class PicHandler : public IoHandler {
-public:
- zx_status_t Init(Guest* guest, uint16_t base);
-
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-};
-
-class PitHandler : public IoHandler {
-public:
- zx_status_t Init(Guest* guest);
-
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-};
-
-class Pm1Handler : public IoHandler {
-public:
- zx_status_t Init(Guest* guest);
-
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-
-private:
- mutable fbl::Mutex mutex_;
- uint16_t enable_ __TA_GUARDED(mutex_) = 0;
-};
-
-class RtcHandler : public IoHandler {
-public:
- zx_status_t Init(Guest* guest);
-
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-
-private:
- zx_status_t ReadRtcRegister(uint8_t rtc_index, uint8_t* value) const;
- zx_status_t WriteRtcRegister(uint8_t rtc_index, uint8_t value);
- mutable fbl::Mutex mutex_;
- uint8_t index_ __TA_GUARDED(mutex_) = 0;
-};
-
-class I8042Handler : public IoHandler {
-public:
- zx_status_t Init(Guest* guest);
-
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-
-private:
- mutable fbl::Mutex mutex_;
- uint8_t command_ __TA_GUARDED(mutex_) = 0;
-};
-
-class IoPort {
-public:
- zx_status_t Init(Guest* guest);
-
-private:
- PicHandler pic1_;
- PicHandler pic2_;
- PitHandler pit_;
- Pm1Handler pm1_;
- RtcHandler rtc_;
- I8042Handler i8042_;
-};
diff --git a/system/ulib/machina/arch/x86/include/machina/tpm.h b/system/ulib/machina/arch/x86/include/machina/tpm.h
deleted file mode 100644
index d6a2458..0000000
--- a/system/ulib/machina/arch/x86/include/machina/tpm.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <hypervisor/address.h>
-#include <hypervisor/guest.h>
-#include <hypervisor/io.h>
-#include <zircon/types.h>
-
-// Stub TPM implementation.
-class Tpm : public IoHandler {
-public:
- zx_status_t Init(Guest* guest) {
- return guest->CreateMapping(TrapType::MMIO_SYNC, TPM_PHYS_BASE, TPM_SIZE, 0, this);
- }
-
- zx_status_t Read(uint64_t addr, IoValue* value) const override { return ZX_OK; }
- zx_status_t Write(uint64_t addr, const IoValue& value) override { return ZX_OK; }
-};
diff --git a/system/ulib/machina/arch/x86/include/machina/uart.h b/system/ulib/machina/arch/x86/include/machina/uart.h
deleted file mode 100644
index 99a9649..0000000
--- a/system/ulib/machina/arch/x86/include/machina/uart.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <hypervisor/io.h>
-
-class Guest;
-
-// Implements the I8250 UART.
-class I8250 : public IoHandler {
-public:
- zx_status_t Init(Guest* guest, uint64_t addr);
-
- // IoHandler interface.
- zx_status_t Read(uint64_t addr, IoValue* io) const override;
- zx_status_t Write(uint64_t addr, const IoValue& io) override;
-
-private:
- static const size_t kBufferSize = 128;
-
- uint8_t tx_buffer_[kBufferSize] = {};
- uint16_t tx_offset_ = 0;
-
- uint8_t interrupt_enable_ = 0;
- uint8_t line_control_ = 0;
-
- void Print(uint8_t ch);
-};
-
-using Uart = I8250;
diff --git a/system/ulib/machina/arch/x86/io_apic.cpp b/system/ulib/machina/arch/x86/io_apic.cpp
deleted file mode 100644
index a181427..0000000
--- a/system/ulib/machina/arch/x86/io_apic.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/interrupt_controller.h>
-
-#include <string.h>
-
-#include <fbl/auto_lock.h>
-#include <hypervisor/address.h>
-#include <hypervisor/bits.h>
-#include <hypervisor/guest.h>
-#include <hypervisor/vcpu.h>
-#include <hypervisor/x86/local_apic.h>
-#include <zircon/assert.h>
-#include <zircon/syscalls.h>
-#include <zircon/syscalls/hypervisor.h>
-
-// clang-format off
-
-/* IO APIC register addresses. */
-#define IO_APIC_IOREGSEL 0x00
-#define IO_APIC_IOWIN 0x10
-
-/* IO APIC register addresses. */
-#define IO_APIC_REGISTER_ID 0x00
-#define IO_APIC_REGISTER_VER 0x01
-#define IO_APIC_REGISTER_ARBITRATION 0x02
-
-/* IO APIC configuration constants. */
-#define IO_APIC_VERSION 0x11
-#define FIRST_REDIRECT_OFFSET 0x10
-#define LAST_REDIRECT_OFFSET (FIRST_REDIRECT_OFFSET + IoApic::kNumRedirectOffsets - 1)
-
-/* DESTMOD register. */
-#define IO_APIC_DESTMOD_PHYSICAL 0x00
-#define IO_APIC_DESTMOD_LOGICAL 0x01
-
-#define LOCAL_APIC_DFR_FLAT_MODEL 0xf
-
-// clang-format on
-
-zx_status_t IoApic::Init(Guest* guest) {
- return guest->CreateMapping(TrapType::MMIO_SYNC, IO_APIC_PHYS_BASE, IO_APIC_SIZE, 0, this);
-}
-
-zx_status_t IoApic::RegisterLocalApic(uint8_t local_apic_id, LocalApic* local_apic) {
- if (local_apic_id >= kMaxLocalApics)
- return ZX_ERR_OUT_OF_RANGE;
- if (local_apic_[local_apic_id] != nullptr)
- return ZX_ERR_ALREADY_EXISTS;
-
- local_apic->set_id(local_apic_id);
- local_apic_[local_apic_id] = local_apic;
- return ZX_OK;
-}
-
-zx_status_t IoApic::SetRedirect(uint32_t global_irq, RedirectEntry& redirect) {
- if (global_irq >= kNumRedirects)
- return ZX_ERR_OUT_OF_RANGE;
- fbl::AutoLock lock(&mutex_);
- redirect_[global_irq] = redirect;
- return ZX_OK;
-}
-
-zx_status_t IoApic::Interrupt(uint32_t global_irq) const {
- if (global_irq >= kNumRedirects)
- return ZX_ERR_OUT_OF_RANGE;
-
- RedirectEntry entry;
- {
- fbl::AutoLock lock(&mutex_);
- entry = redirect_[global_irq];
- }
-
- uint32_t vector = bits_shift(entry.lower, 7, 0);
-
- // The "destination mode" (DESTMOD) determines how the dest field in the
- // redirection entry should be interpreted.
- //
- // With a 'physical' mode, the destination is interpreted as the APIC ID
- // of the target APIC to receive the interrupt.
- //
- // With a 'logical' mode, the target depends on the 'logical destination
- // register' and the 'destination format register' in the connected local
- // APICs.
- //
- // See 82093AA (IOAPIC) Section 2.3.4.
- // See Intel Volume 3, Section 10.6.2.
- uint32_t destmod = bit_shift(entry.lower, 11);
- if (destmod == IO_APIC_DESTMOD_PHYSICAL) {
- uint32_t dest = bits_shift(entry.upper, 27, 24);
- LocalApic* local_apic = dest < kMaxLocalApics ? local_apic_[dest] : nullptr;
- if (local_apic == nullptr)
- return ZX_ERR_NOT_FOUND;
- return local_apic->Interrupt(vector);
- }
-
- // Logical DESTMOD.
- uint32_t dest = bits_shift(entry.upper, 31, 24);
- for (uint8_t local_apic_id = 0; local_apic_id < kMaxLocalApics; ++local_apic_id) {
- LocalApic* local_apic = local_apic_[local_apic_id];
- if (local_apic == nullptr)
- continue;
-
- // Intel Volume 3, Section 10.6.2.2: Each local APIC performs a
- // bit-wise AND of the MDA and its logical APIC ID.
- uint32_t logical_apic_id = bits_shift(local_apic->ldr(), 31, 24);
- if (!(logical_apic_id & dest))
- continue;
-
- // There also exists a 'cluster' model that is not implemented.
- uint32_t model = bits_shift(local_apic->dfr(), 31, 28);
- if (model != LOCAL_APIC_DFR_FLAT_MODEL) {
- fprintf(stderr, "APIC only supports the flat model.\n");
- return ZX_ERR_NOT_SUPPORTED;
- }
-
- // Note we're not currently respecting the DELMODE field and
- // instead are only delivering to the fist local APIC that is
- // targeted.
- return local_apic->Interrupt(vector);
- }
- return ZX_ERR_NOT_FOUND;
-}
-
-zx_status_t IoApic::Read(uint64_t addr, IoValue* value) const {
- switch (addr) {
- case IO_APIC_IOREGSEL: {
- fbl::AutoLock lock(&mutex_);
- value->u32 = select_;
- return ZX_OK;
- }
- case IO_APIC_IOWIN: {
- uint32_t select_register;
- {
- fbl::AutoLock lock(&mutex_);
- select_register = select_;
- }
- return ReadRegister(select_register, value);
- }
- default:
- fprintf(stderr, "Unhandled IO APIC address %#lx\n", addr);
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t IoApic::Write(uint64_t addr, const IoValue& value) {
- switch (addr) {
- case IO_APIC_IOREGSEL: {
- if (value.u32 > UINT8_MAX)
- return ZX_ERR_INVALID_ARGS;
- fbl::AutoLock lock(&mutex_);
- select_ = value.u32;
- return ZX_OK;
- }
- case IO_APIC_IOWIN: {
- uint32_t select_register;
- {
- fbl::AutoLock lock(&mutex_);
- select_register = select_;
- }
- return WriteRegister(select_register, value);
- }
- default:
- fprintf(stderr, "Unhandled IO APIC address %#lx\n", addr);
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t IoApic::ReadRegister(uint32_t select_register, IoValue* value) const {
- switch (select_register) {
- case IO_APIC_REGISTER_ID: {
- fbl::AutoLock lock(&mutex_);
- value->u32 = id_;
- return ZX_OK;
- }
- case IO_APIC_REGISTER_VER:
- // There are two redirect offsets per redirection entry. We return
- // the maximum redirection entry index.
- //
- // From Intel 82093AA, Section 3.2.2.
- value->u32 = (kNumRedirects - 1) << 16 | IO_APIC_VERSION;
- return ZX_OK;
- case IO_APIC_REGISTER_ARBITRATION:
- // Since we have a single I/O APIC, it is always the winner
- // of arbitration and its arbitration register is always 0.
- value->u32 = 0;
- return ZX_OK;
- case FIRST_REDIRECT_OFFSET... LAST_REDIRECT_OFFSET: {
- fbl::AutoLock lock(&mutex_);
- uint32_t redirect_offset = select_ - FIRST_REDIRECT_OFFSET;
- const RedirectEntry& entry = redirect_[redirect_offset / 2];
- uint32_t redirect_register = redirect_offset % 2 == 0 ? entry.lower : entry.upper;
- value->u32 = redirect_register;
- return ZX_OK;
- }
- default:
- fprintf(stderr, "Unhandled IO APIC register %#x\n", select_register);
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t IoApic::WriteRegister(uint32_t select_register, const IoValue& value) {
- switch (select_register) {
- case IO_APIC_REGISTER_ID: {
- fbl::AutoLock lock(&mutex_);
- id_ = value.u32;
- return ZX_OK;
- }
- case FIRST_REDIRECT_OFFSET... LAST_REDIRECT_OFFSET: {
- fbl::AutoLock lock(&mutex_);
- uint32_t redirect_offset = select_ - FIRST_REDIRECT_OFFSET;
- RedirectEntry& entry = redirect_[redirect_offset / 2];
- uint32_t* redirect_register = redirect_offset % 2 == 0 ? &entry.lower : &entry.upper;
- *redirect_register = value.u32;
- return ZX_OK;
- }
- case IO_APIC_REGISTER_VER:
- case IO_APIC_REGISTER_ARBITRATION:
- // Read-only, ignore writes.
- return ZX_OK;
- default:
- fprintf(stderr, "Unhandled IO APIC register %#x\n", select_register);
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
diff --git a/system/ulib/machina/arch/x86/io_port.cpp b/system/ulib/machina/arch/x86/io_port.cpp
deleted file mode 100644
index 0580327..0000000
--- a/system/ulib/machina/arch/x86/io_port.cpp
+++ /dev/null
@@ -1,327 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/io_port.h>
-
-#include <time.h>
-
-#include <fbl/auto_lock.h>
-#include <hypervisor/address.h>
-#include <hypervisor/bits.h>
-
-// clang-format off
-
-/* PIC constatants. */
-constexpr uint16_t kPicDataPort = 1;
-constexpr uint8_t kPicInvalid = UINT8_MAX;
-
-/* PM1 relative port mappings. */
-constexpr uint16_t kPm1StatusPort = 0;
-constexpr uint16_t kPm1EnablePort = 2;
-constexpr uint16_t kPm1ControlPort = PM1_CONTROL_PORT - PM1_EVENT_PORT;
-constexpr uint16_t kPm1Size = kPm1EnablePort + 1;
-
-/* RTC relative port mappings. */
-constexpr uint16_t kRtcIndexPort = 0;
-constexpr uint16_t kRtcDataPort = 1;
-
-/* RTC register addresses. */
-constexpr uint8_t kRtcRegisterSeconds = 0;
-constexpr uint8_t kRtcRegisterSecondsAlarm = 1;
-constexpr uint8_t kRtcRegisterMinutes = 2;
-constexpr uint8_t kRtcRegisterMinutesAlarm = 3;
-constexpr uint8_t kRtcRegisterHours = 4;
-constexpr uint8_t kRtcRegisterHoursAlarm = 5;
-constexpr uint8_t kRtcRegisterDayOfMonth = 7;
-constexpr uint8_t kRtcRegisterMonth = 8;
-constexpr uint8_t kRtcRegisterYear = 9;
-constexpr uint8_t kRtcRegisterA = 10;
-constexpr uint8_t kRtcRegisterB = 11;
-constexpr uint8_t kRtcRegisterC = 12;
-
-/* RTC register B flags. */
-constexpr uint8_t kRtcRegisterBDaylightSavings = 1 << 0;
-constexpr uint8_t kRtcRegisterBHourFormat = 1 << 1;
-constexpr uint8_t kRtcRegisterBInterruptMask = 0x70;
-
-/* RTC relative port mappings. */
-constexpr uint16_t kI8042DataPort = 0x0;
-constexpr uint16_t kI8042CommandPort = 0x4;
-
-/* I8042 status flags. */
-constexpr uint8_t kI8042StatusOutputFull = 1 << 0;
-
-/* I8042 test constants. */
-constexpr uint8_t kI8042CommandTest = 0xaa;
-constexpr uint8_t kI8042DataTestResponse = 0x55;
-
-// clang-format on
-
-zx_status_t PicHandler::Init(Guest* guest, uint16_t base) {
- return guest->CreateMapping(TrapType::PIO_SYNC, base, PIC_SIZE, 0, this);
-}
-
-zx_status_t PicHandler::Read(uint64_t addr, IoValue* value) const {
- if (addr == kPicDataPort) {
- value->access_size = 1;
- value->u8 = kPicInvalid;
- return ZX_OK;
- }
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t PicHandler::Write(uint64_t addr, const IoValue& value) {
- return ZX_OK;
-}
-
-zx_status_t PitHandler::Init(Guest* guest) {
- return guest->CreateMapping(TrapType::PIO_SYNC, PIT_BASE, PIT_SIZE, 0, this);
-}
-
-zx_status_t PitHandler::Read(uint64_t addr, IoValue* value) const {
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t PitHandler::Write(uint64_t addr, const IoValue& value) {
- return ZX_OK;
-}
-
-zx_status_t Pm1Handler::Init(Guest* guest) {
- // Map 2 distinct register blocks for event and control registers.
- zx_status_t status = guest->CreateMapping(TrapType::PIO_SYNC, PM1_EVENT_PORT, kPm1Size, 0,
- this);
- if (status != ZX_OK)
- return status;
- return guest->CreateMapping(TrapType::PIO_SYNC, PM1_CONTROL_PORT, kPm1Size, kPm1ControlPort,
- this);
-}
-
-zx_status_t Pm1Handler::Read(uint64_t addr, IoValue* value) const {
- switch (addr) {
- case kPm1StatusPort:
- value->access_size = 2;
- value->u16 = 0;
- break;
- case kPm1EnablePort: {
- value->access_size = 2;
- fbl::AutoLock lock(&mutex_);
- value->u16 = enable_;
- break;
- }
- case kPm1ControlPort:
- value->u32 = 0;
- break;
- default:
- return ZX_ERR_NOT_SUPPORTED;
- }
- return ZX_OK;
-}
-
-zx_status_t Pm1Handler::Write(uint64_t addr, const IoValue& value) {
- switch (addr) {
- case kPm1StatusPort:
- break;
- case kPm1EnablePort: {
- if (value.access_size != 2)
- return ZX_ERR_IO_DATA_INTEGRITY;
- fbl::AutoLock lock(&mutex_);
- enable_ = value.u16;
- break;
- }
- case kPm1ControlPort: {
- uint16_t slp_en = bit_shift(value.u16, 13);
- uint16_t slp_type = bits_shift(value.u16, 12, 10);
- if (slp_en != 0) {
- // Only power-off transitions are supported.
- return slp_type == SLP_TYP5 ? ZX_ERR_STOP : ZX_ERR_NOT_SUPPORTED;
- }
- break;
- }
- default:
- return ZX_ERR_NOT_SUPPORTED;
- }
- return ZX_OK;
-}
-
-static uint8_t to_bcd(int binary) {
- return static_cast<uint8_t>(((binary / 10) << 4) | (binary % 10));
-}
-
-zx_status_t RtcHandler::Init(Guest* guest) {
- return guest->CreateMapping(TrapType::PIO_SYNC, RTC_BASE, RTC_SIZE, 0, this);
-}
-
-zx_status_t RtcHandler::Read(uint64_t addr, IoValue* value) const {
- switch (addr) {
- case kRtcDataPort: {
- value->access_size = 1;
- uint8_t rtc_index;
- {
- fbl::AutoLock lock(&mutex_);
- rtc_index = index_;
- }
- return ReadRtcRegister(rtc_index, &value->u8);
- }
- default:
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t RtcHandler::Write(uint64_t addr, const IoValue& value) {
- switch (addr) {
- case kRtcDataPort: {
- uint8_t rtc_index;
- {
- fbl::AutoLock lock(&mutex_);
- rtc_index = index_;
- }
- return WriteRtcRegister(rtc_index, value.u8);
- }
- case kRtcIndexPort: {
- if (value.access_size != 1)
- return ZX_ERR_IO_DATA_INTEGRITY;
- fbl::AutoLock lock(&mutex_);
- index_ = value.u8;
- return ZX_OK;
- }
- default:
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t RtcHandler::ReadRtcRegister(uint8_t rtc_index, uint8_t* value) const {
- time_t now = time(nullptr);
- struct tm tm;
- if (localtime_r(&now, &tm) == nullptr)
- return ZX_ERR_INTERNAL;
- switch (rtc_index) {
- case kRtcRegisterSeconds:
- *value = to_bcd(tm.tm_sec);
- break;
- case kRtcRegisterMinutes:
- *value = to_bcd(tm.tm_min);
- break;
- case kRtcRegisterHours:
- *value = to_bcd(tm.tm_hour);
- break;
- case kRtcRegisterDayOfMonth:
- *value = to_bcd(tm.tm_mday);
- break;
- case kRtcRegisterMonth:
- // struct tm represents months as 0-11, RTC uses 1-12.
- *value = to_bcd(tm.tm_mon + 1);
- break;
- case kRtcRegisterYear: {
- // RTC expects the number of years since 2000.
- int year = tm.tm_year - 100;
- if (year < 0)
- year = 0;
- *value = to_bcd(year);
- break;
- }
- case kRtcRegisterA:
- // Ensure that UIP is 0. Other values (clock frequency) are obsolete.
- *value = 0;
- break;
- case kRtcRegisterB:
- *value = kRtcRegisterBHourFormat;
- if (tm.tm_isdst)
- *value |= kRtcRegisterBDaylightSavings;
- break;
- // Alarms are not implemented but allow reads of the registers.
- case kRtcRegisterSecondsAlarm:
- case kRtcRegisterMinutesAlarm:
- case kRtcRegisterHoursAlarm:
- case kRtcRegisterC:
- *value = 0;
- break;
- default:
- fprintf(stderr, "Unsupported RTC register read %x\n", rtc_index);
- return ZX_ERR_NOT_SUPPORTED;
- }
- return ZX_OK;
-}
-
-zx_status_t RtcHandler::WriteRtcRegister(uint8_t rtc_index, uint8_t value) {
- switch (rtc_index) {
- case kRtcRegisterA:
- return ZX_OK;
- case kRtcRegisterB:
- // No interrupts are implemented.
- if (value & kRtcRegisterBInterruptMask)
- return ZX_ERR_NOT_SUPPORTED;
- return ZX_OK;
- default:
- fprintf(stderr, "Unsupported RTC register write %x\n", rtc_index);
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t I8042Handler::Init(Guest* guest) {
- zx_status_t status = guest->CreateMapping(TrapType::PIO_SYNC, I8042_BASE + kI8042DataPort,
- 1, kI8042DataPort, this);
- if (status != ZX_OK)
- return status;
-
- return guest->CreateMapping(TrapType::PIO_SYNC, I8042_BASE + kI8042CommandPort,
- 1, kI8042CommandPort, this);
-}
-
-zx_status_t I8042Handler::Read(uint64_t port, IoValue* value) const {
- switch (port) {
- case kI8042DataPort: {
- value->access_size = 1;
- fbl::AutoLock lock(&mutex_);
- value->u8 = command_ == kI8042CommandTest ? kI8042DataTestResponse : 0;
- break;
- }
- case kI8042CommandPort:
- value->access_size = 1;
- value->u8 = kI8042StatusOutputFull;
- break;
- default:
- return ZX_ERR_NOT_SUPPORTED;
- }
- return ZX_OK;
-}
-
-zx_status_t I8042Handler::Write(uint64_t port, const IoValue& value) {
- switch (port) {
- case kI8042DataPort:
- case kI8042CommandPort: {
- if (value.access_size != 1)
- return ZX_ERR_IO_DATA_INTEGRITY;
- fbl::AutoLock lock(&mutex_);
- command_ = value.u8;
- break;
- }
- default:
- return ZX_ERR_NOT_SUPPORTED;
- }
- return ZX_OK;
-}
-
-zx_status_t IoPort::Init(Guest* guest) {
- zx_status_t status;
- status = pic1_.Init(guest, PIC1_BASE);
- if (status != ZX_OK)
- return status;
- status = pic2_.Init(guest, PIC2_BASE);
- if (status != ZX_OK)
- return status;
- status = pit_.Init(guest);
- if (status != ZX_OK)
- return status;
- status = pm1_.Init(guest);
- if (status != ZX_OK)
- return status;
- status = rtc_.Init(guest);
- if (status != ZX_OK)
- return status;
- status = i8042_.Init(guest);
- if (status != ZX_OK)
- return status;
-
- return ZX_OK;
-}
diff --git a/system/ulib/machina/arch/x86/rules.mk b/system/ulib/machina/arch/x86/rules.mk
deleted file mode 100644
index 0d82e6f..0000000
--- a/system/ulib/machina/arch/x86/rules.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2017 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-ARCH_DIR := $(GET_LOCAL_DIR)
-
-MODULE_SRCS += \
- $(ARCH_DIR)/i8250.cpp \
- $(ARCH_DIR)/io_apic.cpp \
- $(ARCH_DIR)/io_port.cpp \
diff --git a/system/ulib/machina/balloon.cpp b/system/ulib/machina/balloon.cpp
deleted file mode 100644
index dca3bbf..0000000
--- a/system/ulib/machina/balloon.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/balloon.h>
-
-#include <fbl/auto_lock.h>
-#include <virtio/virtio_ids.h>
-#include <zircon/syscalls.h>
-
-static zx_status_t decommit_pages(zx_handle_t vmo, uint64_t addr, uint64_t len) {
- return zx_vmo_op_range(vmo, ZX_VMO_OP_DECOMMIT, addr, len, nullptr, 0);
-}
-
-static zx_status_t commit_pages(zx_handle_t vmo, uint64_t addr, uint64_t len) {
- return zx_vmo_op_range(vmo, ZX_VMO_OP_COMMIT, addr, len, nullptr, 0);
-}
-
-/* Structure passed to the inflate/deflate queue handler. */
-typedef struct queue_ctx {
- // Operation to perform on the queue (inflate or deflate).
- zx_status_t (*op)(zx_handle_t vmo, uint64_t addr, uint64_t len);
- // The VMO to invoke |op| on.
- zx_handle_t vmo;
-} queue_ctx_t;
-
-/* Handle balloon inflate/deflate requests.
- *
- * From VIRTIO 1.0 Section 5.5.6:
- *
- * To supply memory to the balloon (aka. inflate):
- * (a) The driver constructs an array of addresses of unused memory pages.
- * These addresses are divided by 4096 and the descriptor describing the
- * resulting 32-bit array is added to the inflateq.
- *
- * To remove memory from the balloon (aka. deflate):
- * (a) The driver constructs an array of addresses of memory pages it has
- * previously given to the balloon, as described above. This descriptor is
- * added to the deflateq.
- * (b) If the VIRTIO_BALLOON_F_MUST_TELL_HOST feature is negotiated, the guest
- * informs the device of pages before it uses them.
- * (c) Otherwise, the guest is allowed to re-use pages previously given to the
- * balloon before the device has acknowledged their withdrawal.
- */
-static zx_status_t queue_range_op(void* addr, uint32_t len, uint16_t flags, uint32_t* used,
- void* ctx) {
- queue_ctx_t* balloon_op_ctx = static_cast<queue_ctx_t*>(ctx);
- uint32_t* pfns = static_cast<uint32_t*>(addr);
- uint32_t pfn_count = len / 4;
-
- // If the driver writes contiguous PFNs to the array we'll batch them up
- // when invoking the inflate/deflate operation.
- uint64_t region_base = 0;
- uint64_t region_length = 0;
- for (uint32_t i = 0; i < pfn_count; ++i) {
- // If we have a contiguous page, increment the length & continue.
- if (region_length > 0 && (region_base + region_length) == pfns[i]) {
- region_length++;
- continue;
- }
-
- // If we have an existing region; invoke the inflate/deflate op.
- if (region_length > 0) {
- zx_status_t status = balloon_op_ctx->op(balloon_op_ctx->vmo,
- region_base * VirtioBalloon::kPageSize,
- region_length * VirtioBalloon::kPageSize);
- if (status != ZX_OK)
- return status;
- }
-
- // Create a new region.
- region_base = pfns[i];
- region_length = 1;
- }
-
- // Handle the last region.
- if (region_length > 0) {
- zx_status_t status = balloon_op_ctx->op(balloon_op_ctx->vmo,
- region_base * VirtioBalloon::kPageSize,
- region_length * VirtioBalloon::kPageSize);
- if (status != ZX_OK)
- return status;
- }
-
- return ZX_OK;
-}
-
-zx_status_t VirtioBalloon::HandleDescriptor(uint16_t queue_sel) {
- queue_ctx_t ctx;
- switch (queue_sel) {
- case VIRTIO_BALLOON_Q_STATSQ:
- return ZX_OK;
- case VIRTIO_BALLOON_Q_INFLATEQ:
- ctx.op = &decommit_pages;
- break;
- case VIRTIO_BALLOON_Q_DEFLATEQ:
- if (deflate_on_demand_)
- return ZX_OK;
- ctx.op = &commit_pages;
- break;
- default:
- return ZX_ERR_INVALID_ARGS;
- }
- ctx.vmo = vmo_;
- return virtio_queue_handler(&queues_[queue_sel], &queue_range_op, &ctx);
-}
-
-zx_status_t VirtioBalloon::HandleQueueNotify(uint16_t queue_sel) {
- zx_status_t status;
- do {
- status = HandleDescriptor(queue_sel);
- } while (status == ZX_ERR_NEXT);
- return status;
-}
-
-VirtioBalloon::VirtioBalloon(uintptr_t guest_physmem_addr, size_t guest_physmem_size,
- zx_handle_t guest_physmem_vmo)
- : VirtioDevice(VIRTIO_ID_BALLOON, &config_, sizeof(config_), queues_, VIRTIO_BALLOON_Q_COUNT,
- guest_physmem_addr, guest_physmem_size),
- vmo_(guest_physmem_vmo) {
- add_device_features(VIRTIO_BALLOON_F_STATS_VQ | VIRTIO_BALLOON_F_DEFLATE_ON_OOM);
-}
-
-void VirtioBalloon::WaitForStatsBuffer(virtio_queue_t* stats_queue) {
- if (!stats_.has_buffer) {
- virtio_queue_wait(stats_queue, &stats_.desc_index);
- stats_.has_buffer = true;
- }
-}
-
-zx_status_t VirtioBalloon::RequestStats(StatsHandler handler) {
- virtio_queue_t* stats_queue = &queues_[VIRTIO_BALLOON_Q_STATSQ];
-
- // stats.mutex needs to be held during the entire time the guest is
- // processing the buffer since we need to make sure no other threads
- // can grab the returned stats buffer before we process it.
- fbl::AutoLock lock(&stats_.mutex);
-
- // We need an initial buffer we can return to return to the device to
- // request stats from the device. This should be immediately available in
- // the common case but we can race the driver for the initial buffer.
- WaitForStatsBuffer(stats_queue);
-
- // We have a buffer. We need to return it to the driver. It'll populate
- // a new buffer with stats and then send it back to us.
- stats_.has_buffer = false;
- virtio_queue_return(stats_queue, stats_.desc_index, 0);
- zx_status_t status = NotifyGuest();
- if (status != ZX_OK)
- return status;
- WaitForStatsBuffer(stats_queue);
-
- virtio_desc_t desc;
- status = virtio_queue_read_desc(stats_queue, stats_.desc_index, &desc);
- if (status != ZX_OK)
- return status;
-
- if ((desc.len % sizeof(virtio_balloon_stat_t)) != 0)
- return ZX_ERR_IO_DATA_INTEGRITY;
-
- // Invoke the handler on the stats.
- auto stats = static_cast<const virtio_balloon_stat_t*>(desc.addr);
- size_t stats_count = desc.len / sizeof(virtio_balloon_stat_t);
- handler(stats, stats_count);
-
- // Note we deliberately do not return the buffer here. This will be done to
- // initiate the next stats request.
- return ZX_OK;
-}
-
-zx_status_t VirtioBalloon::UpdateNumPages(uint32_t num_pages) {
- fbl::AutoLock lock(&config_mutex_);
- config_.num_pages = num_pages;
-
- // Send a config change interrupt to the guest.
- add_isr_flags(VirtioDevice::VIRTIO_ISR_DEVICE);
- return NotifyGuest();
-}
-
-uint32_t VirtioBalloon::num_pages() {
- fbl::AutoLock lock(&config_mutex_);
- return config_.num_pages;
-}
diff --git a/system/ulib/machina/block.cpp b/system/ulib/machina/block.cpp
deleted file mode 100644
index bde7d7a..0000000
--- a/system/ulib/machina/block.cpp
+++ /dev/null
@@ -1,368 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/block.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <block-client/client.h>
-#include <fbl/auto_call.h>
-#include <fbl/auto_lock.h>
-#include <fbl/unique_ptr.h>
-#include <virtio/virtio_ids.h>
-#include <virtio/virtio_ring.h>
-#include <zircon/compiler.h>
-#include <zircon/device/block.h>
-
-// Dispatcher that fulfills block requests using file-descriptor IO
-// (ex: read/write to a file descriptor).
-class FdioBlockDispatcher : public VirtioBlockRequestDispatcher {
-public:
- static zx_status_t Create(int fd, fbl::unique_ptr<VirtioBlockRequestDispatcher>* out) {
- fbl::AllocChecker ac;
- auto dispatcher = fbl::make_unique_checked<FdioBlockDispatcher>(&ac, fd);
- if (!ac.check())
- return ZX_ERR_NO_MEMORY;
-
- *out = fbl::move(dispatcher);
- return ZX_OK;
- }
-
- FdioBlockDispatcher(int fd)
- : fd_(fd) {}
-
- zx_status_t Flush() override {
- fbl::AutoLock lock(&file_mutex_);
- return fsync(fd_) == 0 ? ZX_OK : ZX_ERR_IO;
- }
-
- zx_status_t Read(off_t disk_offset, void* buf, size_t size) override {
- fbl::AutoLock lock(&file_mutex_);
- off_t off = lseek(fd_, disk_offset, SEEK_SET);
- if (off < 0)
- return ZX_ERR_IO;
-
- size_t ret = read(fd_, buf, size);
- if (ret != size)
- return ZX_ERR_IO;
- return ZX_OK;
- }
-
- zx_status_t Write(off_t disk_offset, const void* buf, size_t size) override {
- fbl::AutoLock lock(&file_mutex_);
- off_t off = lseek(fd_, disk_offset, SEEK_SET);
- if (off < 0)
- return ZX_ERR_IO;
-
- size_t ret = write(fd_, buf, size);
- if (ret != size)
- return ZX_ERR_IO;
- return ZX_OK;
- }
-
- zx_status_t Submit() override {
- // No-op, all IO methods are synchronous.
- return ZX_OK;
- }
-
-private:
- fbl::Mutex file_mutex_;
- int fd_;
-};
-
-class FifoBlockDispatcher : public VirtioBlockRequestDispatcher {
-public:
- static zx_status_t Create(int fd, const PhysMem& phys_mem,
- fbl::unique_ptr<VirtioBlockRequestDispatcher>* out) {
- zx_handle_t fifo;
- ssize_t result = ioctl_block_get_fifos(fd, &fifo);
- if (result != sizeof(fifo))
- return ZX_ERR_IO;
- auto close_fifo = fbl::MakeAutoCall([fifo]() { zx_handle_close(fifo); });
-
- txnid_t txnid = TXNID_INVALID;
- result = ioctl_block_alloc_txn(fd, &txnid);
- if (result != sizeof(txnid_))
- return ZX_ERR_IO;
- auto free_txn = fbl::MakeAutoCall([fd, txnid]() { ioctl_block_free_txn(fd, &txnid); });
-
- zx_handle_t vmo_dup;
- zx_status_t status = zx_handle_duplicate(phys_mem.vmo(), ZX_RIGHT_SAME_RIGHTS, &vmo_dup);
- if (status != ZX_OK)
- return ZX_ERR_IO;
-
- // TODO(ZX-1333): Limit how much of they guest physical address space
- // is exposed to the block server.
- vmoid_t vmoid;
- result = ioctl_block_attach_vmo(fd, &vmo_dup, &vmoid);
- if (result != sizeof(vmoid_)) {
- zx_handle_close(vmo_dup);
- return ZX_ERR_IO;
- }
-
- fifo_client_t* fifo_client = nullptr;
- status = block_fifo_create_client(fifo, &fifo_client);
- if (status != ZX_OK)
- return ZX_ERR_IO;
-
- // The fifo handle is now owned by the block client.
- fifo = ZX_HANDLE_INVALID;
- auto free_fifo_client = fbl::MakeAutoCall(
- [fifo_client]() { block_fifo_release_client(fifo_client); });
-
- fbl::AllocChecker ac;
- auto dispatcher = fbl::make_unique_checked<FifoBlockDispatcher>(&ac, fd, txnid, vmoid,
- fifo_client,
- phys_mem.addr());
- if (!ac.check())
- return ZX_ERR_NO_MEMORY;
-
- close_fifo.cancel();
- free_txn.cancel();
- free_fifo_client.cancel();
- *out = fbl::move(dispatcher);
- return ZX_OK;
- }
-
- FifoBlockDispatcher(int fd, txnid_t txnid, vmoid_t vmoid, fifo_client_t* fifo_client,
- size_t guest_vmo_addr)
- : fd_(fd), txnid_(txnid), vmoid_(vmoid), fifo_client_(fifo_client),
- guest_vmo_addr_(guest_vmo_addr) {}
-
- ~FifoBlockDispatcher() {
- if (txnid_ != TXNID_INVALID) {
- ioctl_block_free_txn(fd_, &txnid_);
- }
- if (fifo_client_ != nullptr) {
- block_fifo_release_client(fifo_client_);
- }
- }
-
- zx_status_t Flush() override {
- return ZX_OK;
- }
-
- zx_status_t Read(off_t disk_offset, void* buf, size_t size) override {
- fbl::AutoLock lock(&fifo_mutex_);
- return EnqueueBlockRequestLocked(BLOCKIO_READ, disk_offset, buf, size);
- }
-
- zx_status_t Write(off_t disk_offset, const void* buf, size_t size) override {
- fbl::AutoLock lock(&fifo_mutex_);
- return EnqueueBlockRequestLocked(BLOCKIO_WRITE, disk_offset, buf, size);
- }
-
- zx_status_t Submit() override {
- fbl::AutoLock lock(&fifo_mutex_);
- return SubmitTransactionsLocked();
- }
-
-private:
- zx_status_t EnqueueBlockRequestLocked(uint16_t opcode, off_t disk_offset, const void* buf,
- size_t size) __TA_REQUIRES(fifo_mutex_) {
- if (request_index_ >= kNumRequests) {
- zx_status_t status = SubmitTransactionsLocked();
- if (status != ZX_OK)
- return status;
- }
-
- block_fifo_request_t* request = &requests_[request_index_++];
- request->txnid = txnid_;
- request->vmoid = vmoid_;
- request->opcode = opcode;
- request->length = size;
- request->vmo_offset = reinterpret_cast<uint64_t>(buf) - guest_vmo_addr_;
- request->dev_offset = disk_offset;
- return ZX_OK;
- }
-
- zx_status_t SubmitTransactionsLocked() __TA_REQUIRES(fifo_mutex_) {
- zx_status_t status = block_fifo_txn(fifo_client_, requests_, request_index_);
- request_index_ = 0;
- return status;
- }
-
- // Block server access.
- int fd_;
- txnid_t txnid_ = TXNID_INVALID;
- vmoid_t vmoid_;
- fifo_client_t* fifo_client_ = nullptr;
-
- size_t guest_vmo_addr_;
- size_t request_index_ __TA_GUARDED(fifo_mutex_) = 0;
- static constexpr size_t kNumRequests = MAX_TXN_MESSAGES;
- block_fifo_request_t requests_[kNumRequests] __TA_GUARDED(fifo_mutex_);
- fbl::Mutex fifo_mutex_;
-};
-
-VirtioBlock::VirtioBlock(uintptr_t guest_physmem_addr, size_t guest_physmem_size)
- : VirtioDevice(VIRTIO_ID_BLOCK, &config_, sizeof(config_), &queue_, 1,
- guest_physmem_addr, guest_physmem_size) {
- config_.blk_size = kSectorSize;
- // Virtio 1.0: 5.2.5.2: Devices SHOULD always offer VIRTIO_BLK_F_FLUSH
- add_device_features(VIRTIO_BLK_F_FLUSH
- // Required by zircon guests.
- | VIRTIO_BLK_F_BLK_SIZE);
-}
-
-zx_status_t VirtioBlock::Init(const char* path, const PhysMem& phys_mem) {
- if (dispatcher_ != nullptr) {
- fprintf(stderr, "Block device has already been initialized.\n");
- return ZX_ERR_BAD_STATE;
- }
-
- // Open block file. First try to open as read-write but fall back to read
- // only if that fails.
- int fd = open(path, O_RDWR);
- if (fd < 0) {
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "Failed to open block file \"%s\"\n", path);
- return ZX_ERR_IO;
- }
- fprintf(stderr, "Unable to open block file \"%s\" read-write. "
- "Block device will be read-only.\n",
- path);
- set_read_only();
- }
- // Read file size.
- off_t ret = lseek(fd, 0, SEEK_END);
- if (ret < 0) {
- fprintf(stderr, "Failed to read size of block file \"%s\"\n", path);
- return ZX_ERR_IO;
- }
- size_ = ret;
- config_.capacity = size_ / kSectorSize;
-
- // Prefer using the faster FIFO-based IO. If the file is not a block device
- // file then fall back to using posix IO.
- fbl::unique_ptr<VirtioBlockRequestDispatcher> dispatcher;
- zx_status_t status = FifoBlockDispatcher::Create(fd, phys_mem, &dispatcher);
- if (status == ZX_OK) {
- printf("virtio-block: Using FIFO IO for block device '%s'.\n", path);
- } else {
- status = FdioBlockDispatcher::Create(fd, &dispatcher);
- if (status != ZX_OK)
- return status;
- printf("virtio-block: Using posix IO for block device '%s'.\n", path);
- }
- dispatcher_ = fbl::move(dispatcher);
-
- return ZX_OK;
-}
-
-zx_status_t VirtioBlock::Start() {
- auto poll_func = +[](virtio_queue_t* queue, uint16_t head, uint32_t* used, void* ctx) {
- return static_cast<VirtioBlock*>(ctx)->HandleBlockRequest(queue, head, used);
- };
- return virtio_queue_poll(&queue_, poll_func, this);
-}
-
-zx_status_t VirtioBlock::HandleBlockRequest(virtio_queue_t* queue, uint16_t head, uint32_t* used) {
- uint8_t block_status = VIRTIO_BLK_S_OK;
- uint8_t* block_status_ptr = nullptr;
- const virtio_blk_req_t* req = nullptr;
- off_t offset = 0;
- virtio_desc_t desc;
-
- zx_status_t status = virtio_queue_read_desc(queue, head, &desc);
- if (status != ZX_OK) {
- desc.addr = nullptr;
- desc.len = 0;
- desc.has_next = false;
- }
-
- if (desc.len == sizeof(virtio_blk_req_t)) {
- req = static_cast<const virtio_blk_req_t*>(desc.addr);
- } else {
- block_status = VIRTIO_BLK_S_IOERR;
- }
-
- // VIRTIO 1.0 Section 5.2.6.2: A device MUST set the status byte to
- // VIRTIO_BLK_S_IOERR for a write request if the VIRTIO_BLK_F_RO feature
- // if offered, and MUST NOT write any data.
- if (req != nullptr && req->type == VIRTIO_BLK_T_OUT && is_read_only()) {
- block_status = VIRTIO_BLK_S_IOERR;
- }
-
- // VIRTIO Version 1.0: A driver MUST set sector to 0 for a
- // VIRTIO_BLK_T_FLUSH request. A driver SHOULD NOT include any data in a
- // VIRTIO_BLK_T_FLUSH request.
- if (req != nullptr && req->type == VIRTIO_BLK_T_FLUSH && req->sector != 0) {
- block_status = VIRTIO_BLK_S_IOERR;
- }
-
- // VIRTIO 1.0 Section 5.2.5.2: If the VIRTIO_BLK_F_BLK_SIZE feature is
- // negotiated, blk_size can be read to determine the optimal sector size
- // for the driver to use. This does not affect the units used in the
- // protocol (always 512 bytes), but awareness of the correct value can
- // affect performance.
- if (req != nullptr)
- offset = req->sector * kSectorSize;
-
- while (desc.has_next) {
- status = virtio_queue_read_desc(queue, desc.next, &desc);
- if (status != ZX_OK) {
- block_status = block_status != VIRTIO_BLK_S_OK ? block_status : VIRTIO_BLK_S_IOERR;
- break;
- }
-
- // Requests should end with a single 1b status byte.
- if (desc.len == 1 && desc.writable && !desc.has_next) {
- block_status_ptr = static_cast<uint8_t*>(desc.addr);
- break;
- }
-
- // Skip doing any file ops if we've already encountered an error, but
- // keep traversing the descriptor chain looking for the status tailer.
- if (block_status != VIRTIO_BLK_S_OK)
- continue;
-
- zx_status_t status;
- switch (req->type) {
- case VIRTIO_BLK_T_IN:
- if (desc.len % kSectorSize != 0) {
- block_status = VIRTIO_BLK_S_IOERR;
- continue;
- }
- status = dispatcher_->Read(offset, desc.addr, desc.len);
- *used += desc.len;
- offset += desc.len;
- break;
- case VIRTIO_BLK_T_OUT: {
- if (desc.len % kSectorSize != 0) {
- block_status = VIRTIO_BLK_S_IOERR;
- continue;
- }
- status = dispatcher_->Write(offset, desc.addr, desc.len);
- offset += desc.len;
- break;
- }
- case VIRTIO_BLK_T_FLUSH:
- status = dispatcher_->Flush();
- break;
- default:
- block_status = VIRTIO_BLK_S_UNSUPP;
- break;
- }
-
- // Report any failures queuing the IO request.
- if (block_status == VIRTIO_BLK_S_OK && status != ZX_OK)
- block_status = VIRTIO_BLK_S_IOERR;
- }
-
- // Wait for operations to become consistent.
- status = dispatcher_->Submit();
- if (block_status == VIRTIO_BLK_S_OK && status != ZX_OK)
- block_status = VIRTIO_BLK_S_IOERR;
-
- // Set the output status if we found the byte in the descriptor chain.
- if (block_status_ptr != nullptr) {
- *block_status_ptr = block_status;
- ++*used;
- }
- return ZX_OK;
-}
diff --git a/system/ulib/machina/gpu.cpp b/system/ulib/machina/gpu.cpp
deleted file mode 100644
index fb3cd95..0000000
--- a/system/ulib/machina/gpu.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/gpu.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <fbl/intrusive_hash_table.h>
-#include <fbl/unique_ptr.h>
-#include <virtio/virtio_ids.h>
-#include <zircon/pixelformat.h>
-#include <zircon/process.h>
-
-VirtioGpu::VirtioGpu(uintptr_t guest_physmem_addr, size_t guest_physmem_size)
- : VirtioDevice(VIRTIO_ID_GPU, &config_, sizeof(config_), queues_, VIRTIO_GPU_Q_COUNT,
- guest_physmem_addr, guest_physmem_size) {
-}
-
-zx_status_t VirtioGpu::Init(const char* path) {
- fbl::unique_ptr<GpuScanout> gpu_scanout;
- zx_status_t status = FramebufferScanout::Create(path, &gpu_scanout);
- if (status != ZX_OK)
- return status;
-
- status = AddScanout(fbl::move(gpu_scanout));
- if (status != ZX_OK)
- return status;
-
- status = virtio_queue_poll(&queues_[VIRTIO_GPU_Q_CONTROLQ], &VirtioGpu::QueueHandler, this);
- if (status != ZX_OK)
- return status;
-
- status = virtio_queue_poll(&queues_[VIRTIO_GPU_Q_CURSORQ], &VirtioGpu::QueueHandler, this);
- if (status != ZX_OK)
- return status;
-
- return ZX_OK;
-}
-
-zx_status_t VirtioGpu::AddScanout(fbl::unique_ptr<GpuScanout> scanout) {
- if (scanout_ != nullptr)
- return ZX_ERR_ALREADY_EXISTS;
-
- config_.num_scanouts = 1;
- scanout_ = fbl::move(scanout);
- return ZX_OK;
-}
-
-zx_status_t VirtioGpu::QueueHandler(virtio_queue_t* queue, uint16_t head, uint32_t* used,
- void* ctx) {
- VirtioGpu* gpu = reinterpret_cast<VirtioGpu*>(ctx);
- return gpu->HandleGpuCommand(queue, head, used);
-}
-
-zx_status_t VirtioGpu::HandleGpuCommand(virtio_queue_t* queue, uint16_t head, uint32_t* used) {
- virtio_desc_t request_desc;
- virtio_queue_read_desc(queue, head, &request_desc);
-
- if (!request_desc.has_next)
- return ZX_ERR_INVALID_ARGS;
- auto header = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(request_desc.addr);
-
- switch (header->type) {
- case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: {
- virtio_desc_t response_desc;
- virtio_queue_read_desc(queue, request_desc.next, &response_desc);
- auto request = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(request_desc.addr);
- auto response = reinterpret_cast<virtio_gpu_resp_display_info_t*>(response_desc.addr);
- GetDisplayInfo(request, response);
- return ZX_OK;
- }
- case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: {
- virtio_desc_t response_desc;
- virtio_queue_read_desc(queue, request_desc.next, &response_desc);
- auto request = reinterpret_cast<virtio_gpu_resource_create_2d_t*>(request_desc.addr);
- auto response = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(response_desc.addr);
- ResourceCreate2D(request, response);
- return ZX_OK;
- }
- case VIRTIO_GPU_CMD_SET_SCANOUT: {
- virtio_desc_t response_desc;
- virtio_queue_read_desc(queue, request_desc.next, &response_desc);
- auto request = reinterpret_cast<virtio_gpu_set_scanout_t*>(request_desc.addr);
- auto response = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(response_desc.addr);
- SetScanout(request, response);
- return ZX_OK;
- }
- case VIRTIO_GPU_CMD_RESOURCE_FLUSH: {
- virtio_desc_t response_desc;
- virtio_queue_read_desc(queue, request_desc.next, &response_desc);
- auto request = reinterpret_cast<virtio_gpu_resource_flush_t*>(request_desc.addr);
- auto response = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(response_desc.addr);
- ResourceFlush(request, response);
- return ZX_OK;
- }
- case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: {
- virtio_desc_t response_desc;
- virtio_queue_read_desc(queue, request_desc.next, &response_desc);
- auto request = reinterpret_cast<virtio_gpu_transfer_to_host_2d_t*>(request_desc.addr);
- auto response = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(response_desc.addr);
- TransferToHost2D(request, response);
- return ZX_OK;
- }
- case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: {
- virtio_desc_t response_desc;
- virtio_queue_read_desc(queue, request_desc.next, &response_desc);
-
- // This may or may not be on the same descriptor.
- virtio_gpu_mem_entry_t* mem_entries;
- if (response_desc.has_next) {
- mem_entries = reinterpret_cast<virtio_gpu_mem_entry_t*>(response_desc.addr);
- virtio_queue_read_desc(queue, response_desc.next, &response_desc);
- } else {
- uintptr_t addr = reinterpret_cast<uintptr_t>(request_desc.addr) +
- sizeof(virtio_gpu_resource_attach_backing_t);
- mem_entries = reinterpret_cast<virtio_gpu_mem_entry_t*>(addr);
- }
-
- auto request = reinterpret_cast<virtio_gpu_resource_attach_backing_t*>(request_desc.addr);
- auto response = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(response_desc.addr);
- ResourceAttachBacking(request, mem_entries, response);
- return ZX_OK;
- }
- case VIRTIO_GPU_CMD_RESOURCE_UNREF: {
- virtio_desc_t response_desc;
- virtio_queue_read_desc(queue, request_desc.next, &response_desc);
- auto request = reinterpret_cast<virtio_gpu_resource_unref_t*>(request_desc.addr);
- auto response = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(response_desc.addr);
- ResourceUnref(request, response);
- return ZX_OK;
- }
- case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: {
- virtio_desc_t response_desc;
- virtio_queue_read_desc(queue, request_desc.next, &response_desc);
- auto request = reinterpret_cast<virtio_gpu_resource_detach_backing_t*>(request_desc.addr);
- auto response = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(response_desc.addr);
- ResourceDetachBacking(request, response);
- return ZX_OK;
- }
- // Not yet implemented.
- case VIRTIO_GPU_CMD_UPDATE_CURSOR:
- case VIRTIO_GPU_CMD_MOVE_CURSOR: {
- default:
- fprintf(stderr, "Unsupported GPU command %d\n", header->type);
- // ACK.
- virtio_desc_t response_desc;
- virtio_queue_read_desc(queue, request_desc.next, &response_desc);
- auto resp = reinterpret_cast<virtio_gpu_ctrl_hdr_t*>(response_desc.addr);
- resp->type = VIRTIO_GPU_RESP_ERR_UNSPEC;
- return ZX_ERR_NOT_SUPPORTED;
- }
- }
-}
-
-void VirtioGpu::GetDisplayInfo(const virtio_gpu_ctrl_hdr_t* request,
- virtio_gpu_resp_display_info_t* response) {
- virtio_gpu_display_one_t* display = &response->pmodes[0];
- if (scanout_ == nullptr) {
- memset(display, 0, sizeof(*display));
- response->hdr.type = VIRTIO_GPU_RESP_ERR_UNSPEC;
- return;
- }
-
- display->enabled = 1;
- display->r.x = 0;
- display->r.y = 0;
- display->r.width = scanout_->width();
- display->r.height = scanout_->height();
- response->hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
-}
-
-void VirtioGpu::ResourceCreate2D(const virtio_gpu_resource_create_2d_t* request,
- virtio_gpu_ctrl_hdr_t* response) {
- auto res = fbl::make_unique<GpuResource>(this, request);
- resources_.insert(fbl::move(res));
- response->type = VIRTIO_GPU_RESP_OK_NODATA;
-}
-
-void VirtioGpu::ResourceUnref(const virtio_gpu_resource_unref_t* request,
- virtio_gpu_ctrl_hdr_t* response) {
- auto it = resources_.find(request->resource_id);
- if (it == resources_.end()) {
- response->type = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
- resources_.erase(it);
- response->type = VIRTIO_GPU_RESP_OK_NODATA;
-}
-
-void VirtioGpu::SetScanout(const virtio_gpu_set_scanout_t* request,
- virtio_gpu_ctrl_hdr_t* response) {
- if (request->resource_id == 0) {
- // Resource ID 0 is a special case and means the provided scanout
- // should be disabled.
- response->type = VIRTIO_GPU_RESP_OK_NODATA;
- return;
- }
- if (request->scanout_id != 0 || scanout_ == nullptr) {
- // Only a single scanout is supported.
- response->type = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
- return;
- }
-
- auto it = resources_.find(request->resource_id);
- if (it == resources_.end()) {
- response->type = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
-
- // Only support a simple scanout where resource/scanout coordinates map
- // 1:1. This is currently what linux and zircon virtcons do but this
- // assumption will likely break down with a more advanced driver.
- if (scanout_->width() != it->width() || scanout_->height() != it->height()) {
- fprintf(stderr, "virtio-gpu: resource/scanout size mismatch not supported.\n");
- response->type = VIRTIO_GPU_RESP_ERR_UNSPEC;
- return;
- }
- if (request->r.x != 0 || request->r.y != 0 || request->r.width != it->width() ||
- request->r.height != it->height()) {
- fprintf(stderr, "virtio-gpu: partial scanout not supported.\n");
- response->type = VIRTIO_GPU_RESP_ERR_UNSPEC;
- return;
- }
- if (it->format() != scanout_->format()) {
- fprintf(stderr, "virtio-gpu: resource/scanout pixel format mismatch not supported.\n");
- response->type = VIRTIO_GPU_RESP_ERR_UNSPEC;
- return;
- }
-
- response->type = it->SetScanout(scanout_.get());
-}
-
-void VirtioGpu::ResourceAttachBacking(const virtio_gpu_resource_attach_backing_t* request,
- const virtio_gpu_mem_entry_t* mem_entries,
- virtio_gpu_ctrl_hdr_t* response) {
- auto it = resources_.find(request->resource_id);
- if (it == resources_.end()) {
- response->type = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
- response->type = it->AttachBacking(mem_entries, request->nr_entries);
-}
-
-void VirtioGpu::ResourceDetachBacking(const virtio_gpu_resource_detach_backing_t* request,
- virtio_gpu_ctrl_hdr_t* response) {
- auto it = resources_.find(request->resource_id);
- if (it == resources_.end()) {
- response->type = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
- response->type = it->DetachBacking();
-}
-
-void VirtioGpu::TransferToHost2D(const virtio_gpu_transfer_to_host_2d_t* request,
- virtio_gpu_ctrl_hdr_t* response) {
- auto it = resources_.find(request->resource_id);
- if (it == resources_.end()) {
- response->type = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
- response->type = it->TransferToHost2D(request);
-}
-
-void VirtioGpu::ResourceFlush(const virtio_gpu_resource_flush_t* request,
- virtio_gpu_ctrl_hdr_t* response) {
- auto it = resources_.find(request->resource_id);
- if (it == resources_.end()) {
- response->type = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
- return;
- }
- response->type = it->Flush(request);
-}
-
-// Convert virtio gpu formats to zircon formats.
-uint32_t FramebufferScanout::VirtioPixelFormat(uint32_t zx_format) {
- switch (zx_format) {
- case ZX_PIXEL_FORMAT_ARGB_8888:
- return VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM;
- case ZX_PIXEL_FORMAT_RGB_x888:
- return VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM;
- default:
- fprintf(stderr, "zircon format %#x not known\n", zx_format);
- return 0;
- }
-}
-
-zx_status_t FramebufferScanout::Create(const char* path, fbl::unique_ptr<GpuScanout>* out) {
- // Open framebuffer and get display info.
- int vfd = open(path, O_RDWR);
- if (vfd < 0)
- return ZX_ERR_NOT_FOUND;
-
- ioctl_display_get_fb_t fb;
- if (ioctl_display_get_fb(vfd, &fb) != sizeof(fb)) {
- close(vfd);
- return ZX_ERR_NOT_FOUND;
- }
-
- // Map framebuffer VMO.
- uintptr_t fbo;
- size_t size = fb.info.stride * fb.info.pixelsize * fb.info.height;
- zx_status_t status = zx_vmar_map(zx_vmar_root_self(), 0, fb.vmo, 0, size,
- ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &fbo);
- if (status != ZX_OK) {
- close(vfd);
- return status;
- }
-
- auto scanout = fbl::make_unique<FramebufferScanout>(vfd, fb, reinterpret_cast<uint8_t*>(fbo));
- *out = fbl::move(scanout);
- return ZX_OK;
-}
-
-FramebufferScanout::~FramebufferScanout() {
- if (fd_ > 0)
- close(fd_);
-}
-
-void FramebufferScanout::FlushRegion(const virtio_gpu_rect_t& r) {
- ioctl_display_region_t fb_region = {
- .x = r.x,
- .y = r.y,
- .width = r.width,
- .height = r.height,
- };
- ioctl_display_flush_fb_region(fd_, &fb_region);
-}
-
-GpuResource::GpuResource(VirtioGpu* gpu, const virtio_gpu_resource_create_2d_t* args)
- : gpu_(gpu), res_id_(args->resource_id), width_(args->width), height_(args->height),
- format_(args->format) {}
-
-virtio_gpu_ctrl_type GpuResource::AttachBacking(const virtio_gpu_mem_entry_t* mem_entries,
- uint32_t num_entries) {
- const size_t required_bytes = width() * height() * VirtioGpu::kBytesPerPixel;
- size_t backing_size = 0;
- for (int i = num_entries - 1; i >= 0; --i) {
- const virtio_gpu_mem_entry_t* entry = &mem_entries[i];
- backing_.push_front(fbl::make_unique<BackingPages>(entry->addr, entry->length));
- backing_size += entry->length;
- }
- if (backing_size < required_bytes) {
- fprintf(stderr, "virtio-gpu: attach backing command provided buffer is too small.\n");
- backing_.clear();
- return VIRTIO_GPU_RESP_ERR_UNSPEC;
- }
- return VIRTIO_GPU_RESP_OK_NODATA;
-}
-
-virtio_gpu_ctrl_type GpuResource::DetachBacking() {
- backing_.clear();
- return VIRTIO_GPU_RESP_OK_NODATA;
-}
-
-virtio_gpu_ctrl_type GpuResource::TransferToHost2D(const virtio_gpu_transfer_to_host_2d_t* request) {
- if (scanout_ == nullptr)
- return VIRTIO_GPU_RESP_ERR_UNSPEC;
- if (backing_.is_empty())
- return VIRTIO_GPU_RESP_ERR_UNSPEC;
-
- // Optimize for copying a contiguous region.
- uint32_t stride = scanout_->width() * VirtioGpu::kBytesPerPixel;
- if (request->offset == 0 && request->r.x == 0 && request->r.y == 0 &&
- request->r.width == scanout_->width()) {
- CopyBytes(0, scanout_->buffer(), stride * scanout_->height());
- return VIRTIO_GPU_RESP_OK_NODATA;
- }
-
- // line-by-line copy.
- uint32_t linesize = request->r.width * 4;
- for (uint32_t line = 0; line < request->r.height; ++line) {
- uint64_t src_offset = request->offset + stride * line;
- size_t size = ((request->r.y + line) * stride) + (request->r.x * VirtioGpu::kBytesPerPixel);
-
- CopyBytes(src_offset, scanout_->buffer() + size, linesize);
- }
- return VIRTIO_GPU_RESP_OK_NODATA;
-}
-
-virtio_gpu_ctrl_type GpuResource::Flush(const virtio_gpu_resource_flush_t* request) {
- if (scanout_ == nullptr)
- return VIRTIO_GPU_RESP_ERR_UNSPEC;
-
- scanout_->FlushRegion(request->r);
- return VIRTIO_GPU_RESP_OK_NODATA;
-}
-
-virtio_gpu_ctrl_type GpuResource::SetScanout(GpuScanout* scanout) {
- scanout_ = scanout;
- return VIRTIO_GPU_RESP_OK_NODATA;
-}
-
-void GpuResource::CopyBytes(uint64_t offset, uint8_t* dest, size_t size) {
- size_t base = 0;
- for (const auto& entry : backing_) {
- if (size == 0)
- break;
- if (base + entry.length > offset) {
- size_t len = (entry.length + base) - offset;
- len = len > size ? size : len;
-
- zx_vaddr_t src_vaddr = gpu_->guest_physmem_addr() + entry.addr;
- src_vaddr = src_vaddr + offset - base;
-
- memcpy(dest, reinterpret_cast<void*>(src_vaddr), len);
-
- dest += len;
- offset += len;
- size -= len;
- }
- base += entry.length;
- }
-}
diff --git a/system/ulib/machina/include/machina/balloon.h b/system/ulib/machina/include/machina/balloon.h
deleted file mode 100644
index 683ddc4..0000000
--- a/system/ulib/machina/include/machina/balloon.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <fbl/function.h>
-#include <fbl/mutex.h>
-#include <machina/virtio.h>
-#include <virtio/balloon.h>
-#include <zircon/compiler.h>
-#include <zircon/types.h>
-
-#define VIRTIO_BALLOON_Q_INFLATEQ 0
-#define VIRTIO_BALLOON_Q_DEFLATEQ 1
-#define VIRTIO_BALLOON_Q_STATSQ 2
-#define VIRTIO_BALLOON_Q_COUNT 3
-
-/* Virtio memory balloon device. */
-class VirtioBalloon : public VirtioDevice {
-public:
- // Per Virtio 1.0 Section 5.5.6, This value is historical, and independent
- // of the guest page size.
- static const uint32_t kPageSize = 4096;
-
- VirtioBalloon(uintptr_t guest_physmem_addr, size_t guest_physmem_size,
- zx_handle_t guest_physmem_vmo);
- ~VirtioBalloon() override = default;
-
- zx_status_t HandleQueueNotify(uint16_t queue_sel) override;
-
- // Receives an array of statistics in |stats| that contains |len| entries.
- //
- // The pointers backing |stats| are only guaranteed to live for the
- // duration of this callback.
- using StatsHandler = fbl::Function<void(const virtio_balloon_stat_t* stats, size_t len)>;
-
- // Request balloon memory statistics from the guest.
- //
- // Sends a message to the driver that memory stats are requested. Once the
- // driver has provided the statistics, the handler will be invoked.
- //
- // This method blocks for the entire duration of the request.
- zx_status_t RequestStats(StatsHandler handler);
-
- // Update the 'num_pages' configuration field in the balloon.
- //
- // If the value is greater than what it currently is, the driver should
- // provided pages to us. If the value is less than what it currently is,
- // driver is free to reclaim memory from the balloon.
- zx_status_t UpdateNumPages(uint32_t num_pages);
-
- // Read the 'num_pages' configuration field.
- uint32_t num_pages();
-
- // If deflate on demand is enabled, then the balloon will treat deflate
- // requests as a no-op. This memory will instead be provided via demand
- // paging.
- void set_deflate_on_demand(bool b) { deflate_on_demand_ = b; }
-
-private:
- void WaitForStatsBuffer(virtio_queue_t* stats_queue) __TA_REQUIRES(stats_.mutex);
-
- zx_status_t HandleDescriptor(uint16_t queue_sel);
-
- // Handle to the guest phsycial memory VMO for memory management.
- zx_handle_t vmo_ = ZX_HANDLE_INVALID;
-
- // With on-demand deflation we won't commit memory up-front for balloon
- // deflate requests.
- bool deflate_on_demand_ = false;
-
- struct {
- // The index in the available ring of the stats descriptor.
- uint16_t desc_index __TA_GUARDED(mutex) = 0;
- // Indicates if desc_index valid.
- bool has_buffer __TA_GUARDED(mutex) = false;
- // Holds exclusive access to the stats queue. At most one stats request
- // can be active at a time (by design). Specifically we need to hold
- // exclusive access of the queue from the time a buffer is returned to
- // the queue, initiating a stats request, until any logic processing
- // the result has finished.
- //
- // Also guards access to other members of this structure.
- fbl::Mutex mutex;
- } stats_;
-
- virtio_queue_t queues_[VIRTIO_BALLOON_Q_COUNT];
-
- virtio_balloon_config_t config_ __TA_GUARDED(config_mutex_) = {};
-};
diff --git a/system/ulib/machina/include/machina/block.h b/system/ulib/machina/include/machina/block.h
deleted file mode 100644
index 4bc9fa65..0000000
--- a/system/ulib/machina/include/machina/block.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <fbl/mutex.h>
-#include <machina/virtio.h>
-#include <virtio/block.h>
-
-typedef struct file_state file_state_t;
-
-// Component to service block requests.
-class VirtioBlockRequestDispatcher {
-public:
- virtual ~VirtioBlockRequestDispatcher() = default;
-
- virtual zx_status_t Flush() = 0;
- virtual zx_status_t Read(off_t disk_offset, void* buf, size_t size) = 0;
- virtual zx_status_t Write(off_t disk_offset, const void* buf, size_t size) = 0;
- virtual zx_status_t Submit() = 0;
-
-};
-
-// Stores the state of a block device.
-class VirtioBlock : public VirtioDevice {
-public:
- static const size_t kSectorSize = 512;
-
- VirtioBlock(uintptr_t guest_physmem_addr, size_t guest_physmem_size);
- ~VirtioBlock() override = default;
-
- // Opens a file to use as backing for the block device.
- //
- // Default to opening the file as read-write, but fall back to read-only
- // if that is not possible.
- zx_status_t Init(const char* path, const PhysMem& phys_mem);
-
- // Starts a thread to monitor the queue for incomming block requests.
- zx_status_t Start();
-
- // Our config space is read-only.
- zx_status_t WriteConfig(uint64_t addr, const IoValue& value) override {
- return ZX_ERR_NOT_SUPPORTED;
- }
-
- zx_status_t HandleBlockRequest(virtio_queue_t* queue, uint16_t head, uint32_t* used);
-
- // The 'read-only' feature flag.
- bool is_read_only() { return has_device_features(VIRTIO_BLK_F_RO); }
- void set_read_only() { add_device_features(VIRTIO_BLK_F_RO); }
-
- // The queue used for handling block reauests.
- virtio_queue_t& queue() { return queue_; }
-
-private:
- // Size of file backing the block device.
- uint64_t size_ = 0;
- // Queue for handling block requests.
- virtio_queue_t queue_;
- // Device configuration fields.
- virtio_blk_config_t config_ = {};
-
- fbl::unique_ptr<VirtioBlockRequestDispatcher> dispatcher_;
-};
diff --git a/system/ulib/machina/include/machina/gpu.h b/system/ulib/machina/include/machina/gpu.h
deleted file mode 100644
index 383a529..0000000
--- a/system/ulib/machina/include/machina/gpu.h
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <fbl/intrusive_hash_table.h>
-#include <fbl/mutex.h>
-#include <fbl/unique_ptr.h>
-#include <machina/virtio.h>
-#include <virtio/gpu.h>
-#include <zircon/compiler.h>
-#include <zircon/device/display.h>
-#include <zircon/types.h>
-
-#define VIRTIO_GPU_Q_CONTROLQ 0
-#define VIRTIO_GPU_Q_CURSORQ 1
-#define VIRTIO_GPU_Q_COUNT 2
-
-class VirtioGpu;
-
-using ResourceId = uint32_t;
-using ScanoutId = uint32_t;
-
-/* A scanout represents a display that GPU resources can be rendered to.
- *
- * Each scanout will own a single device under /dev/class/framebuffer/
- */
-class GpuScanout {
-public:
- GpuScanout(uint32_t width, uint32_t height, uint32_t format, uint8_t* buffer)
- : width_(width), height_(height), format_(format), buffer_(buffer) {}
-
- virtual ~GpuScanout() = default;
-
- uint32_t width() const { return width_; }
- uint32_t height() const { return height_; }
- uint32_t format() const { return format_; }
- uint8_t* buffer() const { return buffer_; }
-
- virtual void FlushRegion(const virtio_gpu_rect_t& rect) {}
-
-private:
- uint32_t width_;
- uint32_t height_;
- uint32_t format_;
- uint8_t* buffer_;
-};
-
-class FramebufferScanout : public GpuScanout {
-public:
- static zx_status_t Create(const char* framebuffer, fbl::unique_ptr<GpuScanout>* out);
-
- FramebufferScanout(int fd, const ioctl_display_get_fb_t& fb, uint8_t* buffer)
- : GpuScanout(fb.info.width, fb.info.height, VirtioPixelFormat(fb.info.format), buffer),
- fd_(fd) {}
-
- virtual ~FramebufferScanout();
-
- void FlushRegion(const virtio_gpu_rect_t& rect) override;
-
-private:
- static uint32_t VirtioPixelFormat(uint32_t zx_format);
- int fd_ = 0;
-};
-
-/* A resource corresponds to a single display buffer. */
-class GpuResource : public fbl::SinglyLinkedListable<fbl::unique_ptr<GpuResource>> {
-public:
- // The driver will provide a scatter-gather list of memory pages to back
- // the framebuffer in guest physical memory.
- struct BackingPages : public fbl::SinglyLinkedListable<fbl::unique_ptr<BackingPages>> {
- uint64_t addr;
- uint32_t length;
-
- BackingPages(uint64_t addr_, uint32_t length_)
- : addr(addr_), length(length_) {}
- };
-
- // Fix the number of hash table buckets to 1 because linux and zircon
- // virtcons only use a single resource.
- static constexpr size_t kNumHashTableBuckets = 1;
- using HashTable = fbl::HashTable<ResourceId,
- fbl::unique_ptr<GpuResource>,
- fbl::SinglyLinkedList<fbl::unique_ptr<GpuResource>>,
- size_t,
- kNumHashTableBuckets>;
-
- GpuResource(VirtioGpu* gpu, const virtio_gpu_resource_create_2d_t* args);
-
- uint32_t width() const { return width_; }
- uint32_t height() const { return height_; }
- uint32_t format() const { return format_; }
-
- virtio_gpu_ctrl_type SetScanout(GpuScanout* scanout);
-
- // Handle a VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING command for this
- // resource.
- virtio_gpu_ctrl_type AttachBacking(const virtio_gpu_mem_entry_t* mem_entries,
- uint32_t num_entries);
-
- // Handle a VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING command for this
- // resource.
- virtio_gpu_ctrl_type DetachBacking();
-
- // Handle a VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D command for this
- // resource.
- virtio_gpu_ctrl_type TransferToHost2D(const virtio_gpu_transfer_to_host_2d_t* request);
-
- // Handle a VIRTIO_GPU_CMD_RESOURCE_FLUSH command for this
- // resource.
- virtio_gpu_ctrl_type Flush(const virtio_gpu_resource_flush_t* request);
-
- // Handle a VIRTIO_GPU_CMD_SET_SCANOUT command for this
- // resource.
- virtio_gpu_ctrl_type Flush(GpuScanout* scanout);
-
- // Trait implementation for fbl::HashTable
- ResourceId GetKey() const { return res_id_; }
- static size_t GetHash(ResourceId key) { return key; }
-
-private:
- // Copies bytes from the linked list of backing pages in guest memory into
- // a host resource.
- void CopyBytes(uint64_t offset, uint8_t* dest, size_t size);
-
- VirtioGpu* gpu_;
- GpuScanout* scanout_;
- ResourceId res_id_;
- uint32_t width_;
- uint32_t height_;
- uint32_t format_;
- fbl::SinglyLinkedList<fbl::unique_ptr<BackingPages>> backing_;
-};
-
-/* Virtio 2D GPU device. */
-class VirtioGpu : public VirtioDevice {
-public:
- static constexpr uint8_t kBytesPerPixel = 4;
-
- VirtioGpu(uintptr_t guest_physmem_addr, size_t guest_physmem_size);
- ~VirtioGpu() override = default;
-
- virtio_queue_t& control_queue() { return queues_[VIRTIO_GPU_Q_CONTROLQ]; }
- virtio_queue_t& cursor_queue() { return queues_[VIRTIO_GPU_Q_CURSORQ]; }
-
- // Opens the framebuffer device located at |path| and starts processing
- // any descriptors that become available in the queues.
- zx_status_t Init(const char* path);
-
- // Adds a scanout to the GPU.
- //
- // Currently only a single scanout is supported. ZX_ERR_ALREADY_EXISTS will
- // be returned if this method is called multiple times.
- zx_status_t AddScanout(fbl::unique_ptr<GpuScanout> scanout);
-
- zx_status_t HandleGpuCommand(virtio_queue_t* queue, uint16_t head, uint32_t* used);
-
-protected:
- static zx_status_t QueueHandler(virtio_queue_t* queue, uint16_t head, uint32_t* used,
- void* ctx);
-
- // VIRTIO_GPU_CMD_GET_DISPLAY_INFO
- void GetDisplayInfo(const virtio_gpu_ctrl_hdr_t* request,
- virtio_gpu_resp_display_info_t* response);
-
- // VIRTIO_GPU_CMD_RESOURCE_CREATE_2D
- void ResourceCreate2D(const virtio_gpu_resource_create_2d_t* request,
- virtio_gpu_ctrl_hdr_t* response);
-
- // VIRTIO_GPU_CMD_RESOURCE_UNREF
- void ResourceUnref(const virtio_gpu_resource_unref_t* request,
- virtio_gpu_ctrl_hdr_t* response);
-
- // VIRTIO_GPU_CMD_SET_SCANOUT
- void SetScanout(const virtio_gpu_set_scanout_t* request, virtio_gpu_ctrl_hdr_t* response);
-
- // VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING
- void ResourceAttachBacking(const virtio_gpu_resource_attach_backing_t* request,
- const virtio_gpu_mem_entry_t* mem_entries,
- virtio_gpu_ctrl_hdr_t* response);
-
- // VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING
- void ResourceDetachBacking(const virtio_gpu_resource_detach_backing_t* request,
- virtio_gpu_ctrl_hdr_t* response);
-
- // VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D
- void TransferToHost2D(const virtio_gpu_transfer_to_host_2d_t* request,
- virtio_gpu_ctrl_hdr_t* response);
-
- // VIRTIO_GPU_CMD_RESOURCE_FLUSH
- void ResourceFlush(const virtio_gpu_resource_flush_t* request,
- virtio_gpu_ctrl_hdr_t* response);
-
-private:
- fbl::unique_ptr<GpuScanout> scanout_;
- GpuResource::HashTable resources_;
- virtio_queue_t queues_[VIRTIO_GPU_Q_COUNT];
- virtio_gpu_config_t config_ = {};
-};
diff --git a/system/ulib/machina/include/machina/input.h b/system/ulib/machina/include/machina/input.h
deleted file mode 100644
index 984faea..0000000
--- a/system/ulib/machina/include/machina/input.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <fbl/intrusive_single_list.h>
-#include <fbl/unique_ptr.h>
-#include <hid/hid.h>
-#include <machina/virtio.h>
-#include <virtio/input.h>
-#include <zircon/compiler.h>
-#include <zircon/device/input.h>
-#include <zircon/types.h>
-
-#define VIRTIO_INPUT_Q_EVENTQ 0
-#define VIRTIO_INPUT_Q_STATUSQ 1
-#define VIRTIO_INPUT_Q_COUNT 2
-
-/* Interface for manipulating the stream of input events. */
-class VirtioInputEventEmitter {
-public:
- virtual ~VirtioInputEventEmitter() = default;
-
- virtual zx_status_t QueueInputEvent(const virtio_input_event_t& event) = 0;
-
- virtual zx_status_t FlushInputEvents() = 0;
-};
-
-/* Manages input events from a single (host) keyboard device. */
-class KeyboardEventSource : public fbl::SinglyLinkedListable<fbl::unique_ptr<KeyboardEventSource>> {
-public:
- // Map HID scancodes to evdev keycodes.
- //
- // See include/uapi/linux/input-event-codes.h in the linux kernel for the full
- // set of evdev keycodes.
- static const uint8_t kKeyMap[];
-
- KeyboardEventSource(VirtioInputEventEmitter* emitter, int fd)
- : fd_(fd), emitter_(emitter) {}
-
- ~KeyboardEventSource();
-
- // Compares |keys| against the previous report to infer which keys have
- // been pressed or released. Sends a corresponding evdev event for each
- // key press/release.
- zx_status_t HandleHidKeys(const hid_keys_t& keys);
-
- // Spawn a thread to read key reports from the keyboard device.
- zx_status_t Start();
-
- zx_status_t HidEventLoop();
-
-private:
- // Sends an evdev key event.
- zx_status_t SendKeyEvent(uint32_t scancode, bool pressed);
-
- // Send an evdev barrier event to mark the end of a sequence of events.
- zx_status_t SendBarrierEvent();
-
- int fd_ = -1;
- hid_keys_t prev_keys_ = {};
- VirtioInputEventEmitter* emitter_;
-};
-
-/* Virtio input device. */
-class VirtioInput : public VirtioDevice, public VirtioInputEventEmitter {
-public:
- VirtioInput(uintptr_t guest_physmem_addr, size_t guest_physmem_size,
- const char* device_name, const char* device_serial);
-
- zx_status_t WriteConfig(uint64_t addr, const IoValue& value) override;
-
- virtio_queue_t& event_queue() { return queues_[VIRTIO_INPUT_Q_EVENTQ]; }
-
- // Spawns a thread to monitor for new input devices. When one is detected
- // the corresponding event source will be created to poll for events.
- zx_status_t Start();
-
- // VirtioInputEventEmitter interface.
- //
- // |QueueInputEvents| will write packets to the event queue, but no
- // interrupt will be generated to the guest until |FlushInputEvents| is
- // called.
- zx_status_t QueueInputEvent(const virtio_input_event_t& event) override;
- zx_status_t FlushInputEvents() override { return NotifyGuest(); }
-
- // Invoked when new devices are added.
- static zx_status_t AddInputDevice(int dirfd, int event, const char* fn, void* cookie);
-
-private:
- fbl::Mutex mutex_;
- const char* device_name_;
- const char* device_serial_;
- virtio_queue_t queues_[VIRTIO_INPUT_Q_COUNT];
- virtio_input_config_t config_ __TA_GUARDED(config_mutex_) = {};
-
- fbl::SinglyLinkedList<fbl::unique_ptr<KeyboardEventSource>> keyboards_ __TA_GUARDED(mutex_);
-};
diff --git a/system/ulib/machina/include/machina/pci.h b/system/ulib/machina/include/machina/pci.h
deleted file mode 100644
index 1d875f8..0000000
--- a/system/ulib/machina/include/machina/pci.h
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <fbl/mutex.h>
-#include <hypervisor/guest.h>
-#include <hypervisor/io.h>
-#include <machina/interrupt_controller.h>
-#include <zircon/compiler.h>
-#include <zircon/types.h>
-
-// clang-format off
-
-#define PCI_DEVICE_ROOT_COMPLEX 0u
-#define PCI_DEVICE_VIRTIO_BALLOON 1u
-#define PCI_DEVICE_VIRTIO_BLOCK 2u
-#define PCI_DEVICE_VIRTIO_GPU 3u
-#define PCI_DEVICE_VIRTIO_INPUT 4u
-#define PCI_DEVICE_INVALID UINT16_MAX
-#define PCI_MAX_DEVICES 5u
-#define PCI_MAX_BARS 2u
-
-// PCI configuration constants.
-#define PCI_BAR_ASPACE_MASK 0x0001u
-#define PCI_BAR_ASPACE_PIO 0x0001u
-#define PCI_BAR_ASPACE_MMIO 0x0000u
-#define PCI_VENDOR_ID_INTEL 0x8086u
-#define PCI_DEVICE_ID_INTEL_Q35 0x29c0u
-#define PCI_CLASS_BRIDGE_HOST 0x0600u
-#define PCI_CLASS_MASS_STORAGE 0x0100u
-
-// PCI type 1 address manipulation.
-#define PCI_TYPE1_BUS(addr) (((addr) >> 16) & 0xff)
-#define PCI_TYPE1_DEVICE(addr) (((addr) >> 11) & 0x1f)
-#define PCI_TYPE1_FUNCTION(addr) (((addr) >> 8) & 0x7)
-#define PCI_TYPE1_REGISTER_MASK 0xfc
-#define PCI_TYPE1_REGISTER(addr) ((addr)&PCI_TYPE1_REGISTER_MASK)
-
-// PCI ECAM address manipulation.
-#define PCI_ECAM_BUS(addr) (((addr) >> 20) & 0xff)
-#define PCI_ECAM_DEVICE(addr) (((addr) >> 15) & 0x1f)
-#define PCI_ECAM_FUNCTION(addr) (((addr) >> 12) & 0x7)
-#define PCI_ECAM_REGISTER(addr) ((addr)&0xfff)
-
-// clang-format on
-
-class Guest;
-class PciBus;
-class PciDevice;
-
-/* PCI capability structure.
- *
- * The 1-byte next pointer will be computed dynamically while traversing the
- * capabilities list.
- */
-typedef struct pci_cap {
- // PCI capability ID as defined in PCI LOCAL BUS SPECIFICATION, REV. 3.0
- // Appendix H.
- uint8_t id;
- // Data for this capability. Must be at least |len| bytes. The first
- // two bytes will be ignored (id and next) as these will be populated
- // dynamically. They're skipped over in the data pointer to allow common
- // structures to be used for read/write where the id/next pointers are
- // embedded in the structure.
- uint8_t* data;
- // Size of |data|.
- uint8_t len;
-} pci_cap_t;
-
-struct PciBar : public IoHandler {
- // Register value.
- uint32_t addr;
- // Size of this BAR.
- uint32_t size;
- // The type of trap to create for this region.
- TrapType trap_type;
-
- // Pointer to the owning device.
- PciDevice* device;
- // Bar number.
- uint8_t n;
-
- // IoHandler interface.
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-
- uint32_t aspace() const;
- uint32_t base() const;
-};
-
-/* Stores the state of PCI devices. */
-class PciDevice {
-public:
- // Static attributes associated with a device.
- struct Attributes {
- // Device attributes.
- uint16_t device_id;
- uint16_t vendor_id;
- uint16_t subsystem_id;
- uint16_t subsystem_vendor_id;
- // class, subclass, prog_if, and revision id.
- uint32_t device_class;
- };
-
- // Read from a region mapped by a BAR register.
- virtual zx_status_t ReadBar(uint8_t bar, uint64_t addr, IoValue* value) const {
- return ZX_ERR_NOT_SUPPORTED;
- }
-
- // Write to a region mapped by a BAR register.
- virtual zx_status_t WriteBar(uint8_t bar, uint64_t addr, const IoValue& value) {
- return ZX_ERR_NOT_SUPPORTED;
- }
-
- // Handle accesses to this devics config space.
- zx_status_t ReadConfig(uint64_t reg, IoValue* value) const;
- zx_status_t WriteConfig(uint64_t reg, const IoValue& value);
-
- // Send the configured interrupt for this device.
- zx_status_t Interrupt() const;
-
- // Determines if the given base address register is implemented for this
- // device.
- bool is_bar_implemented(size_t bar) const {
- return bar < PCI_MAX_BARS && bar_[bar].size > 0;
- }
-
- // Returns a pointer to a base address register for this device.
- //
- // Returns nullptr if the register is not implmeneted.
- const PciBar* bar(size_t n) const { return is_bar_implemented(n) ? &bar_[n] : nullptr; }
-
- // Install a capability list.
- void set_capabilities(const pci_cap_t* caps, size_t num_caps) {
- capabilities_ = caps;
- num_capabilities_ = num_caps;
- }
-
-protected:
- PciDevice(const Attributes attrs);
-
- // Base address registers.
- PciBar bar_[PCI_MAX_BARS] = {};
-
-private:
- friend class PciBus;
-
- // Setup traps and handlers for accesses to BAR regions.
- zx_status_t SetupBarTraps(Guest* guest);
-
- zx_status_t ReadConfigWord(uint8_t reg, uint32_t* value) const;
-
- zx_status_t ReadCapability(uint8_t addr, uint32_t* out) const;
-
- const pci_cap_t* FindCapability(uint8_t addr, uint8_t* cap_index, uint32_t* cap_base) const;
-
- mutable fbl::Mutex mutex_;
-
- // Static attributes for this device.
- const Attributes attrs_;
- // Command register.
- uint16_t command_ __TA_GUARDED(mutex_) = 0;
- // Array of capabilities for this device.
- const pci_cap_t* capabilities_ = nullptr;
- // Size of |capabilities|.
- size_t num_capabilities_ = 0;
- // PCI bus this device is connected to.
- PciBus* bus_ = nullptr;
- // IRQ vector assigned by the bus.
- uint32_t global_irq_ = 0;
-};
-
-class PciPortHandler : public IoHandler {
-public:
- PciPortHandler(PciBus* bus);
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-
-private:
- PciBus* bus_;
-};
-
-class PciEcamHandler : public IoHandler {
-public:
- PciEcamHandler(PciBus* bus);
- zx_status_t Read(uint64_t addr, IoValue* value) const override;
- zx_status_t Write(uint64_t addr, const IoValue& value) override;
-
-private:
- PciBus* bus_;
-};
-
-class PciBus {
-public:
- // Base address in PIO space to map device BAR registers.
- static const uint32_t kPioBarBase = 0x8000;
-
- // Base address in MMIO space to map device BAR registers.
- static const uint32_t kMmioBarBase = 0xf0000000;
-
- PciBus(Guest* guest, const InterruptController* interrupt_controller);
-
- zx_status_t Init();
-
- // Connect a PCI device to the bus.
- //
- // |slot| must be between 1 and PCI_MAX_DEVICES (slot 0 is reserved for
- // the root complex).
- //
- // This method is *not* thread-safe and must only be called during
- // initialization.
- zx_status_t Connect(PciDevice* device, uint8_t slot) __TA_NO_THREAD_SAFETY_ANALYSIS;
-
- // Access devices via the ECAM region.
- //
- // |addr| is the offset from the start of the ECAM region for this bus.
- zx_status_t ReadEcam(uint64_t addr, IoValue* value) const;
- zx_status_t WriteEcam(uint64_t addr, const IoValue& value);
-
- // Handle access to the PC IO ports (0xcf8 - 0xcff).
- zx_status_t ReadIoPort(uint64_t port, IoValue* value) const;
- zx_status_t WriteIoPort(uint64_t port, const IoValue& value);
-
- // Raise an interrupt for the given device.
- zx_status_t Interrupt(const PciDevice& device) const;
-
- // Returns true if |bus|, |device|, |function| corresponds to a valid
- // device address.
- bool is_addr_valid(uint8_t bus, uint8_t device, uint8_t function) const {
- return bus == 0 && device < PCI_MAX_DEVICES && function == 0 && device_[device];
- }
-
- // Current config address seleceted by the 0xcf8 IO port.
- uint32_t config_addr();
- void set_config_addr(uint32_t addr);
-
- PciDevice& root_complex() { return root_complex_; }
-
-private:
- mutable fbl::Mutex mutex_;
-
- Guest* guest_;
- PciEcamHandler ecam_handler_;
- PciPortHandler port_handler_;
-
- // Selected address in PCI config space.
- uint32_t config_addr_ __TA_GUARDED(mutex_) = 0;
-
- // Devices on the virtual PCI bus.
- PciDevice* device_[PCI_MAX_DEVICES] = {};
- // IO APIC for use with interrupt redirects.
- const InterruptController* interrupt_controller_ = nullptr;
- // Embedded root complex device.
- PciDevice root_complex_;
- // Next pio window to be allocated to connected devices.
- uint32_t pio_base_ = kPioBarBase;
- // Next mmio window to be allocated to connected devices.
- uint32_t mmio_base_ = kMmioBarBase;
-};
diff --git a/system/ulib/machina/include/machina/virtio.h b/system/ulib/machina/include/machina/virtio.h
deleted file mode 100644
index 6cbfb3e..0000000
--- a/system/ulib/machina/include/machina/virtio.h
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <fbl/auto_lock.h>
-#include <fbl/mutex.h>
-#include <machina/virtio_pci.h>
-#include <virtio/virtio.h>
-#include <zircon/compiler.h>
-#include <zircon/types.h>
-
-struct vring_desc;
-struct vring_avail;
-struct vring_used;
-
-class VirtioDevice;
-
-typedef struct virtio_queue virtio_queue_t;
-
-/* Base class for all virtio devices. */
-class VirtioDevice {
-public:
- virtual ~VirtioDevice() = default;
-
- // Read a device-specific configuration field.
- virtual zx_status_t ReadConfig(uint64_t addr, IoValue* value);
-
- // Write a device-specific configuration field.
- virtual zx_status_t WriteConfig(uint64_t addr, const IoValue& value);
-
- // Handle notify events for one of this devices queues.
- virtual zx_status_t HandleQueueNotify(uint16_t queue_sel) {
- return ZX_OK;
- }
-
- // Send a notification back to the guest that there are new descriptors in
- // then used ring.
- //
- // The method for how this notification is delievered is transport
- // specific.
- zx_status_t NotifyGuest();
-
- uintptr_t guest_physmem_addr() { return guest_physmem_addr_; }
- size_t guest_physmem_size() { return guest_physmem_size_; }
-
- uint16_t num_queues() const { return num_queues_; }
-
- // ISR flag values.
- enum IsrFlags : uint8_t {
- // Interrupt is caused by a queue.
- VIRTIO_ISR_QUEUE = 0x1,
- // Interrupt is caused by a device config change.
- VIRTIO_ISR_DEVICE = 0x2,
- };
-
- // Sets the given flags in the ISR register.
- void add_isr_flags(uint8_t flags) {
- fbl::AutoLock lock(&mutex_);
- isr_status_ |= flags;
- }
-
- // Device features.
- //
- // These are feature bits that are supported by the device. They may or
- // may not correspond to the set of feature flags that have been negotiated
- // at runtime.
- void add_device_features(uint32_t features) {
- fbl::AutoLock lock(&mutex_);
- features_ |= features;
- }
- bool has_device_features(uint32_t features) {
- fbl::AutoLock lock(&mutex_);
- return (features_ & features) == features;
- }
-
- PciDevice& pci_device() { return pci_; }
-
-protected:
- VirtioDevice(uint8_t device_id, void* config, size_t config_size, virtio_queue_t* queues,
- uint16_t num_queues, uintptr_t guest_physmem_addr, size_t guest_physmem_size);
-
- // Mutex for accessing device configuration fields.
- fbl::Mutex config_mutex_;
-
-private:
- // Temporarily expose our state to the PCI transport until the proper
- // accessor methods are defined.
- friend class VirtioPci;
-
- fbl::Mutex mutex_;
-
- // Handle kicks from the driver that a queue needs attention.
- zx_status_t Kick(uint16_t queue_sel);
-
- // Device feature bits.
- //
- // Defined in Virtio 1.0 Section 2.2.
- uint32_t features_ __TA_GUARDED(mutex_) = 0;
- uint32_t features_sel_ __TA_GUARDED(mutex_) = 0;
-
- // Driver feature bits.
- uint32_t driver_features_ __TA_GUARDED(mutex_) = 0;
- uint32_t driver_features_sel_ __TA_GUARDED(mutex_) = 0;
-
- // Virtio device id.
- const uint8_t device_id_;
-
- // Device status field as defined in Virtio 1.0, Section 2.1.
- uint8_t status_ __TA_GUARDED(mutex_) = 0;
-
- // Interrupt status register.
- uint8_t isr_status_ __TA_GUARDED(mutex_) = 0;
-
- // Index of the queue currently selected by the driver.
- uint16_t queue_sel_ __TA_GUARDED(mutex_) = 0;
-
- // Pointer to the structure that holds this devices configuration
- // structure.
- void* const device_config_ __TA_GUARDED(config_mutex_) = nullptr;
-
- // Number of bytes used for this devices configuration space.
- //
- // This should cover only bytes used for the device-specific portions of
- // the configuration header, omitting any of the (transport-specific)
- // shared configuration space.
- const size_t device_config_size_ = 0;
-
- // Size of queues array.
- const uint16_t num_queues_ = 0;
-
- // Virtqueues for this device.
- virtio_queue_t* const queues_ = nullptr;
-
- // Address of guest physical memory.
- const uintptr_t guest_physmem_addr_ = 0;
- // Size of guest physical memory.
- const size_t guest_physmem_size_ = 0;
-
- // Virtio PCI transport.
- VirtioPci pci_;
-};
-
-/* Stores the Virtio queue based on the ring provided by the guest.
- *
- * NOTE(abdulla): This structure points to guest-controlled memory.
- */
-typedef struct virtio_queue {
- mtx_t mutex;
- // Allow threads to block on buffers in the avail ring.
- cnd_t avail_ring_cnd;
-
- // Queue addresses as defined in Virtio 1.0 Section 4.1.4.3.
- union {
- struct {
- uint64_t desc;
- uint64_t avail;
- uint64_t used;
- };
-
- // Software will access these using 32 bit operations. Provide a
- // convenience interface for these use cases.
- uint32_t words[6];
- } addr;
-
- // Number of entries in the descriptor table.
- uint16_t size;
- uint16_t index;
-
- // Pointer to the owning device.
- VirtioDevice* virtio_device;
-
- volatile struct vring_desc* desc; // guest-controlled
-
- volatile struct vring_avail* avail; // guest-controlled
- volatile uint16_t* used_event; // guest-controlled
-
- volatile struct vring_used* used; // guest-controlled
- volatile uint16_t* avail_event; // guest-controlled
-} virtio_queue_t;
-
-/* Callback function for virtio_queue_handler.
- *
- * For chained buffers uing VRING_DESC_F_NEXT, this function will be called once for each buffer
- * in the chain.
- *
- * addr - Pointer to the descriptor buffer.
- * len - Length of the descriptor buffer.
- * flags - Flags from the vring descriptor.
- * used - To be incremented by the number of bytes used from addr.
- * ctx - The same pointer passed to virtio_queue_handler.
- */
-typedef zx_status_t (*virtio_queue_fn_t)(void* addr, uint32_t len, uint16_t flags, uint32_t* used,
- void* ctx);
-
-/* Handles the next available descriptor in a Virtio queue, calling handler to
- * process individual payload buffers.
- *
- * On success the function either returns ZX_OK if there are no more descriptors
- * available, or ZX_ERR_NEXT if there are more available descriptors to process.
- */
-zx_status_t virtio_queue_handler(virtio_queue_t* queue, virtio_queue_fn_t handler, void* ctx);
-
-/* Get the index of the next descriptor in the available ring.
- *
- * If a buffer is a available, the descriptor index is written to |index|, the
- * queue index pointer is incremented, and ZX_OK is returned.
- *
- * If no buffers are available ZX_ERR_NOT_FOUND is returned.
- */
-zx_status_t virtio_queue_next_avail(virtio_queue_t* queue, uint16_t* index);
-
-/* Blocking variant of virtio_queue_next_avail. */
-void virtio_queue_wait(virtio_queue_t* queue, uint16_t* index);
-
-/* Notify waiting threads blocked on |virtio_queue_wait| that the avail ring
- * has descriptors available. */
-void virtio_queue_signal(virtio_queue_t* queue);
-
-/* Sets the address of the descriptor table for this queue. */
-void virtio_queue_set_desc_addr(virtio_queue_t* queue, uint64_t desc_addr);
-
-/* Sets the address of the available ring for this queue. */
-void virtio_queue_set_avail_addr(virtio_queue_t* queue, uint64_t avail_addr);
-
-/* Sets the address of the used ring for this queue. */
-void virtio_queue_set_used_addr(virtio_queue_t* queue, uint64_t used_addr);
-
-/* Callback for virtio_queue_poll.
- *
- * queue - The queue being polled.
- * head - Descriptor index of the buffer chain to process.
- * used - To be incremented by the number of bytes used from addr.
- * ctx - The same pointer passed to virtio_queue_poll.
- *
- * The queue will continue to be polled as long as this method returns ZX_OK.
- * The error ZX_ERR_STOP will be treated as a special value to indicate queue
- * polling should stop gracefully and terminate the thread.
- *
- * Any other error values will be treated as unexpected errors that will cause
- * the polling thread to be terminated with a non-zero exit value.
- */
-typedef zx_status_t (*virtio_queue_poll_fn_t)(virtio_queue_t* queue, uint16_t head,
- uint32_t* used, void* ctx);
-
-/* Spawn a thread to wait for descriptors to be available and invoke the
- * provided handler on each available buffer asyncronously.
- */
-zx_status_t virtio_queue_poll(virtio_queue_t* queue, virtio_queue_poll_fn_t handler, void* ctx);
-
-/* A higher-level API for vring_desc. */
-typedef struct virtio_desc {
- // Pointer to the buffer in our address space.
- void* addr;
- // Number of bytes at addr.
- uint32_t len;
- // Is there another buffer after this one?
- bool has_next;
- // Only valid if has_next is true.
- uint16_t next;
- // If true, this buffer must only be written to (no reads). Otherwise this
- // buffer must only be read from (no writes).
- bool writable;
-} virtio_desc_t;
-
-/* Reads a single descriptor from the queue.
- *
- * This method should only be called using descriptor indicies acquired with
- * virtio_queue_next_avail (including any chained decriptors) and before
- * they've been released with virtio_queue_return.
- */
-zx_status_t virtio_queue_read_desc(virtio_queue_t* queue, uint16_t index, virtio_desc_t* desc);
-
-/* Return a descriptor to the used ring.
- *
- * |index| must be a value received from a call to virtio_queue_next_avail. Any
- * buffers accessed via |index| or any chained descriptors must not be used
- * after calling virtio_queue_return.
- */
-void virtio_queue_return(virtio_queue_t* queue, uint16_t index, uint32_t len);
diff --git a/system/ulib/machina/include/machina/virtio_pci.h b/system/ulib/machina/include/machina/virtio_pci.h
deleted file mode 100644
index af09866..0000000
--- a/system/ulib/machina/include/machina/virtio_pci.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <machina/pci.h>
-#include <virtio/virtio.h>
-#include <zircon/types.h>
-
-class VirtioDevice;
-
-typedef struct virtio_queue virtio_queue_t;
-
-static const size_t kVirtioPciNumCapabilities = 4;
-
-/* Virtio PCI transport implementation. */
-class VirtioPci : public PciDevice {
-public:
- VirtioPci(VirtioDevice* device);
-
- // Read a value at |bar| and |offset| from this device.
- zx_status_t ReadBar(uint8_t bar, uint64_t offset, IoValue* value) const override;
- // Write a value at |bar| and |offset| to this device.
- zx_status_t WriteBar(uint8_t bar, uint64_t offset, const IoValue& value) override;
-
-private:
- // Handle accesses to the general configuration BAR.
- zx_status_t ConfigBarRead(uint64_t addr, IoValue* value) const;
- zx_status_t ConfigBarWrite(uint64_t addr, const IoValue& value);
-
- // Handle accesses to the common configuration region.
- zx_status_t CommonCfgRead(uint64_t addr, IoValue* value) const;
- zx_status_t CommonCfgWrite(uint64_t addr, const IoValue& value);
-
- // Handle writes to the notify BAR.
- zx_status_t NotifyBarWrite(uint64_t addr, const IoValue& value);
-
- void SetupCaps();
- void SetupCap(pci_cap_t* cap, virtio_pci_cap_t* virtio_cap, uint8_t cfg_type,
- size_t cap_len, size_t data_length, uint8_t bar, size_t bar_offset);
-
- virtio_queue_t* selected_queue() const;
-
- // We need one of these for every virtio_pci_cap_t structure we expose.
- pci_cap_t capabilities_[kVirtioPciNumCapabilities];
- // Virtio PCI capabilities.
- virtio_pci_cap_t common_cfg_cap_;
- virtio_pci_cap_t device_cfg_cap_;
- virtio_pci_notify_cap_t notify_cfg_cap_;
- virtio_pci_cap_t isr_cfg_cap_;
-
- VirtioDevice* device_;
-};
diff --git a/system/ulib/machina/input.cpp b/system/ulib/machina/input.cpp
deleted file mode 100644
index c55498d..0000000
--- a/system/ulib/machina/input.cpp
+++ /dev/null
@@ -1,401 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/input.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <fbl/alloc_checker.h>
-#include <fbl/auto_call.h>
-#include <fbl/auto_lock.h>
-#include <fdio/watcher.h>
-#include <hypervisor/bits.h>
-#include <virtio/virtio_ids.h>
-
-static const char* kInputDirPath = "/dev/class/input";
-
-// HID keycode -> evdev keycode.
-const uint8_t KeyboardEventSource::kKeyMap[] = {
- 0, // Reserved
- 0, // Keyboard ErrorRollOver
- 0, // Keyboard POSTFail
- 0, // Keyboard ErrorUndefined
- 30, // A
- 48, // B
- 46, // C
- 32, // D
- 18, // E
- 33, // F
- 34, // G
- 35, // H
- 23, // I
- 36, // J
- 37, // K
- 38, // L
- 50, // M
- 49, // N
- 24, // O
- 25, // P
- 16, // Q
- 19, // R
- 31, // S
- 20, // T
- 22, // U
- 47, // V
- 17, // W
- 45, // X
- 21, // Y
- 44, // Z
- 2, // 1
- 3, // 2
- 4, // 3
- 5, // 4
- 6, // 5
- 7, // 6
- 8, // 7
- 9, // 8
- 10, // 9
- 11, // 0
- 28, // Enter
- 1, // Esc
- 14, // Backspace
- 15, // Tab
- 57, // Space
- 12, // -
- 13, // =
- 26, // [
- 27, // ]
- 43, // Backslash
- 43, // Non-US # and ~
- 39, // ;
- 40, // '
- 41, // `
- 51, // ,
- 52, // .
- 53, // /
- 58, // Caps Lock
- 59, // F1
- 60, // F2
- 61, // F3
- 62, // F4
- 63, // F5
- 64, // F6
- 65, // F7
- 66, // F8
- 67, // F9
- 68, // F10
- 87, // F11
- 88, // F12
- 99, // Print Screen
- 70, // ScrollLock
- 119, // Pause
- 110, // Insert
- 102, // Home
- 104, // PageUp
- 111, // Delete Forward
- 107, // End
- 109, // PageDown
- 106, // Right
- 105, // Left
- 108, // Down
- 103, // Up
- 69, // NumLock
- 98, // Keypad /
- 55, // Keypad *
- 74, // Keypad -
- 78, // Keypad +
- 96, // Keypad Enter
- 79, // Keypad 1
- 80, // Keypad 2
- 81, // Keypad 3
- 75, // Keypad 4
- 76, // Keypad 5
- 77, // Keypad 6
- 71, // Keypad 7
- 72, // Keypad 8
- 73, // Keypad 9
- 82, // Keypad 0
- 83, // Keypad .
- 86, // Non-US \ and |
- 127, // Keyboard Application
- 116, // Power
- 117, // Keypad =
- 183, // F13
- 184, // F14
- 185, // F15
- 186, // F16
- 187, // F17
- 188, // F18
- 189, // F19
- 190, // F20
- 191, // F21
- 192, // F22
- 193, // F23
- 194, // F24
- 134, // Execute
- 138, // Help
- 130, // Menu
- 132, // Select
- 128, // Stop
- 129, // Again
- 131, // Undo
- 137, // Cut
- 133, // Copy
- 135, // Paste
- 136, // Find
- 113, // Mute
- 115, // Volume Up
- 114, // Volume Down
-
- // Skip some more esoteric keys that have no obvious evdev counterparts.
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 29, // Left Ctrl
- 42, // Left Shift
- 56, // Left Alt
- 125, // Left Meta
- 97, // Right Ctrl
- 54, // Right Shift
- 100, // Right Alt
- 126, // Right Meta
-};
-
-VirtioInput::VirtioInput(uintptr_t guest_physmem_addr, size_t guest_physmem_size,
- const char* device_name, const char* device_serial)
- : VirtioDevice(VIRTIO_ID_INPUT, &config_, sizeof(config_), queues_, VIRTIO_INPUT_Q_COUNT,
- guest_physmem_addr, guest_physmem_size),
- device_name_(device_name), device_serial_(device_serial) {}
-
-zx_status_t VirtioInput::WriteConfig(uint64_t addr, const IoValue& value) {
- zx_status_t status = VirtioDevice::WriteConfig(addr, value);
- if (status != ZX_OK)
- return status;
- if (addr >= 2)
- return ZX_OK;
-
- // A write to select or subselect modifies the contents of the config.u
- // field.
- fbl::AutoLock lock(&config_mutex_);
- switch (config_.select) {
- case VIRTIO_INPUT_CFG_ID_NAME: {
- size_t len = strlen(device_name_);
- memcpy(&config_.u, device_name_, len);
- config_.size = static_cast<uint8_t>(len > sizeof(config_.u) ? sizeof(config_.u) : len);
- return ZX_OK;
- }
- case VIRTIO_INPUT_CFG_ID_SERIAL: {
- size_t len = strlen(device_serial_);
- config_.size = static_cast<uint8_t>(len > sizeof(config_.u) ? sizeof(config_.u) : len);
- memcpy(&config_.u, device_serial_, len);
- return ZX_OK;
- }
-
- // VIRTIO_INPUT_CFG_EV_BITS: subsel specifies the event type (EV_*).
- // If size is non-zero the event type is supported and a bitmap the of
- // supported event codes is returned in u.bitmap.
- case VIRTIO_INPUT_CFG_EV_BITS: {
- if (config_.subsel == VIRTIO_INPUT_EV_KEY) {
- // Say we support all key events. This isn't true but it's
- // simple.
- memset(&config_.u, 0xff, sizeof(config_.u));
- config_.size = sizeof(config_.u);
- return ZX_OK;
- }
- // Fall-through.
- }
- case VIRTIO_INPUT_CFG_UNSET:
- case VIRTIO_INPUT_CFG_ID_DEVIDS:
- case VIRTIO_INPUT_CFG_PROP_BITS:
- case VIRTIO_INPUT_CFG_ABS_INFO:
- memset(&config_.u, 0, sizeof(config_.u));
- config_.size = 0;
- return ZX_OK;
- default:
- fprintf(stderr, "unsupported select value %u\n", config_.select);
- return ZX_ERR_NOT_SUPPORTED;
- }
- return ZX_OK;
-}
-
-static int watch_input_directory_thread(void* input) {
- int dirfd = open(kInputDirPath, O_DIRECTORY | O_RDONLY);
- if (dirfd < 0)
- return ZX_ERR_IO;
-
- zx_status_t status = fdio_watch_directory(dirfd, &VirtioInput::AddInputDevice,
- ZX_TIME_INFINITE, input);
-
- close(dirfd);
- return status;
-}
-
-zx_status_t VirtioInput::Start() {
- thrd_t thread;
- int ret = thrd_create(&thread, &watch_input_directory_thread, this);
- if (ret != thrd_success) {
- return ZX_ERR_INTERNAL;
- }
- ret = thrd_detach(thread);
- if (ret != thrd_success) {
- return ZX_ERR_INTERNAL;
- }
- return ZX_OK;
-}
-
-zx_status_t VirtioInput::QueueInputEvent(const virtio_input_event_t& event) {
- uint16_t head;
- virtio_queue_wait(&event_queue(), &head);
-
- virtio_desc_t desc;
- zx_status_t status = virtio_queue_read_desc(&event_queue(), head, &desc);
- if (status != ZX_OK)
- return status;
-
- auto event_out = static_cast<virtio_input_event_t*>(desc.addr);
- memcpy(event_out, &event, sizeof(event));
- virtio_queue_return(&event_queue(), head, sizeof(event));
- return ZX_OK;
-}
-
-// static
-zx_status_t VirtioInput::AddInputDevice(int dirfd, int event, const char* fn, void* cookie) {
- auto input = static_cast<VirtioInput*>(cookie);
- if (event != WATCH_EVENT_ADD_FILE) {
- return ZX_OK;
- }
-
- int fd = openat(dirfd, fn, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "Failed to open device %s/%s\n", kInputDirPath, fn);
- return ZX_OK;
- }
-
- auto closer = fbl::MakeAutoCall([fd]() { close(fd); });
-
- int proto = INPUT_PROTO_NONE;
- if (ioctl_input_get_protocol(fd, &proto) < 0) {
- fprintf(stderr, "Failed to get input device protocol.\n");
- return ZX_ERR_INVALID_ARGS;
- }
-
- // If the device isn't a keyboard, just continue.
- if (proto != INPUT_PROTO_KBD)
- return ZX_OK;
-
- fbl::AllocChecker ac;
- auto keyboard = fbl::make_unique_checked<KeyboardEventSource>(&ac, input, fd);
- if (!ac.check())
- return ZX_ERR_NO_MEMORY;
-
- zx_status_t status = keyboard->Start();
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to start device %s/%s\n", kInputDirPath, fn);
- return status;
- }
- fprintf(stderr, "virtio-input: Polling device %s/%s for key events.\n", kInputDirPath, fn);
-
- closer.cancel();
- fbl::AutoLock lock(&input->mutex_);
- input->keyboards_.push_front(fbl::move(keyboard));
- return ZX_OK;
-}
-
-KeyboardEventSource::~KeyboardEventSource() {
- if (fd_ >= 0)
- close(fd_);
-}
-
-static int hid_event_thread(void* cookie) {
- return reinterpret_cast<KeyboardEventSource*>(cookie)->HidEventLoop();
-}
-
-zx_status_t KeyboardEventSource::Start() {
- thrd_t thread;
- int ret = thrd_create(&thread, &hid_event_thread, this);
- if (ret != thrd_success) {
- return ZX_ERR_INTERNAL;
- }
- ret = thrd_detach(thread);
- if (ret != thrd_success) {
- return ZX_ERR_INTERNAL;
- }
- return ZX_OK;
-}
-
-zx_status_t KeyboardEventSource::HidEventLoop() {
- uint8_t report[8];
- while (true) {
- ssize_t r = read(fd_, report, sizeof(report));
- if (r != sizeof(report)) {
- fprintf(stderr, "failed to read from input device\n");
- return ZX_ERR_IO;
- }
-
- hid_keys_t curr_keys;
- hid_kbd_parse_report(report, &curr_keys);
-
- zx_status_t status = HandleHidKeys(curr_keys);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to handle HID keys.\n");
- return status;
- }
- }
- return ZX_OK;
-}
-
-zx_status_t KeyboardEventSource::HandleHidKeys(const hid_keys_t& curr_keys) {
- // Send key-down events.
- uint8_t keycode;
- hid_keys_t pressed;
- hid_kbd_pressed_keys(&prev_keys_, &curr_keys, &pressed);
- hid_for_every_key(&pressed, keycode) {
- zx_status_t status = SendKeyEvent(keycode, true);
- if (status != ZX_OK)
- return status;
- }
-
- // Send key-up events.
- hid_keys_t released;
- hid_kbd_released_keys(&prev_keys_, &curr_keys, &released);
- hid_for_every_key(&released, keycode) {
- zx_status_t status = SendKeyEvent(keycode, false);
- if (status != ZX_OK)
- return status;
- }
-
- prev_keys_ = curr_keys;
- return SendBarrierEvent();
-}
-
-zx_status_t KeyboardEventSource::SendKeyEvent(uint32_t scancode, bool pressed) {
- if (scancode >= sizeof(kKeyMap) / sizeof(kKeyMap[0])) {
- // Unknown key.
- return ZX_OK;
- }
-
- virtio_input_event_t event;
- event.type = VIRTIO_INPUT_EV_KEY;
- event.code = kKeyMap[scancode];
- event.value = pressed ? VIRTIO_INPUT_EV_KEY_PRESSED : VIRTIO_INPUT_EV_KEY_RELEASED;
- return emitter_->QueueInputEvent(event);
-}
-
-zx_status_t KeyboardEventSource::SendBarrierEvent() {
- virtio_input_event_t event;
- event.type = VIRTIO_INPUT_EV_SYN;
- event.code = 0;
- event.value = 0;
- zx_status_t status = emitter_->QueueInputEvent(event);
- if (status != ZX_OK)
- return status;
- return emitter_->FlushInputEvents();
-}
diff --git a/system/ulib/machina/pci.cpp b/system/ulib/machina/pci.cpp
deleted file mode 100644
index 67a496d..0000000
--- a/system/ulib/machina/pci.cpp
+++ /dev/null
@@ -1,551 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/pci.h>
-
-#include <stdio.h>
-
-#include <fbl/auto_lock.h>
-#include <hw/pci.h>
-#include <hypervisor/address.h>
-#include <hypervisor/bits.h>
-#include <machina/interrupt_controller.h>
-
-// PCI BAR register addresses.
-#define PCI_REGISTER_BAR_0 0x10
-#define PCI_REGISTER_BAR_1 0x14
-#define PCI_REGISTER_BAR_2 0x18
-#define PCI_REGISTER_BAR_3 0x1c
-#define PCI_REGISTER_BAR_4 0x20
-#define PCI_REGISTER_BAR_5 0x24
-
-// PCI Capabilities registers.
-#define PCI_REGISTER_CAP_BASE 0xa4
-#define PCI_REGISTER_CAP_TOP UINT8_MAX
-
-/* PCI config relative IO port addresses (typically at 0xcf8). */
-constexpr uint16_t kPciConfigAddressPortBase = 0;
-constexpr uint16_t kPciConfigAddressPortTop = 3;
-constexpr uint16_t kPciConfigDataPortBase = 4;
-constexpr uint16_t kPciConfigDataPortTop = 7;
-
-constexpr uint32_t kPioAddressMask = ~bit_mask<uint32_t>(2);
-constexpr uint32_t kMmioAddressMask = ~bit_mask<uint32_t>(4);
-
-// PCI capabilities register layout.
-constexpr uint8_t kPciCapTypeOffset = 0;
-constexpr uint8_t kPciCapNextOffset = 1;
-
-/* Per-device IRQ assignments.
- *
- * These are provided to the guest via the _SB section in the DSDT ACPI table.
- *
- * The DSDT defines interrupts for 5 devices (IRQ 32-36). Adding
- * additional devices beyond that will require updates to the DSDT.
- */
-constexpr uint32_t kPciGlobalIrqAssigments[PCI_MAX_DEVICES] = {32, 33, 34, 35, 36};
-
-uint32_t PciBar::aspace() const {
- switch (trap_type) {
- case TrapType::PIO_SYNC:
- case TrapType::PIO_ASYNC:
- return PCI_BAR_ASPACE_PIO;
- case TrapType::MMIO_SYNC:
- case TrapType::MMIO_BELL:
- return PCI_BAR_ASPACE_MMIO;
- default:
- return 0;
- }
-}
-
-uint32_t PciBar::base() const {
- switch (aspace()) {
- case PCI_BAR_ASPACE_PIO:
- return addr & kPioAddressMask;
- case PCI_BAR_ASPACE_MMIO:
- return addr & kMmioAddressMask;
- default:
- return 0;
- }
-}
-
-zx_status_t PciBar::Read(uint64_t addr, IoValue* value) const {
- if (device == nullptr)
- return ZX_ERR_BAD_STATE;
- return device->ReadBar(n, addr, value);
-}
-
-zx_status_t PciBar::Write(uint64_t addr, const IoValue& value) {
- if (device == nullptr)
- return ZX_ERR_BAD_STATE;
- return device->WriteBar(n, addr, value);
-}
-
-static const PciDevice::Attributes kRootComplexAttributes = {
- .device_id = PCI_DEVICE_ID_INTEL_Q35,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .subsystem_id = 0,
- .subsystem_vendor_id = 0,
- .device_class = (PCI_CLASS_BRIDGE_HOST << 16),
-};
-
-PciDevice::PciDevice(const Attributes attrs)
- : attrs_(attrs) {}
-
-PciPortHandler::PciPortHandler(PciBus* bus)
- : bus_(bus) {}
-
-zx_status_t PciPortHandler::Read(uint64_t addr, IoValue* value) const {
- return bus_->ReadIoPort(addr, value);
-}
-
-zx_status_t PciPortHandler::Write(uint64_t addr, const IoValue& value) {
- return bus_->WriteIoPort(addr, value);
-}
-
-PciEcamHandler::PciEcamHandler(PciBus* bus)
- : bus_(bus) {}
-
-zx_status_t PciEcamHandler::Read(uint64_t addr, IoValue* value) const {
- return bus_->ReadEcam(addr, value);
-}
-
-zx_status_t PciEcamHandler::Write(uint64_t addr, const IoValue& value) {
- return bus_->WriteEcam(addr, value);
-}
-
-PciBus::PciBus(Guest* guest, const InterruptController* interrupt_controller)
- : guest_(guest), ecam_handler_(this), port_handler_(this),
- interrupt_controller_(interrupt_controller), root_complex_(kRootComplexAttributes) {}
-
-zx_status_t PciBus::Init() {
- root_complex_.bar_[0].size = 0x10;
- root_complex_.bar_[0].trap_type = TrapType::MMIO_SYNC;
- zx_status_t status = Connect(&root_complex_, PCI_DEVICE_ROOT_COMPLEX);
- if (status != ZX_OK)
- return status;
-
- // Setup ECAM trap for a single bus.
- status = guest_->CreateMapping(TrapType::MMIO_SYNC, PCI_ECAM_PHYS_BASE, PCI_ECAM_SIZE(0, 1),
- 0, &ecam_handler_);
- if (status != ZX_OK)
- return status;
-
-#if __x86_64__
- // Setup PIO trap.
- status = guest_->CreateMapping(TrapType::PIO_SYNC, PCI_CONFIG_PORT_BASE, PCI_CONFIG_PORT_SIZE,
- 0, &port_handler_);
- if (status != ZX_OK)
- return status;
-#endif
-
- return ZX_OK;
-}
-
-uint32_t PciBus::config_addr() {
- fbl::AutoLock lock(&mutex_);
- return config_addr_;
-}
-
-void PciBus::set_config_addr(uint32_t addr) {
- fbl::AutoLock lock(&mutex_);
- config_addr_ = addr;
-}
-
-zx_status_t PciBus::Connect(PciDevice* device, uint8_t slot) {
- if (slot >= PCI_MAX_DEVICES)
- return ZX_ERR_OUT_OF_RANGE;
- if (device_[slot])
- return ZX_ERR_ALREADY_EXISTS;
-
- // Initialize BAR registers.
- for (uint8_t bar_num = 0; bar_num < PCI_MAX_BARS; ++bar_num) {
- PciBar* bar = &device->bar_[bar_num];
-
- // Skip unimplemented bars.
- if (!device->is_bar_implemented(bar_num))
- break;
-
- device->bus_ = this;
- if (device->bar_[bar_num].aspace() == PCI_BAR_ASPACE_PIO) {
- // PCI LOCAL BUS SPECIFICATION, REV. 3.0 Section 6.2.5.1
- //
- // This design implies that all address spaces used are a power of two in
- // size and are naturally aligned.
- bar->size = round_up_pow2(bar->size);
- bar->addr = align(pio_base_, bar->size);
- pio_base_ = bar->addr + bar->size;
- } else {
- bar->size = static_cast<uint16_t>(align(bar->size, PAGE_SIZE));
- bar->addr = mmio_base_;
- mmio_base_ += bar->size;
- }
- }
-
- device->command_ = PCI_COMMAND_IO_EN | PCI_COMMAND_MEM_EN;
- device->global_irq_ = kPciGlobalIrqAssigments[slot];
- device_[slot] = device;
-
- return device->SetupBarTraps(guest_);
-}
-
-// PCI LOCAL BUS SPECIFICATION, REV. 3.0 Section 6.1: All PCI devices must
-// treat Configuration Space write operations to reserved registers as no-ops;
-// that is, the access must be completed normally on the bus and the data
-// discarded.
-static inline zx_status_t pci_write_unimplemented_register() {
- return ZX_OK;
-}
-
-static inline zx_status_t pci_write_unimplemented_device() {
- return ZX_OK;
-}
-
-// PCI LOCAL BUS SPECIFICATION, REV. 3.0 Section 6.1: Read accesses to reserved
-// or unimplemented registers must be completed normally and a data value of 0
-// returned.
-static inline zx_status_t pci_read_unimplemented_register(uint32_t* value) {
- *value = 0;
- return ZX_OK;
-}
-
-// PCI LOCAL BUS SPECIFICATION, REV. 3.0 Section 6.1: The host bus to PCI bridge
-// must unambiguously report attempts to read the Vendor ID of non-existent
-// devices. Since 0 FFFFh is an invalid Vendor ID, it is adequate for the host
-// bus to PCI bridge to return a value of all 1's on read accesses to
-// Configuration Space registers of non-existent devices.
-static inline zx_status_t pci_read_unimplemented_device(IoValue* value) {
- value->u32 = bit_mask<uint32_t>(value->access_size * 8);
- return ZX_OK;
-}
-
-zx_status_t PciBus::ReadEcam(uint64_t addr, IoValue* value) const {
- const uint8_t device = PCI_ECAM_DEVICE(addr);
- const uint16_t reg = PCI_ECAM_REGISTER(addr);
- const bool valid = is_addr_valid(PCI_ECAM_BUS(addr), device, PCI_ECAM_FUNCTION(addr));
- if (!valid) {
- return pci_read_unimplemented_device(value);
- }
-
- return device_[device]->ReadConfig(reg, value);
-}
-
-zx_status_t PciBus::WriteEcam(uint64_t addr, const IoValue& value) {
- const uint8_t device = PCI_ECAM_DEVICE(addr);
- const uint16_t reg = PCI_ECAM_REGISTER(addr);
- const bool valid = is_addr_valid(PCI_ECAM_BUS(addr), device, PCI_ECAM_FUNCTION(addr));
- if (!valid) {
- return pci_write_unimplemented_device();
- }
-
- return device_[device]->WriteConfig(reg, value);
-}
-
-zx_status_t PciBus::ReadIoPort(uint64_t port, IoValue* value) const {
- switch (port) {
- case kPciConfigAddressPortBase... kPciConfigAddressPortTop: {
- uint64_t bit_offset = (port - kPciConfigAddressPortBase) * 8;
- uint32_t mask = bit_mask<uint32_t>(value->access_size * 8);
-
- fbl::AutoLock lock(&mutex_);
- uint32_t addr = config_addr_ >> bit_offset;
- value->u32 = addr & mask;
- return ZX_OK;
- }
- case kPciConfigDataPortBase... kPciConfigDataPortTop: {
- uint32_t addr;
- uint64_t reg;
- {
- fbl::AutoLock lock(&mutex_);
- addr = config_addr_;
- if (!is_addr_valid(PCI_TYPE1_BUS(addr), PCI_TYPE1_DEVICE(addr),
- PCI_TYPE1_FUNCTION(addr))) {
- return pci_read_unimplemented_device(value);
- }
- }
-
- PciDevice* device = device_[PCI_TYPE1_DEVICE(addr)];
- reg = PCI_TYPE1_REGISTER(addr) + port - kPciConfigDataPortBase;
- return device->ReadConfig(reg, value);
- }
- default:
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t PciBus::WriteIoPort(uint64_t port, const IoValue& value) {
- switch (port) {
- case kPciConfigAddressPortBase... kPciConfigAddressPortTop: {
- // Software can (and Linux does) perform partial word accesses to the
- // PCI address register. This means we need to take care to read/write
- // portions of the 32bit register without trampling the other bits.
- uint64_t bit_offset = (port - kPciConfigAddressPortBase) * 8;
- uint32_t bit_size = value.access_size * 8;
- uint32_t mask = bit_mask<uint32_t>(bit_size);
-
- fbl::AutoLock lock(&mutex_);
- // Clear out the bits we'll be modifying.
- config_addr_ = clear_bits(config_addr_, bit_size, bit_offset);
- // Set the bits of the address.
- config_addr_ |= (value.u32 & mask) << bit_offset;
- return ZX_OK;
- }
- case kPciConfigDataPortBase... kPciConfigDataPortTop: {
- uint32_t addr;
- uint64_t reg;
- {
- fbl::AutoLock lock(&mutex_);
- addr = config_addr_;
-
- if (!is_addr_valid(PCI_TYPE1_BUS(addr),
- PCI_TYPE1_DEVICE(addr),
- PCI_TYPE1_FUNCTION(addr))) {
- return pci_write_unimplemented_device();
- }
-
- reg = PCI_TYPE1_REGISTER(addr) + port - kPciConfigDataPortBase;
- }
- PciDevice* device = device_[PCI_TYPE1_DEVICE(addr)];
- return device->WriteConfig(reg, value);
- }
- default:
- return ZX_ERR_NOT_SUPPORTED;
- }
-}
-
-zx_status_t PciBus::Interrupt(const PciDevice& device) const {
- return interrupt_controller_->Interrupt(device.global_irq_);
-}
-
-// PCI Local Bus Spec v3.0 Section 6.7: Each capability must be DWORD aligned.
-static inline uint8_t pci_cap_len(const pci_cap_t* cap) {
- return align(cap->len, 4);
-}
-
-const pci_cap_t* PciDevice::FindCapability(uint8_t addr, uint8_t* cap_index,
- uint32_t* cap_base) const {
- uint32_t base = PCI_REGISTER_CAP_BASE;
- for (uint8_t i = 0; i < num_capabilities_; ++i) {
- const pci_cap_t* cap = &capabilities_[i];
- uint8_t cap_len = pci_cap_len(cap);
- if (addr >= base + cap_len) {
- base += cap_len;
- continue;
- }
- *cap_index = i;
- *cap_base = base;
- return cap;
- }
-
- // Given address doesn't lie within the range of addresses occupied by
- // capabilities.
- return nullptr;
-}
-
-zx_status_t PciDevice::ReadCapability(uint8_t addr, uint32_t* out) const {
- uint8_t cap_index;
- uint32_t cap_base;
- const pci_cap_t* cap = FindCapability(addr, &cap_index, &cap_base);
- if (cap == nullptr)
- return ZX_ERR_NOT_FOUND;
-
- uint32_t word = 0;
- uint32_t cap_offset = addr - cap_base;
- for (uint8_t byte = 0; byte < sizeof(word); ++byte, ++cap_offset) {
-
- // In the case of padding bytes, return 0.
- if (cap_offset >= cap->len)
- break;
-
- // PCI Local Bus Spec v3.0 Section 6.7:
- // Each capability in the list consists of an 8-bit ID field assigned
- // by the PCI SIG, an 8 bit pointer in configuration space to the next
- // capability, and some number of additional registers immediately
- // following the pointer to implement that capability.
- uint32_t val = 0;
- switch (cap_offset) {
- case kPciCapTypeOffset:
- val = cap->id;
- break;
- case kPciCapNextOffset:
- // PCI Local Bus Spec v3.0 Section 6.7: A pointer value of 00h is
- // used to indicate the last capability in the list.
- if (cap_index + 1u < num_capabilities_)
- val = cap_base + pci_cap_len(cap);
- break;
- default:
- val = cap->data[cap_offset];
- break;
- }
- word |= val << (byte * 8);
- }
-
- *out = word;
- return ZX_OK;
-}
-
-/* Read a 4 byte aligned value from PCI config space. */
-zx_status_t PciDevice::ReadConfigWord(uint8_t reg, uint32_t* value) const {
- switch (reg) {
- // ---------------------------------
- // | (31..16) | (15..0) |
- // | device_id | vendor_id |
- // ---------------------------------
- case PCI_CONFIG_VENDOR_ID:
- *value = attrs_.vendor_id;
- *value |= attrs_.device_id << 16;
- return ZX_OK;
- // ----------------------------
- // | (31..16) | (15..0) |
- // | status | command |
- // ----------------------------
- case PCI_CONFIG_COMMAND: {
- fbl::AutoLock lock(&mutex_);
- *value = command_;
-
- uint16_t status = PCI_STATUS_INTERRUPT;
- if (capabilities_ != nullptr)
- status |= PCI_STATUS_NEW_CAPS;
- *value |= status << 16;
- return ZX_OK;
- }
- // -------------------------------------------------
- // | (31..16) | (15..8) | (7..0) |
- // | class_code | prog_if | revision_id |
- // -------------------------------------------------
- case PCI_CONFIG_REVISION_ID:
- *value = attrs_.device_class;
- return ZX_OK;
- // ---------------------------------------------------------------
- // | (31..24) | (23..16) | (15..8) | (7..0) |
- // | BIST | header_type | latency_timer | cache_line_size |
- // ---------------------------------------------------------------
- case PCI_CONFIG_CACHE_LINE_SIZE:
- *value = PCI_HEADER_TYPE_STANDARD << 16;
- return ZX_OK;
- case PCI_REGISTER_BAR_0:
- case PCI_REGISTER_BAR_1:
- case PCI_REGISTER_BAR_2:
- case PCI_REGISTER_BAR_3:
- case PCI_REGISTER_BAR_4:
- case PCI_REGISTER_BAR_5: {
- uint32_t bar_num = (reg - PCI_REGISTER_BAR_0) / 4;
- if (bar_num >= PCI_MAX_BARS)
- return pci_read_unimplemented_register(value);
-
- fbl::AutoLock lock(&mutex_);
- const PciBar* bar = &bar_[bar_num];
- *value = bar->addr | bar->aspace();
- return ZX_OK;
- }
- // -------------------------------------------------------------
- // | (31..24) | (23..16) | (15..8) | (7..0) |
- // | max_latency | min_grant | interrupt_pin | interrupt_line |
- // -------------------------------------------------------------
- case PCI_CONFIG_INTERRUPT_LINE: {
- const uint8_t interrupt_pin = 1;
- *value = interrupt_pin << 8;
- return ZX_OK;
- }
- // -------------------------------------------
- // | (31..16) | (15..0) |
- // | subsystem_id | subsystem_vendor_id |
- // -------------------------------------------
- case PCI_CONFIG_SUBSYS_VENDOR_ID:
- *value = attrs_.subsystem_vendor_id;
- *value |= attrs_.subsystem_id << 16;
- return ZX_OK;
- // ------------------------------------------
- // | (31..8) | (7..0) |
- // | Reserved | capabilities_pointer |
- // ------------------------------------------
- case PCI_CONFIG_CAPABILITIES:
- *value = 0;
- if (capabilities_ != nullptr)
- *value |= PCI_REGISTER_CAP_BASE;
- return ZX_OK;
- case PCI_REGISTER_CAP_BASE... PCI_REGISTER_CAP_TOP:
- if (ReadCapability(reg, value) != ZX_ERR_NOT_FOUND)
- return ZX_OK;
- // Fall-through if the capability is not-implemented.
- default:
- return pci_read_unimplemented_register(value);
- }
-}
-
-zx_status_t PciDevice::ReadConfig(uint64_t reg, IoValue* value) const {
- // Perform 4-byte aligned read and then shift + mask the result to get the
- // expected value.
- uint32_t word = 0;
- const uint8_t reg_mask = bit_mask<uint8_t>(2);
- uint8_t word_aligend_reg = static_cast<uint8_t>(reg & ~reg_mask);
- uint8_t bit_offset = static_cast<uint8_t>((reg & reg_mask) * 8);
- zx_status_t status = ReadConfigWord(word_aligend_reg, &word);
- if (status != ZX_OK)
- return status;
-
- word >>= bit_offset;
- word &= bit_mask<uint32_t>(value->access_size * 8);
- value->u32 = word;
- return ZX_OK;
-}
-
-zx_status_t PciDevice::WriteConfig(uint64_t reg, const IoValue& value) {
- switch (reg) {
- case PCI_CONFIG_COMMAND: {
- if (value.access_size != 2)
- return ZX_ERR_NOT_SUPPORTED;
- fbl::AutoLock lock(&mutex_);
- command_ = value.u16;
- return ZX_OK;
- }
- case PCI_REGISTER_BAR_0:
- case PCI_REGISTER_BAR_1:
- case PCI_REGISTER_BAR_2:
- case PCI_REGISTER_BAR_3:
- case PCI_REGISTER_BAR_4:
- case PCI_REGISTER_BAR_5: {
- if (value.access_size != 4)
- return ZX_ERR_NOT_SUPPORTED;
-
- uint64_t bar_num = (reg - PCI_REGISTER_BAR_0) / 4;
- if (bar_num >= PCI_MAX_BARS)
- return pci_write_unimplemented_register();
-
- fbl::AutoLock lock(&mutex_);
- PciBar* bar = &bar_[bar_num];
- bar->addr = value.u32;
- // We zero bits in the BAR in order to set the size.
- bar->addr &= ~(bar->size - 1);
- return ZX_OK;
- }
- default:
- return pci_write_unimplemented_register();
- }
-}
-
-zx_status_t PciDevice::SetupBarTraps(Guest* guest) {
- for (uint8_t i = 0; i < PCI_MAX_BARS; ++i) {
- PciBar* bar = &bar_[i];
- if (!is_bar_implemented(i))
- break;
-
- bar->n = i;
- bar->device = this;
-
- uint64_t addr = bar->base();
- uint64_t size = bar->size;
- zx_status_t status = guest->CreateMapping(bar->trap_type, addr, size, 0, bar);
- if (status != ZX_OK)
- return status;
- }
-
- return ZX_OK;
-}
-
-zx_status_t PciDevice::Interrupt() const {
- if (!bus_)
- return ZX_ERR_BAD_STATE;
- return bus_->Interrupt(*this);
-}
diff --git a/system/ulib/machina/rules.mk b/system/ulib/machina/rules.mk
deleted file mode 100644
index 9683b22..0000000
--- a/system/ulib/machina/rules.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2017 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-LOCAL_DIR := $(GET_LOCAL_DIR)
-
-MODULE := $(LOCAL_DIR)
-
-MODULE_SO_NAME := machina
-
-MODULE_TYPE := userlib
-
-MODULE_SRCS := \
- $(LOCAL_DIR)/balloon.cpp \
- $(LOCAL_DIR)/block.cpp \
- $(LOCAL_DIR)/gpu.cpp \
- $(LOCAL_DIR)/input.cpp \
- $(LOCAL_DIR)/pci.cpp \
- $(LOCAL_DIR)/virtio.cpp \
- $(LOCAL_DIR)/virtio_pci.cpp \
-
-MODULE_HEADER_DEPS := \
- system/ulib/ddk \
- system/ulib/virtio \
-
-MODULE_LIBS := \
- system/ulib/c \
- system/ulib/fdio \
- system/ulib/hid \
- system/ulib/zircon \
-
-MODULE_STATIC_LIBS := \
- system/ulib/block-client \
- system/ulib/fbl \
- system/ulib/hypervisor \
- system/ulib/sync \
- system/ulib/zx \
- system/ulib/zxcpp \
-
-MODULE_CPPFLAGS += \
- -Isystem/ulib/hypervisor/arch/$(ARCH)/include \
- -Isystem/ulib/machina/arch/$(ARCH)/include \
-
-include system/ulib/machina/arch/$(ARCH)/rules.mk
-include make/module.mk
diff --git a/system/ulib/machina/virtio.cpp b/system/ulib/machina/virtio.cpp
deleted file mode 100644
index 5279767..0000000
--- a/system/ulib/machina/virtio.cpp
+++ /dev/null
@@ -1,315 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/virtio.h>
-
-#include <stdio.h>
-#include <string.h>
-
-#include <fbl/auto_lock.h>
-#include <fbl/unique_ptr.h>
-#include <virtio/virtio_ring.h>
-
-#define QUEUE_SIZE 128u
-
-// Convert guest-physical addresses to usable virtual addresses.
-#define guest_paddr_to_host_vaddr(device, addr) \
- (static_cast<zx_vaddr_t>(((device)->guest_physmem_addr()) + (addr)))
-
-VirtioDevice::VirtioDevice(uint8_t device_id, void* config, size_t config_size,
- virtio_queue_t* queues, uint16_t num_queues,
- uintptr_t guest_physmem_addr, size_t guest_physmem_size)
- : device_id_(device_id), device_config_(config), device_config_size_(config_size),
- num_queues_(num_queues), queues_(queues), guest_physmem_addr_(guest_physmem_addr),
- guest_physmem_size_(guest_physmem_size), pci_(this) {
- // Virt queue initialization.
- for (int i = 0; i < num_queues_; ++i) {
- virtio_queue_t* queue = &queues_[i];
- memset(queue, 0, sizeof(*queue));
- queue->size = QUEUE_SIZE;
- queue->virtio_device = this;
- }
-}
-
-// Returns a circular index into a Virtio ring.
-static uint32_t ring_index(virtio_queue_t* queue, uint32_t index) {
- return index % queue->size;
-}
-
-static bool ring_has_avail(virtio_queue_t* queue) {
- if (queue->avail == nullptr)
- return 0;
- return queue->avail->idx != queue->index;
-}
-
-static bool validate_queue_range(VirtioDevice* device, zx_vaddr_t addr, size_t size) {
- uintptr_t mem_addr = device->guest_physmem_addr();
- size_t mem_size = device->guest_physmem_size();
- zx_vaddr_t range_end = addr + size;
- zx_vaddr_t mem_end = mem_addr + mem_size;
-
- return addr >= mem_addr && range_end <= mem_end;
-}
-
-template <typename T>
-static void queue_set_segment_addr(virtio_queue_t* queue, uint64_t guest_paddr, size_t size,
- T** ptr) {
- VirtioDevice* device = queue->virtio_device;
- zx_vaddr_t host_vaddr = guest_paddr_to_host_vaddr(device, guest_paddr);
-
- *ptr = validate_queue_range(device, host_vaddr, size) ? reinterpret_cast<T*>(host_vaddr)
- : nullptr;
-}
-
-void virtio_queue_set_desc_addr(virtio_queue_t* queue, uint64_t desc_paddr) {
- queue->addr.desc = desc_paddr;
- uintptr_t desc_size = queue->size * sizeof(queue->desc[0]);
- queue_set_segment_addr(queue, desc_paddr, desc_size, &queue->desc);
-}
-
-void virtio_queue_set_avail_addr(virtio_queue_t* queue, uint64_t avail_paddr) {
- queue->addr.avail = avail_paddr;
- uintptr_t avail_size = sizeof(*queue->avail) + (queue->size * sizeof(queue->avail->ring[0]));
- queue_set_segment_addr(queue, avail_paddr, avail_size, &queue->avail);
-
- uintptr_t used_event_paddr = avail_paddr + avail_size;
- uintptr_t used_event_size = sizeof(*queue->used_event);
- queue_set_segment_addr(queue, used_event_paddr, used_event_size, &queue->used_event);
-}
-
-void virtio_queue_set_used_addr(virtio_queue_t* queue, uint64_t used_paddr) {
- queue->addr.used = used_paddr;
- uintptr_t used_size = sizeof(*queue->used) + (queue->size * sizeof(queue->used->ring[0]));
- queue_set_segment_addr(queue, used_paddr, used_size, &queue->used);
-
- uintptr_t avail_event_paddr = used_paddr + used_size;
- uintptr_t avail_event_size = sizeof(*queue->avail_event);
- queue_set_segment_addr(queue, avail_event_paddr, avail_event_size, &queue->avail_event);
-}
-
-void virtio_queue_signal(virtio_queue_t* queue) {
- mtx_lock(&queue->mutex);
- if (ring_has_avail(queue))
- cnd_signal(&queue->avail_ring_cnd);
- mtx_unlock(&queue->mutex);
-}
-
-zx_status_t VirtioDevice::NotifyGuest() {
- return pci_.Interrupt();
-}
-
-zx_status_t VirtioDevice::Kick(uint16_t kicked_queue) {
- if (kicked_queue >= num_queues_)
- return ZX_ERR_OUT_OF_RANGE;
-
- zx_status_t status = HandleQueueNotify(kicked_queue);
- if (status != ZX_OK) {
- fprintf(stderr, "Failed to handle queue notify event.\n");
- return status;
- }
-
- // Send an interrupt back to the guest if we've generated one while
- // processing the queue.
- fbl::AutoLock lock(&mutex_);
- if (isr_status_ > 0) {
- return NotifyGuest();
- }
-
- // Notify threads waiting on a descriptor.
- virtio_queue_signal(&queues_[kicked_queue]);
- return ZX_OK;
-}
-
-// This must not return any errors besides ZX_ERR_NOT_FOUND.
-static zx_status_t virtio_queue_next_avail_locked(virtio_queue_t* queue, uint16_t* index) {
- if (!ring_has_avail(queue))
- return ZX_ERR_NOT_FOUND;
-
- *index = queue->avail->ring[ring_index(queue, queue->index++)];
- return ZX_OK;
-}
-
-zx_status_t virtio_queue_next_avail(virtio_queue_t* queue, uint16_t* index) {
- mtx_lock(&queue->mutex);
- zx_status_t status = virtio_queue_next_avail_locked(queue, index);
- mtx_unlock(&queue->mutex);
- return status;
-}
-
-void virtio_queue_wait(virtio_queue_t* queue, uint16_t* index) {
- mtx_lock(&queue->mutex);
- while (virtio_queue_next_avail_locked(queue, index) == ZX_ERR_NOT_FOUND)
- cnd_wait(&queue->avail_ring_cnd, &queue->mutex);
- mtx_unlock(&queue->mutex);
-}
-
-struct poll_task_args_t {
- virtio_queue_t* queue;
- virtio_queue_poll_fn_t handler;
- void* ctx;
-
- poll_task_args_t(virtio_queue_t* queue, virtio_queue_poll_fn_t handler, void* ctx)
- : queue(queue), handler(handler), ctx(ctx) {}
-};
-
-static int virtio_queue_poll_task(void* ctx) {
- zx_status_t result = ZX_OK;
- fbl::unique_ptr<poll_task_args_t> args(static_cast<poll_task_args_t*>(ctx));
- while (true) {
- uint16_t descriptor;
- virtio_queue_wait(args->queue, &descriptor);
-
- uint32_t used = 0;
- zx_status_t status = args->handler(args->queue, descriptor, &used, args->ctx);
- virtio_queue_return(args->queue, descriptor, used);
-
- if (status == ZX_ERR_STOP)
- break;
- if (status != ZX_OK) {
- fprintf(stderr, "Error %d while handling queue buffer.\n", status);
- result = status;
- break;
- }
-
- result = args->queue->virtio_device->NotifyGuest();
- if (result != ZX_OK)
- break;
- }
-
- return result;
-}
-
-zx_status_t virtio_queue_poll(virtio_queue_t* queue, virtio_queue_poll_fn_t handler, void* ctx) {
- auto args = fbl::make_unique<poll_task_args_t>(queue, handler, ctx);
-
- thrd_t thread;
- int ret = thrd_create(&thread, virtio_queue_poll_task, args.release());
- if (ret != thrd_success) {
- fprintf(stderr, "Failed to create queue thread %d\n", ret);
- return ZX_ERR_INTERNAL;
- }
-
- ret = thrd_detach(thread);
- if (ret != thrd_success) {
- fprintf(stderr, "Failed to detach queue thread %d\n", ret);
- return ZX_ERR_INTERNAL;
- }
-
- return ZX_OK;
-}
-
-zx_status_t virtio_queue_read_desc(virtio_queue_t* queue, uint16_t desc_index, virtio_desc_t* out) {
- VirtioDevice* device = queue->virtio_device;
- volatile struct vring_desc& desc = queue->desc[desc_index];
- size_t mem_size = device->guest_physmem_size();
-
- const uint64_t end = desc.addr + desc.len;
- if (end < desc.addr || end > mem_size)
- return ZX_ERR_OUT_OF_RANGE;
-
- out->addr = reinterpret_cast<void*>(guest_paddr_to_host_vaddr(device, desc.addr));
- out->len = desc.len;
- out->has_next = desc.flags & VRING_DESC_F_NEXT;
- out->writable = desc.flags & VRING_DESC_F_WRITE;
- out->next = desc.next;
- return ZX_OK;
-}
-
-void virtio_queue_return(virtio_queue_t* queue, uint16_t index, uint32_t len) {
- mtx_lock(&queue->mutex);
-
- volatile struct vring_used_elem* used = &queue->used->ring[ring_index(queue, queue->used->idx)];
-
- used->id = index;
- used->len = len;
- queue->used->idx++;
-
- mtx_unlock(&queue->mutex);
-
- // Set the queue bit in the device ISR so that the driver knows to check
- // the queues on the next interrupt.
- queue->virtio_device->add_isr_flags(VirtioDevice::VIRTIO_ISR_QUEUE);
-}
-
-zx_status_t virtio_queue_handler(virtio_queue_t* queue, virtio_queue_fn_t handler, void* context) {
- uint16_t head;
- uint32_t used_len = 0;
- uintptr_t mem_addr = queue->virtio_device->guest_physmem_addr();
- size_t mem_size = queue->virtio_device->guest_physmem_size();
-
- // Get the next descriptor from the available ring. If none are available
- // we can just no-op.
- zx_status_t status = virtio_queue_next_avail(queue, &head);
- if (status == ZX_ERR_NOT_FOUND)
- return ZX_OK;
- if (status != ZX_OK)
- return status;
-
- status = ZX_OK;
- uint16_t desc_index = head;
- volatile const struct vring_desc* desc;
- do {
- if (desc_index >= queue->size)
- return ZX_ERR_OUT_OF_RANGE;
- desc = &queue->desc[desc_index];
-
- const uint64_t end = desc->addr + desc->len;
- if (end < desc->addr || end > mem_size)
- return ZX_ERR_OUT_OF_RANGE;
-
- void* addr = reinterpret_cast<void*>(mem_addr + desc->addr);
- status = handler(addr, desc->len, desc->flags, &used_len, context);
- if (status != ZX_OK)
- return status;
-
- desc_index = desc->next;
- } while (desc->flags & VRING_DESC_F_NEXT);
-
- virtio_queue_return(queue, head, used_len);
- return ring_has_avail(queue) ? ZX_ERR_NEXT : ZX_OK;
-}
-
-zx_status_t VirtioDevice::ReadConfig(uint64_t addr, IoValue* value) {
- fbl::AutoLock lock(&config_mutex_);
- switch (value->access_size) {
- case 1: {
- uint8_t* buf = reinterpret_cast<uint8_t*>(device_config_);
- value->u8 = buf[addr];
- return ZX_OK;
- }
- case 2: {
- uint16_t* buf = reinterpret_cast<uint16_t*>(device_config_);
- value->u16 = buf[addr / 2];
- return ZX_OK;
- }
- case 4: {
- uint32_t* buf = reinterpret_cast<uint32_t*>(device_config_);
- value->u32 = buf[addr / 4];
- return ZX_OK;
- }
- }
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t VirtioDevice::WriteConfig(uint64_t addr, const IoValue& value) {
- fbl::AutoLock lock(&config_mutex_);
- switch (value.access_size) {
- case 1: {
- uint8_t* buf = reinterpret_cast<uint8_t*>(device_config_);
- buf[addr] = value.u8;
- return ZX_OK;
- }
- case 2: {
- uint16_t* buf = reinterpret_cast<uint16_t*>(device_config_);
- buf[addr / 2] = value.u16;
- return ZX_OK;
- }
- case 4: {
- uint32_t* buf = reinterpret_cast<uint32_t*>(device_config_);
- buf[addr / 4] = value.u32;
- return ZX_OK;
- }
- }
- return ZX_ERR_NOT_SUPPORTED;
-}
diff --git a/system/ulib/machina/virtio_pci.cpp b/system/ulib/machina/virtio_pci.cpp
deleted file mode 100644
index 516b07a..0000000
--- a/system/ulib/machina/virtio_pci.cpp
+++ /dev/null
@@ -1,464 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/virtio_pci.h>
-
-#include <stdio.h>
-
-#include <fbl/auto_lock.h>
-#include <hypervisor/bits.h>
-#include <machina/virtio.h>
-#include <virtio/virtio_ids.h>
-
-static uint8_t kPciCapTypeVendorSpecific = 0x9;
-
-static uint16_t kPciVendorIdVirtio = 0x1af4;
-
-/* Virtio PCI Bar Layout.
- *
- * Expose all read/write fields on BAR0 using a strongly ordered mapping.
- * Map the Queue notify region to BAR1 with a BELL type that does not require
- * the guest to decode any instruction fields. The queue to notify can be
- * inferred based on the address accessed alone.
- *
- * BAR0 BAR1
- * ------------ 00h ------------ 00h
- * | Virtio PCI | | Queue 0 |
- * | Common | | Notify |
- * | Config | |------------| 04h
- * |------------| 38h | Queue 1 |
- * | ISR Config | | Notify |
- * |------------| 3ch |------------|
- * | Device- | | ... |
- * | Specific | |------------| 04 * N
- * | Config | | Queue N |
- * | | | Notify |
- * ------------ ------------
- * These structures are defined in Virtio 1.0 Section 4.1.4.
- */
-static const uint8_t kVirtioPciBar = 0;
-static const uint8_t kVirtioPciNotifyBar = 1;
-
-// Common configuration.
-static const size_t kVirtioPciCommonCfgBase = 0;
-static const size_t kVirtioPciCommonCfgSize = 0x38;
-static const size_t kVirtioPciCommonCfgTop = kVirtioPciCommonCfgBase + kVirtioPciCommonCfgSize - 1;
-static_assert(kVirtioPciCommonCfgSize == sizeof(virtio_pci_common_cfg_t),
- "virtio_pci_common_cfg_t has unexpected size");
-// Virtio 1.0 Section 4.1.4.3.1: offset MUST be 4-byte aligned.
-static_assert(is_aligned(kVirtioPciCommonCfgBase, 4),
- "Virtio PCI common config has illegal alignment.");
-
-// Notification configuration.
-//
-// Virtio 1.0 Section 4.1.4.4: notify_off_multiplier is combined with the
-// queue_notify_off to derive the Queue Notify address within a BAR for a
-// virtqueue:
-//
-// cap.offset + queue_notify_off * notify_off_multiplier
-//
-// Virtio 1.0 Section 4.1.4.4.1: The device MUST either present
-// notify_off_multiplier as an even power of 2, or present
-// notify_off_multiplier as 0.
-//
-// By using a multiplier of 4, we use sequential 4b words to notify, ex:
-//
-// cap.offset + 0 -> Notify Queue 0
-// cap.offset + 4 -> Notify Queue 1
-// ...
-// cap.offset + 4n -> Notify Queuen 'n'
-static const size_t kVirtioPciNotifyCfgMultiplier = 4;
-static const size_t kVirtioPciNotifyCfgBase = 0;
-// Virtio 1.0 Section 4.1.4.4.1: offset MUST be 2-byte aligned.
-static_assert(is_aligned(kVirtioPciNotifyCfgBase, 2),
- "Virtio PCI notify config has illegal alignment.");
-
-// Interrupt status configuration.
-static const size_t kVirtioPciIsrCfgBase = 0x38;
-static const size_t kVirtioPciIsrCfgSize = 1;
-static const size_t kVirtioPciIsrCfgTop = kVirtioPciIsrCfgBase + kVirtioPciIsrCfgSize - 1;
-// Virtio 1.0 Section 4.1.4.5: The offset for the ISR status has no alignment
-// requirements.
-
-// Device-specific configuration.
-static const size_t kVirtioPciDeviceCfgBase = 0x3c;
-// Virtio 1.0 Section 4.1.4.6.1: The offset for the device-specific
-// configuration MUST be 4-byte aligned.
-static_assert(is_aligned(kVirtioPciDeviceCfgBase, 4),
- "Virtio PCI notify config has illegal alignment.");
-
-/* Handle reads to the common configuration structure as defined in
- * Virtio 1.0 Section 4.1.4.3.
- */
-zx_status_t VirtioPci::CommonCfgRead(uint64_t addr, IoValue* value) const {
- switch (addr) {
- case VIRTIO_PCI_COMMON_CFG_DRIVER_FEATURES_SEL: {
- fbl::AutoLock lock(&device_->mutex_);
- value->u32 = device_->driver_features_sel_;
- value->access_size = 4;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_DEVICE_FEATURES_SEL: {
- fbl::AutoLock lock(&device_->mutex_);
- value->u32 = device_->features_sel_;
- value->access_size = 4;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_DRIVER_FEATURES: {
- // We currently only support a single feature word.
- fbl::AutoLock lock(&device_->mutex_);
- value->u32 = device_->driver_features_sel_ > 0 ? 0 : device_->driver_features_;
- value->access_size = 4;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_DEVICE_FEATURES: {
- // Virtio 1.0 Section 6:
- //
- // A device MUST offer VIRTIO_F_VERSION_1.
- //
- // VIRTIO_F_VERSION_1(32) This indicates compliance with this
- // specification, giving a simple way to detect legacy devices or
- // drivers.
- //
- // This is the only feature supported beyond the first feature word so
- // we just specaial case it here.
- fbl::AutoLock lock(&device_->mutex_);
- value->access_size = 4;
- if (device_->features_sel_ == 1) {
- value->u32 = 1;
- return ZX_OK;
- }
-
- value->u32 = device_->features_sel_ > 0 ? 0 : device_->features_;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_NUM_QUEUES: {
- fbl::AutoLock lock(&device_->mutex_);
- value->u16 = device_->num_queues_;
- value->access_size = 2;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_DEVICE_STATUS: {
- fbl::AutoLock lock(&device_->mutex_);
- value->u8 = device_->status_;
- value->access_size = 1;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_QUEUE_SEL: {
- fbl::AutoLock lock(&device_->mutex_);
- value->u16 = device_->queue_sel_;
- value->access_size = 2;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_QUEUE_SIZE: {
- virtio_queue_t* queue = selected_queue();
- if (queue == nullptr)
- return ZX_ERR_BAD_STATE;
-
- fbl::AutoLock lock(&queue->mutex);
- value->u16 = queue->size;
- value->access_size = 2;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_QUEUE_ENABLE:
- // Virtio 1.0 Section 4.1.4.3: The device MUST present a 0 in
- // queue_enable on reset.
- //
- // Note the implementation currently does not respect this value.
- value->access_size = 2;
- value->u16 = 0;
- return ZX_OK;
- case VIRTIO_PCI_COMMON_CFG_QUEUE_DESC_LOW... VIRTIO_PCI_COMMON_CFG_QUEUE_USED_HIGH: {
- virtio_queue_t* queue = selected_queue();
- if (queue == nullptr)
- return ZX_ERR_BAD_STATE;
-
- size_t word = (addr - VIRTIO_PCI_COMMON_CFG_QUEUE_DESC_LOW) / sizeof(uint32_t);
- fbl::AutoLock lock(&queue->mutex);
- value->u32 = queue->addr.words[word];
- value->access_size = 4;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_QUEUE_NOTIFY_OFF: {
- fbl::AutoLock lock(&device_->mutex_);
- if (device_->queue_sel_ >= device_->num_queues_)
- return ZX_ERR_BAD_STATE;
-
- value->u32 = device_->queue_sel_;
- value->access_size = 4;
- return ZX_OK;
- }
-
- // Currently not implmeneted.
- case VIRTIO_PCI_COMMON_CFG_CONFIG_GEN:
- case VIRTIO_PCI_COMMON_CFG_QUEUE_MSIX_VECTOR:
- case VIRTIO_PCI_COMMON_CFG_MSIX_CONFIG:
- value->u32 = 0;
- return ZX_OK;
- }
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t VirtioPci::ConfigBarRead(uint64_t addr, IoValue* value) const {
- switch (addr) {
- case kVirtioPciCommonCfgBase... kVirtioPciCommonCfgTop:
- return CommonCfgRead(addr - kVirtioPciCommonCfgBase, value);
- case kVirtioPciIsrCfgBase... kVirtioPciIsrCfgTop:
- fbl::AutoLock lock(&device_->mutex_);
- value->u8 = device_->isr_status_;
- value->access_size = 1;
-
- // From VIRTIO 1.0 Section 4.1.4.5:
- //
- // To avoid an extra access, simply reading this register resets it to
- // 0 and causes the device to de-assert the interrupt.
- device_->isr_status_ = 0;
- return ZX_OK;
- }
-
- size_t device_config_top = kVirtioPciDeviceCfgBase + device_->device_config_size_;
- if (addr >= kVirtioPciDeviceCfgBase && addr < device_config_top) {
- uint64_t device_offset = addr - kVirtioPciDeviceCfgBase;
- return device_->ReadConfig(device_offset, value);
- }
- fprintf(stderr, "Unhandled read %#lx\n", addr);
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-static void virtio_queue_update_addr(virtio_queue_t* queue) {
- virtio_queue_set_desc_addr(queue, queue->addr.desc);
- virtio_queue_set_avail_addr(queue, queue->addr.avail);
- virtio_queue_set_used_addr(queue, queue->addr.used);
-}
-
-/* Handle writes to the common configuration structure as defined in
- * Virtio 1.0 Section 4.1.4.3.
- */
-zx_status_t VirtioPci::CommonCfgWrite(uint64_t addr, const IoValue& value) {
- switch (addr) {
- case VIRTIO_PCI_COMMON_CFG_DEVICE_FEATURES_SEL: {
- if (value.access_size != 4)
- return ZX_ERR_IO_DATA_INTEGRITY;
-
- fbl::AutoLock lock(&device_->mutex_);
- device_->features_sel_ = value.u32;
- return ZX_OK;
- }
-
- case VIRTIO_PCI_COMMON_CFG_DRIVER_FEATURES_SEL: {
- if (value.access_size != 4)
- return ZX_ERR_IO_DATA_INTEGRITY;
-
- fbl::AutoLock lock(&device_->mutex_);
- device_->driver_features_sel_ = value.u32;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_DRIVER_FEATURES: {
- if (value.access_size != 4)
- return ZX_ERR_IO_DATA_INTEGRITY;
-
- fbl::AutoLock lock(&device_->mutex_);
- if (device_->driver_features_sel_ == 0)
- device_->driver_features_ = value.u32;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_DEVICE_STATUS: {
- if (value.access_size != 1)
- return ZX_ERR_IO_DATA_INTEGRITY;
-
- fbl::AutoLock lock(&device_->mutex_);
- device_->status_ = value.u8;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_QUEUE_SEL: {
- if (value.access_size != 2)
- return ZX_ERR_IO_DATA_INTEGRITY;
- if (value.u16 >= device_->num_queues_)
- return ZX_ERR_NOT_SUPPORTED;
-
- fbl::AutoLock lock(&device_->mutex_);
- device_->queue_sel_ = value.u16;
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_QUEUE_SIZE: {
- if (value.access_size != 2)
- return ZX_ERR_IO_DATA_INTEGRITY;
- virtio_queue_t* queue = selected_queue();
- if (queue == nullptr)
- return ZX_ERR_BAD_STATE;
-
- fbl::AutoLock lock(&queue->mutex);
- queue->size = value.u16;
- virtio_queue_update_addr(queue);
- return ZX_OK;
- }
- case VIRTIO_PCI_COMMON_CFG_QUEUE_DESC_LOW... VIRTIO_PCI_COMMON_CFG_QUEUE_USED_HIGH: {
- if (value.access_size != 4)
- return ZX_ERR_IO_DATA_INTEGRITY;
- virtio_queue_t* queue = selected_queue();
- if (queue == nullptr)
- return ZX_ERR_BAD_STATE;
-
- size_t word = (addr - VIRTIO_PCI_COMMON_CFG_QUEUE_DESC_LOW) / sizeof(uint32_t);
- fbl::AutoLock lock(&queue->mutex);
- queue->addr.words[word] = value.u32;
- virtio_queue_update_addr(queue);
- return ZX_OK;
- }
- // Not implemented registers.
- case VIRTIO_PCI_COMMON_CFG_QUEUE_MSIX_VECTOR:
- case VIRTIO_PCI_COMMON_CFG_MSIX_CONFIG:
- case VIRTIO_PCI_COMMON_CFG_QUEUE_ENABLE:
- return ZX_OK;
- // Read-only registers.
- case VIRTIO_PCI_COMMON_CFG_QUEUE_NOTIFY_OFF:
- case VIRTIO_PCI_COMMON_CFG_NUM_QUEUES:
- case VIRTIO_PCI_COMMON_CFG_CONFIG_GEN:
- case VIRTIO_PCI_COMMON_CFG_DEVICE_FEATURES:
- fprintf(stderr, "Unsupported write to %#lx\n", addr);
- return ZX_ERR_NOT_SUPPORTED;
- }
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t VirtioPci::ConfigBarWrite(uint64_t addr, const IoValue& value) {
- switch (addr) {
- case kVirtioPciCommonCfgBase... kVirtioPciCommonCfgTop: {
- uint64_t offset = addr - kVirtioPciCommonCfgBase;
- return CommonCfgWrite(offset, value);
- }
- }
-
- size_t device_config_top = kVirtioPciDeviceCfgBase + device_->device_config_size_;
- if (addr >= kVirtioPciDeviceCfgBase && addr < device_config_top) {
- uint64_t device_offset = addr - kVirtioPciDeviceCfgBase;
- return device_->WriteConfig(device_offset, value);
- }
- fprintf(stderr, "Unhandled write %#lx\n", addr);
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-void VirtioPci::SetupCap(pci_cap_t* cap, virtio_pci_cap_t* virtio_cap, uint8_t cfg_type,
- size_t cap_len, size_t data_length, uint8_t bar, size_t bar_offset) {
- virtio_cap->cfg_type = cfg_type;
- virtio_cap->bar = bar;
- virtio_cap->offset = static_cast<uint32_t>(bar_offset);
- virtio_cap->length = static_cast<uint32_t>(data_length);
-
- cap->id = kPciCapTypeVendorSpecific;
- cap->data = reinterpret_cast<uint8_t*>(virtio_cap);
- cap->len = virtio_cap->cap_len = static_cast<uint8_t>(cap_len);
-}
-
-void VirtioPci::SetupCaps() {
- // Common configuration.
- SetupCap(&capabilities_[0], &common_cfg_cap_,
- VIRTIO_PCI_CAP_COMMON_CFG, sizeof(common_cfg_cap_),
- kVirtioPciCommonCfgSize, kVirtioPciBar, kVirtioPciCommonCfgBase);
-
- // Notify configuration.
- notify_cfg_cap_.notify_off_multiplier = kVirtioPciNotifyCfgMultiplier;
- size_t notify_size = device_->num_queues() * kVirtioPciNotifyCfgMultiplier;
- SetupCap(&capabilities_[1], ¬ify_cfg_cap_.cap,
- VIRTIO_PCI_CAP_NOTIFY_CFG, sizeof(notify_cfg_cap_),
- notify_size, kVirtioPciNotifyBar, kVirtioPciNotifyCfgBase);
- bar_[kVirtioPciNotifyBar].size = static_cast<uint32_t>(notify_size);
- bar_[kVirtioPciNotifyBar].trap_type = TrapType::MMIO_BELL;
-
- // ISR configuration.
- SetupCap(&capabilities_[2], &isr_cfg_cap_,
- VIRTIO_PCI_CAP_ISR_CFG, sizeof(isr_cfg_cap_),
- kVirtioPciIsrCfgSize, kVirtioPciBar, kVirtioPciIsrCfgBase);
-
- // Device-specific configuration.
- SetupCap(&capabilities_[3], &device_cfg_cap_,
- VIRTIO_PCI_CAP_DEVICE_CFG, sizeof(device_cfg_cap_),
- device_->device_config_size_, kVirtioPciBar, kVirtioPciDeviceCfgBase);
-
- // Note VIRTIO_PCI_CAP_PCI_CFG is not implmeneted.
- // This one is more complex since it is writable and doesn't seem to be
- // used by Linux or Zircon.
-
- static_assert(kVirtioPciNumCapabilities == 4, "Incorrect number of capabilities.");
- set_capabilities(capabilities_, kVirtioPciNumCapabilities);
-
- static_assert(kVirtioPciBar < PCI_MAX_BARS, "Not enough BAR registers available.");
- bar_[kVirtioPciBar].size = static_cast<uint32_t>(
- kVirtioPciDeviceCfgBase + device_->device_config_size_);
- bar_[kVirtioPciBar].trap_type = TrapType::MMIO_SYNC;
-}
-
-static constexpr uint16_t virtio_pci_id(uint16_t virtio_id) {
- return static_cast<uint16_t>(virtio_id + 0x1040u);
-}
-
-static constexpr uint32_t virtio_pci_class_code(uint16_t virtio_id) {
- // See PCI LOCAL BUS SPECIFICATION, REV. 3.0 Section D.
- switch (virtio_id) {
- case VIRTIO_ID_BLOCK:
- return 0x01800000;
- case VIRTIO_ID_GPU:
- return 0x03808000;
- case VIRTIO_ID_INPUT:
- return 0x09800000;
- }
- return 0;
-}
-
-// Virtio 1.0 Section 4.1.2.1: Non-transitional devices SHOULD have a PCI
-// Revision ID of 1 or higher.
-static constexpr uint32_t kVirtioPciRevisionId = 1;
-
-static constexpr uint32_t virtio_pci_device_class(uint16_t virtio_id) {
- return virtio_pci_class_code(virtio_id) | kVirtioPciRevisionId;
-}
-
-virtio_queue_t* VirtioPci::selected_queue() const {
- fbl::AutoLock lock(&device_->mutex_);
- if (device_->queue_sel_ >= device_->num_queues_)
- return nullptr;
- return &device_->queues_[device_->queue_sel_];
-}
-
-VirtioPci::VirtioPci(VirtioDevice* device)
- : PciDevice({
- .device_id = virtio_pci_id(device->device_id_),
- .vendor_id = kPciVendorIdVirtio,
- .subsystem_id = device->device_id_,
- .subsystem_vendor_id = 0,
- .device_class = virtio_pci_device_class(device->device_id_),
- }),
- device_(device) {
-
- SetupCaps();
-}
-
-zx_status_t VirtioPci::ReadBar(uint8_t bar, uint64_t offset, IoValue* value) const {
- switch (bar) {
- case kVirtioPciBar:
- return ConfigBarRead(offset, value);
- }
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t VirtioPci::WriteBar(uint8_t bar, uint64_t offset, const IoValue& value) {
- switch (bar) {
- case kVirtioPciBar:
- return ConfigBarWrite(offset, value);
- case kVirtioPciNotifyBar:
- return NotifyBarWrite(offset, value);
- }
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t VirtioPci::NotifyBarWrite(uint64_t offset, const IoValue& value) {
- if (!is_aligned(offset, kVirtioPciNotifyCfgMultiplier))
- return ZX_ERR_INVALID_ARGS;
-
- uint64_t notify_queue = offset / kVirtioPciNotifyCfgMultiplier;
- if (notify_queue >= device_->num_queues())
- return ZX_ERR_INVALID_ARGS;
-
- return device_->Kick(static_cast<uint16_t>(notify_queue));
-}
diff --git a/system/utest/machina/block.cpp b/system/utest/machina/block.cpp
deleted file mode 100644
index 054ab58..0000000
--- a/system/utest/machina/block.cpp
+++ /dev/null
@@ -1,562 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <fbl/unique_ptr.h>
-#include <hypervisor/vcpu.h>
-#include <machina/block.h>
-#include <machina/virtio.h>
-#include <unittest/unittest.h>
-#include <virtio/block.h>
-#include <virtio/virtio_ring.h>
-
-#include "virtio_queue_fake.h"
-
-#define QUEUE_SIZE 8u
-#define DATA_SIZE 512u
-
-class VirtioBlockTest {
-public:
- VirtioBlockTest() : block_(0, UINTPTR_MAX), queue_(&block_.queue()) {}
-
- ~VirtioBlockTest() {
- if (fd_ > 0)
- close(fd_);
- }
-
- zx_status_t Init(char* block_path) {
- fd_ = CreateBlockFile(block_path);
- if (fd_ < 0)
- return ZX_ERR_IO;
-
- PhysMem phys_mem;
- zx_status_t status = block_.Init(block_path, phys_mem);
- if (status != ZX_OK)
- return status;
-
- return queue_.Init(QUEUE_SIZE);
- }
-
- zx_status_t WriteSector(uint8_t value, uint32_t sector, size_t len) {
- if (len > VirtioBlock::kSectorSize)
- return ZX_ERR_OUT_OF_RANGE;
-
- uint8_t buffer[VirtioBlock::kSectorSize];
- memset(buffer, value, len);
-
- ssize_t ret = lseek(fd_, sector * VirtioBlock::kSectorSize, SEEK_SET);
- if (ret < 0)
- return ZX_ERR_IO;
- ret = write(fd_, buffer, len);
- if (ret < 0)
- return ZX_ERR_IO;
-
- return ZX_OK;
- }
-
- VirtioBlock& block() { return block_; }
-
- VirtioQueueFake& queue() { return queue_; }
-
- int fd() const { return fd_; }
-
-private:
- int CreateBlockFile(char* path) {
- int fd = mkstemp(path);
- if (fd >= 0) {
- uint8_t zeroes[VirtioBlock::kSectorSize * 8];
- memset(zeroes, 0, sizeof(zeroes));
- ssize_t ret = write(fd, zeroes, sizeof(zeroes));
- if (ret < 0)
- return static_cast<int>(ret);
- }
- return fd;
- }
-
- int fd_ = 0;
- VirtioBlock block_;
- VirtioQueueFake queue_;
-};
-
-static bool file_block_device_bad_header(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-bad-header.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t req = {};
- uint8_t status;
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&req, sizeof(req) - 1)
- .AppendWriteable(&status, 1)
- .Build(&desc),
- ZX_OK);
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
- ASSERT_EQ(status, VIRTIO_BLK_S_IOERR);
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&req, sizeof(req) + 1)
- .AppendWriteable(&status, 1)
- .Build(&desc),
- ZX_OK);
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
- ASSERT_EQ(status, VIRTIO_BLK_S_IOERR);
-
- END_TEST;
-}
-
-static bool file_block_device_bad_payload(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-bad-payload.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t req = {};
- uint8_t status;
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&req, sizeof(req))
- .AppendReadable(UINTPTR_MAX, 1)
- .AppendWriteable(&status, 1)
- .Build(&desc),
- ZX_OK);
-
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
- END_TEST;
-}
-
-static bool file_block_device_bad_status(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-bad-status.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t header = {};
- uint8_t data[DATA_SIZE];
- uint8_t status = 0xff;
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&header, sizeof(header))
- .AppendReadable(data, DATA_SIZE)
- .AppendReadable(&status, 0)
- .Build(&desc),
- ZX_OK);
-
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
- ASSERT_EQ(status, 0xff);
-
- END_TEST;
-}
-
-static bool file_block_device_bad_request(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-bad-request.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- // Build a request with an invalid 'type'. The device will handle the
- // request successfully but indicate an error to the driver via the
- // status field in the request.
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t header = {};
- uint8_t data[DATA_SIZE];
- uint8_t status = 0;
- header.type = UINT32_MAX;
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&header, sizeof(header))
- .AppendReadable(data, sizeof(data))
- .AppendWriteable(&status, sizeof(status))
- .Build(&desc),
- ZX_OK);
-
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
- ASSERT_EQ(status, VIRTIO_BLK_S_UNSUPP);
-
- END_TEST;
-}
-
-static bool file_block_device_bad_flush(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-bad-flush.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t req = {};
- req.type = VIRTIO_BLK_T_FLUSH;
- req.sector = 1;
- uint8_t status;
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&req, sizeof(req))
- .AppendWriteable(&status, sizeof(status))
- .Build(&desc),
- ZX_OK);
-
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
- ASSERT_EQ(status, VIRTIO_BLK_S_IOERR);
-
- END_TEST;
-}
-
-static bool file_block_device_read(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-read.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t header = {};
- uint8_t data[DATA_SIZE];
- uint8_t status = 0;
- header.type = VIRTIO_BLK_T_IN;
- memset(data, UINT8_MAX, sizeof(data));
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&header, sizeof(header))
- .AppendWriteable(data, sizeof(data))
- .AppendWriteable(&status, sizeof(status))
- .Build(&desc),
- ZX_OK);
-
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
-
- uint8_t expected[DATA_SIZE];
- ASSERT_EQ(status, VIRTIO_BLK_S_OK);
- memset(expected, 0, DATA_SIZE);
- ASSERT_EQ(memcmp(data, expected, DATA_SIZE), 0);
-
- END_TEST;
-}
-
-static bool file_block_device_read_chain(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-read-chain.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t header = {};
- uint8_t data1[DATA_SIZE];
- uint8_t data2[DATA_SIZE];
- uint8_t status = 0;
- header.type = VIRTIO_BLK_T_IN;
- memset(data1, UINT8_MAX, sizeof(data1));
- memset(data2, UINT8_MAX, sizeof(data2));
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&header, sizeof(header))
- .AppendWriteable(data1, sizeof(data1))
- .AppendWriteable(data2, sizeof(data2))
- .AppendWriteable(&status, sizeof(status))
- .Build(&desc),
- ZX_OK);
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
-
- uint8_t expected[DATA_SIZE];
- memset(expected, 0, DATA_SIZE);
- ASSERT_EQ(status, VIRTIO_BLK_S_OK);
- ASSERT_EQ(memcmp(data1, expected, DATA_SIZE), 0);
- ASSERT_EQ(memcmp(data2, expected, DATA_SIZE), 0);
- ASSERT_EQ(used, sizeof(data1) + sizeof(data2) + sizeof(status));
-
- END_TEST;
-}
-
-static bool file_block_device_write(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-write.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t header = {};
- uint8_t data[DATA_SIZE];
- uint8_t status = 0;
- header.type = VIRTIO_BLK_T_OUT;
- memset(data, UINT8_MAX, sizeof(data));
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&header, sizeof(header))
- .AppendReadable(data, sizeof(data))
- .AppendWriteable(&status, sizeof(status))
- .Build(&desc),
- ZX_OK);
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
-
- int fd = test.fd();
- uint8_t actual[DATA_SIZE];
- ASSERT_EQ(status, VIRTIO_BLK_S_OK);
- ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
- ASSERT_EQ(read(fd, actual, DATA_SIZE), DATA_SIZE);
-
- uint8_t expected[DATA_SIZE];
- memset(expected, UINT8_MAX, DATA_SIZE);
- ASSERT_EQ(memcmp(actual, expected, DATA_SIZE), 0);
-
-
- END_TEST;
-}
-
-static bool file_block_device_write_chain(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-write-chain.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t header = {};
- uint8_t data1[DATA_SIZE];
- uint8_t data2[DATA_SIZE];
- uint8_t status = 0;
- header.type = VIRTIO_BLK_T_OUT;
- memset(data1, UINT8_MAX, sizeof(data1));
- memset(data2, UINT8_MAX, sizeof(data2));
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&header, sizeof(header))
- .AppendReadable(data1, sizeof(data1))
- .AppendReadable(data2, sizeof(data2))
- .AppendWriteable(&status, sizeof(status))
- .Build(&desc),
- ZX_OK);
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
-
- int fd = test.fd();
- uint8_t actual[DATA_SIZE];
- ASSERT_EQ(status, VIRTIO_BLK_S_OK);
- ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
- ASSERT_EQ(read(fd, actual, DATA_SIZE), DATA_SIZE);
-
- uint8_t expected[DATA_SIZE];
- memset(expected, UINT8_MAX, DATA_SIZE);
- ASSERT_EQ(memcmp(actual, expected, DATA_SIZE), 0);
- ASSERT_EQ(used, sizeof(status));
-
- END_TEST;
-}
-
-static bool file_block_device_flush(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-flush.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t header = {};
- header.type = VIRTIO_BLK_T_FLUSH;
- uint8_t status = 0;
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&header, sizeof(header))
- .AppendWriteable(&status, sizeof(status))
- .Build(&desc),
- ZX_OK);
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
- ASSERT_EQ(status, VIRTIO_BLK_S_OK);
-
- END_TEST;
-}
-
-static bool file_block_device_flush_data(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-flush-data.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t header = {};
- uint8_t data[DATA_SIZE];
- uint8_t status = 0;
- header.type = VIRTIO_BLK_T_FLUSH;
- memset(data, UINT8_MAX, sizeof(data));
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&header, sizeof(header))
- .AppendWriteable(data, sizeof(data))
- .AppendWriteable(&status, sizeof(status))
- .Build(&desc),
- ZX_OK);
-
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
- ASSERT_EQ(status, VIRTIO_BLK_S_OK);
- ASSERT_EQ(used, sizeof(status));
-
- END_TEST;
-}
-
-struct TestBlockRequest {
- uint16_t desc;
- uint32_t used;
- virtio_blk_req_t header;
- uint8_t data[DATA_SIZE];
- uint8_t status;
-};
-
-// Queue up 2 read requests for different sectors and verify both will be
-// handled correctly.
-static bool file_block_device_multiple_descriptors(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-multiple-descriptors.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- // Request 1 (descriptors 0,1,2).
- TestBlockRequest request1;
- const uint8_t request1_bitpattern = 0xaa;
- memset(request1.data, UINT8_MAX, DATA_SIZE);
- request1.used = 0;
- request1.header.type = VIRTIO_BLK_T_IN;
- request1.header.sector = 0;
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&request1.header, sizeof(request1.header))
- .AppendWriteable(request1.data, sizeof(request1.data))
- .AppendWriteable(&request1.status, sizeof(request1.status))
- .Build(&request1.desc),
- ZX_OK);
-
- // Request 2 (descriptors 3,4,5).
- TestBlockRequest request2;
- const uint8_t request2_bitpattern = 0xdd;
- memset(request2.data, UINT8_MAX, DATA_SIZE);
- request2.used = 0;
- request2.header.type = VIRTIO_BLK_T_IN;
- request2.header.sector = 1;
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&request2.header, sizeof(request2.header))
- .AppendWriteable(request2.data, sizeof(request2.data))
- .AppendWriteable(&request2.status, sizeof(request2.status))
- .Build(&request2.desc),
- ZX_OK);
-
- // Initalize block device. Write unique bit patterns to sector 1 and 2.
- ASSERT_EQ(test.WriteSector(request1_bitpattern, 0, DATA_SIZE), ZX_OK);
- ASSERT_EQ(test.WriteSector(request2_bitpattern, 1, DATA_SIZE), ZX_OK);
- ASSERT_EQ(
- test.block().HandleBlockRequest(&test.block().queue(), request1.desc, &request1.used),
- ZX_OK);
- ASSERT_EQ(
- test.block().HandleBlockRequest(&test.block().queue(), request2.desc, &request2.used),
- ZX_OK);
-
- // Verify request 1.
- uint8_t expected[DATA_SIZE];
- memset(expected, request1_bitpattern, DATA_SIZE);
- ASSERT_EQ(memcmp(request1.data, expected, DATA_SIZE), 0);
- ASSERT_EQ(request1.status, VIRTIO_BLK_S_OK);
- ASSERT_EQ(request1.used, DATA_SIZE + sizeof(request1.status));
-
- // Verify request 2.
- memset(expected, request2_bitpattern, DATA_SIZE);
- ASSERT_EQ(memcmp(request2.data, expected, DATA_SIZE), 0);
- ASSERT_EQ(request2.status, VIRTIO_BLK_S_OK);
- ASSERT_EQ(request2.used, DATA_SIZE + sizeof(request2.status));
-
- END_TEST;
-}
-
-static bool file_block_device_read_only(void) {
- BEGIN_TEST;
-
- char path[] = "/tmp/file-block-device-read-only.XXXXXX";
- VirtioBlockTest test;
- ASSERT_EQ(test.Init(path), ZX_OK);
-
- uint16_t desc;
- uint32_t used = 0;
- virtio_blk_req_t header = {};
- uint8_t data[DATA_SIZE];
- uint8_t status = 0;
- header.type = VIRTIO_BLK_T_OUT;
- test.block().add_device_features(VIRTIO_BLK_F_RO);
-
- ASSERT_EQ(
- test.queue().BuildDescriptor()
- .AppendReadable(&header, sizeof(header))
- .AppendReadable(data, sizeof(data))
- .AppendWriteable(&status, sizeof(status))
- .Build(&desc),
- ZX_OK);
- ASSERT_EQ(test.block().HandleBlockRequest(&test.block().queue(), desc, &used), ZX_OK);
-
- // No bytes written and error status set.
- ASSERT_EQ(status, VIRTIO_BLK_S_IOERR);
- ASSERT_EQ(used, sizeof(status));
-
- // Read back bytes from the file.
- int fd = test.fd();
- uint8_t actual[DATA_SIZE];
- ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
- ASSERT_EQ(read(fd, actual, DATA_SIZE), DATA_SIZE);
-
- // The image file is initialized to all 0's and we attempted to write all
- // 1's. Verify that the file contents are unchanged.
- uint8_t expected[DATA_SIZE];
- memset(expected, 0, DATA_SIZE);
- ASSERT_EQ(memcmp(actual, expected, DATA_SIZE), 0);
-
- END_TEST;
-}
-
-BEGIN_TEST_CASE(virtio_block)
-RUN_TEST(file_block_device_bad_header)
-RUN_TEST(file_block_device_bad_payload)
-RUN_TEST(file_block_device_bad_status)
-RUN_TEST(file_block_device_bad_request)
-RUN_TEST(file_block_device_bad_flush)
-RUN_TEST(file_block_device_read)
-RUN_TEST(file_block_device_read_chain)
-RUN_TEST(file_block_device_write)
-RUN_TEST(file_block_device_write_chain)
-RUN_TEST(file_block_device_flush)
-RUN_TEST(file_block_device_flush_data)
-RUN_TEST(file_block_device_multiple_descriptors)
-RUN_TEST(file_block_device_read_only)
-END_TEST_CASE(virtio_block)
diff --git a/system/utest/machina/gpu.cpp b/system/utest/machina/gpu.cpp
deleted file mode 100644
index 6c706b6..0000000
--- a/system/utest/machina/gpu.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/gpu.h>
-
-#include <fbl/unique_ptr.h>
-#include <unittest/unittest.h>
-
-#include "virtio_queue_fake.h"
-
-static constexpr uint32_t kDisplayWidth = 1024;
-static constexpr uint32_t kDisplayHeight = 768;
-static constexpr uint32_t kPixelFormat = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM;
-static constexpr uint16_t kQueueSize = 32;
-static constexpr uint32_t kRootResourceId = 1;
-static constexpr uint32_t kScanoutId = 0;
-
-struct BackingPages : public fbl::SinglyLinkedListable<fbl::unique_ptr<BackingPages>> {
- BackingPages(size_t size): buffer(new uint8_t[size]), len(size) {}
-
- fbl::unique_ptr<uint8_t[]> buffer;
- size_t len;
-};
-
-// Scanout that uses an in-memory buffer instead of a framebuffer device.
-class TestScanout : public GpuScanout {
-public:
- TestScanout(uint32_t width, uint32_t height, uint32_t format,
- fbl::unique_ptr<uint8_t[]> buffer)
- : GpuScanout(width, height, format, buffer.get()), fb_(fbl::move(buffer)) {}
-
-private:
- fbl::unique_ptr<uint8_t[]> fb_;
-};
-
-class VirtioGpuTest {
-public:
-
- VirtioGpuTest() : gpu_(0, UINTPTR_MAX), control_queue_(&gpu_.control_queue()) {}
-
- zx_status_t Init() {
- zx_status_t status = control_queue_.Init(kQueueSize);
- if (status != ZX_OK)
- return status;
- return CreateScanout(kDisplayWidth, kDisplayHeight);
- }
-
- VirtioGpu& gpu() { return gpu_; }
-
- VirtioQueueFake& control_queue() { return control_queue_; }
-
- uint8_t* scanout_buffer() const { return scanout_buffer_; }
-
- size_t scanout_size() const { return scanout_size_; }
-
- fbl::SinglyLinkedList<fbl::unique_ptr<BackingPages>>& backing_pages() { return backing_pages_; }
-
- zx_status_t CreateScanout(uint32_t width, uint32_t height) {
- size_t scanout_size = width * height * VirtioGpu::kBytesPerPixel;
- fbl::unique_ptr<uint8_t[]> buffer(new uint8_t[scanout_size]);
- scanout_buffer_ = buffer.get();
- scanout_size_ = scanout_size;
-
- auto scanout = fbl::make_unique<TestScanout>(
- width, height, kPixelFormat, fbl::move(buffer));
- gpu_.AddScanout(fbl::move(scanout));
- return ZX_OK;
- }
-
- zx_status_t CreateRootResource() {
- virtio_gpu_resource_create_2d_t request = {};
- request.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D;
- request.format = kPixelFormat;
- request.resource_id = kRootResourceId;
- request.width = kDisplayWidth;
- request.height = kDisplayHeight;
-
- uint16_t desc = 0;
- virtio_gpu_ctrl_hdr_t response = {};
- zx_status_t status = control_queue().BuildDescriptor()
- .AppendReadable(&request, sizeof(request))
- .AppendWriteable(&response, sizeof(response))
- .Build(&desc);
- if (status != ZX_OK)
- return status;
-
- uint32_t used;
- status = gpu_.HandleGpuCommand(&gpu_.control_queue(), desc, &used);
- if (status != ZX_OK)
- return status;
-
- return response.type == VIRTIO_GPU_RESP_OK_NODATA ? ZX_OK : response.type;
- }
-
- // Attaches a single, contiguous memory region.
- zx_status_t AttachBacking() {
- virtio_gpu_resource_attach_backing_t request = {};
- request.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING;
- request.resource_id = kRootResourceId;
- request.nr_entries = 1;
-
- uint32_t size = kDisplayWidth * kDisplayHeight * VirtioGpu::kBytesPerPixel;
- auto backing = fbl::make_unique<BackingPages>(size);
- virtio_gpu_mem_entry_t entry = {};
- entry.addr = reinterpret_cast<uint64_t>(backing->buffer.get());
- entry.length = size;
- backing_pages_.push_front(fbl::move(backing));
-
- uint16_t desc = 0;
- virtio_gpu_ctrl_hdr_t response = {};
- zx_status_t status = control_queue().BuildDescriptor()
- .AppendReadable(&request, sizeof(request))
- .AppendReadable(&entry, sizeof(entry))
- .AppendWriteable(&response, sizeof(response))
- .Build(&desc);
- if (status != ZX_OK)
- return status;
-
- uint32_t used;
- status = gpu_.HandleGpuCommand(&gpu_.control_queue(), desc, &used);
- if (status != ZX_OK)
- return status;
-
- return response.type == VIRTIO_GPU_RESP_OK_NODATA ? ZX_OK : response.type;
- }
-
- zx_status_t SetScanout() {
- virtio_gpu_set_scanout_t request = {};
- request.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT;
- request.resource_id = kRootResourceId;
- request.scanout_id = kScanoutId;
- request.r.x = 0;
- request.r.y = 0;
- request.r.width = kDisplayWidth;
- request.r.height = kDisplayHeight;
-
- uint16_t desc = 0;
- virtio_gpu_ctrl_hdr_t response = {};
- zx_status_t status = control_queue().BuildDescriptor()
- .AppendReadable(&request, sizeof(request))
- .AppendWriteable(&response, sizeof(response))
- .Build(&desc);
- if (status != ZX_OK)
- return status;
-
- uint32_t used;
- status = gpu_.HandleGpuCommand(&gpu_.control_queue(), desc, &used);
- if (status != ZX_OK)
- return status;
-
- return response.type == VIRTIO_GPU_RESP_OK_NODATA ? ZX_OK : response.type;
- }
-
-private:
- VirtioGpu gpu_;
- VirtioQueueFake control_queue_;
- // Backing pages for the root resource.
- fbl::SinglyLinkedList<fbl::unique_ptr<BackingPages>> backing_pages_;
-
- // A direct pointer into our scanout buffer.
- uint8_t* scanout_buffer_ = nullptr;
- size_t scanout_size_ = 0;
-};
-
-static bool test_get_display_info(void) {
- BEGIN_TEST;
-
- uint16_t desc;
- VirtioGpuTest test;
- ASSERT_EQ(test.Init(), ZX_OK);
-
- virtio_gpu_ctrl_hdr_t request = {};
- virtio_gpu_resp_display_info_t response = {};
- ASSERT_EQ(
- test.control_queue().BuildDescriptor()
- .AppendReadable(&request, sizeof(request))
- .AppendWriteable(&response, sizeof(response))
- .Build(&desc),
- ZX_OK);
-
- uint32_t used = 0;
- request.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO;
- ASSERT_EQ(test.gpu().HandleGpuCommand(&test.gpu().control_queue(), desc, &used), ZX_OK);
-
- EXPECT_EQ(response.hdr.type, VIRTIO_GPU_RESP_OK_DISPLAY_INFO);
- EXPECT_EQ(response.pmodes[0].r.x, 0);
- EXPECT_EQ(response.pmodes[0].r.y, 0);
- EXPECT_EQ(response.pmodes[0].r.width, kDisplayWidth);
- EXPECT_EQ(response.pmodes[0].r.height, kDisplayHeight);
-
- END_TEST;
-}
-
-// Test the basic device initialization sequence.
-static bool test_device_initialization(void) {
- BEGIN_TEST;
-
- VirtioGpuTest test;
- ASSERT_EQ(test.Init(), ZX_OK);
-
- ASSERT_EQ(test.CreateRootResource(), ZX_OK);
- ASSERT_EQ(test.AttachBacking(), ZX_OK);
- ASSERT_EQ(test.SetScanout(), ZX_OK);
-
- END_TEST;
-}
-
-static bool test_set_scanout_invalid_resource_id(void) {
- BEGIN_TEST;
-
- VirtioGpuTest test;
- ASSERT_EQ(test.Init(), ZX_OK);
-
- ASSERT_EQ(test.CreateRootResource(), ZX_OK);
- ASSERT_EQ(test.AttachBacking(), ZX_OK);
-
- virtio_gpu_set_scanout_t request = {};
- request.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT;
- request.resource_id = 123;
- request.scanout_id = kScanoutId;
- request.r.x = 0;
- request.r.y = 0;
- request.r.width = kDisplayWidth;
- request.r.height = kDisplayHeight;
-
- uint16_t desc = 0;
- virtio_gpu_ctrl_hdr_t response = {};
- ASSERT_EQ(
- test.control_queue().BuildDescriptor()
- .AppendReadable(&request, sizeof(request))
- .AppendWriteable(&response, sizeof(response))
- .Build(&desc),
- ZX_OK);
-
- uint32_t used;
- ASSERT_EQ(test.gpu().HandleGpuCommand(&test.gpu().control_queue(), desc, &used), ZX_OK);
- ASSERT_EQ(response.type, VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID);
-
- return response.type == VIRTIO_GPU_RESP_OK_NODATA ? ZX_OK : response.type;
-
- END_TEST;
-}
-
-// Verify a basic transfer 2d command correctly fills in the scanout.
-static bool test_fill_display(void) {
- BEGIN_TEST;
-
- VirtioGpuTest test;
- ASSERT_EQ(test.Init(), ZX_OK);
-
- ASSERT_EQ(test.CreateRootResource(), ZX_OK);
- ASSERT_EQ(test.AttachBacking(), ZX_OK);
- ASSERT_EQ(test.SetScanout(), ZX_OK);
-
- virtio_gpu_transfer_to_host_2d_t request = {};
- request.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D;
- request.resource_id = kRootResourceId;
- request.r.x = 0;
- request.r.y = 0;
- request.r.width = kDisplayWidth;
- request.r.height = kDisplayHeight;
-
- uint16_t desc = 0;
- virtio_gpu_ctrl_hdr_t response = {};
- ASSERT_EQ(
- test.control_queue().BuildDescriptor()
- .AppendReadable(&request, sizeof(request))
- .AppendWriteable(&response, sizeof(response))
- .Build(&desc),
- ZX_OK);
-
-
- // Initialize the scanout to 0x00 and write 0xff to the backing pages.
- // A transfer 2d command will copy the 0xff into the scanout buffer.
- memset(test.scanout_buffer(), 0, test.scanout_size());
- for (const auto& entry : test.backing_pages()) {
- memset(entry.buffer.get(), 0xff, entry.len);
- }
-
- uint32_t used;
- ASSERT_EQ(test.gpu().HandleGpuCommand(&test.gpu().control_queue(), desc, &used), ZX_OK);
- ASSERT_EQ(response.type, VIRTIO_GPU_RESP_OK_NODATA);
-
- // Verify backing/scanout are now in sync.
- size_t offset = 0;
- for (const auto& entry : test.backing_pages()) {
- ASSERT_EQ(memcmp(entry.buffer.get(), test.scanout_buffer() + offset, entry.len), 0);
- offset += entry.len;
- }
-
- END_TEST;
-}
-
-BEGIN_TEST_CASE(virtio_gpu)
-RUN_TEST(test_get_display_info);
-RUN_TEST(test_device_initialization);
-RUN_TEST(test_set_scanout_invalid_resource_id);
-RUN_TEST(test_fill_display);
-END_TEST_CASE(virtio_gpu)
diff --git a/system/utest/machina/input.cpp b/system/utest/machina/input.cpp
deleted file mode 100644
index f057dc8..0000000
--- a/system/utest/machina/input.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <fbl/vector.h>
-#include <hid/hid.h>
-#include <hid/usages.h>
-#include <machina/input.h>
-
-#include <unittest/unittest.h>
-
-// Yanked from system/ulib/hid/hid.c
-#define KEYSET(bitmap, n) (bitmap[(n) >> 5] |= (1 << ((n)&31)))
-#define KEYCLR(bitmap, n) (bitmap[(n) >> 5] &= ~(1 << ((n)&31)))
-
-static const hid_keys_t kAllKeysUp = {};
-
-/* Event emitter that records all queued events for verification purposes. */
-class FakeEventEmitter : public VirtioInputEventEmitter {
-public:
- virtual zx_status_t QueueInputEvent(const virtio_input_event_t& event) override {
- if (flushed_) {
- fprintf(stderr, "FakeEventEmitter has been flushed. Call Reset() to queue more "
- "events.\n");
- return ZX_ERR_BAD_STATE;
- }
- queued_events_.push_back(event);
- return ZX_OK;
- }
-
- virtual zx_status_t FlushInputEvents() override {
- flushed_ = true;
- return ZX_OK;
- }
-
- void Reset() {
- flushed_ = false;
- queued_events_.reset();
- }
-
- size_t events() { return queued_events_.size(); }
-
- virtio_input_event_t event(size_t index) {
- return queued_events_[index];
- }
-
- // Check for an evdev event between |min| and |max| inclusive in the
- // output stream.
- bool HasEvent(size_t min, size_t max, uint16_t type, uint16_t code, uint32_t value) {
- for (size_t i = min; i < max + 1 && i < queued_events_.size(); ++i) {
- auto event = queued_events_[i];
- if (event.type == type && event.value == value && event.code == code) {
- return true;
- }
- }
- return false;
- }
-
- bool HasKeyPress(size_t min, size_t max, uint16_t usage) {
- uint16_t code = KeyboardEventSource::kKeyMap[usage];
- return HasEvent(min, max, VIRTIO_INPUT_EV_KEY, code, VIRTIO_INPUT_EV_KEY_PRESSED);
- }
-
- bool HasKeyRelease(size_t min, size_t max, uint16_t usage) {
- uint16_t code = KeyboardEventSource::kKeyMap[usage];
- return HasEvent(min, max, VIRTIO_INPUT_EV_KEY, code, VIRTIO_INPUT_EV_KEY_RELEASED);
- }
-
- bool HasBarrier(size_t index) {
- return HasEvent(index, index, VIRTIO_INPUT_EV_SYN, 0, 0);
- }
-
-private:
- bool flushed_ = false;
- fbl::Vector<virtio_input_event_t> queued_events_;
-};
-
-static bool test_key_press(void) {
- BEGIN_TEST;
-
- FakeEventEmitter emitter;
- KeyboardEventSource keyboard(&emitter, 0);
-
- // Set 'A' as pressed.
- hid_keys_t keys = {};
- KEYSET(keys.keymask, HID_USAGE_KEY_A);
-
- ASSERT_EQ(keyboard.HandleHidKeys(keys), ZX_OK);
-
- ASSERT_EQ(emitter.events(), 2);
- EXPECT_TRUE(emitter.HasKeyPress(0, 0, HID_USAGE_KEY_A));
- EXPECT_TRUE(emitter.HasBarrier(1));
-
- END_TEST;
-}
-
-static bool test_key_press_multiple(void) {
- BEGIN_TEST;
-
- FakeEventEmitter emitter;
- KeyboardEventSource keyboard(&emitter, 0);
-
- // Set 'ABCD' as pressed.
- hid_keys_t keys = {};
- KEYSET(keys.keymask, HID_USAGE_KEY_A);
- KEYSET(keys.keymask, HID_USAGE_KEY_B);
- KEYSET(keys.keymask, HID_USAGE_KEY_C);
- KEYSET(keys.keymask, HID_USAGE_KEY_D);
-
- ASSERT_EQ(keyboard.HandleHidKeys(keys), ZX_OK);
-
- ASSERT_EQ(emitter.events(), 5);
- EXPECT_TRUE(emitter.HasKeyPress(0, 3, HID_USAGE_KEY_A));
- EXPECT_TRUE(emitter.HasKeyPress(0, 3, HID_USAGE_KEY_B));
- EXPECT_TRUE(emitter.HasKeyPress(0, 3, HID_USAGE_KEY_C));
- EXPECT_TRUE(emitter.HasKeyPress(0, 3, HID_USAGE_KEY_D));
- EXPECT_TRUE(emitter.HasBarrier(4));
-
- END_TEST;
-}
-
-static bool test_key_release(void) {
- BEGIN_TEST;
-
- FakeEventEmitter emitter;
- KeyboardEventSource keyboard(&emitter, 0);
-
- // Initialize with 'A' key pressed.
- hid_keys_t key_pressed_keys = {};
- KEYSET(key_pressed_keys.keymask, HID_USAGE_KEY_A);
- ASSERT_EQ(keyboard.HandleHidKeys(key_pressed_keys), ZX_OK);
- emitter.Reset();
-
- // Release all keys.
- ASSERT_EQ(keyboard.HandleHidKeys(kAllKeysUp), ZX_OK);
-
- ASSERT_EQ(emitter.events(), 2);
- EXPECT_TRUE(emitter.HasKeyRelease(0, 0, HID_USAGE_KEY_A));
- EXPECT_TRUE(emitter.HasBarrier(1));
-
- END_TEST;
-}
-
-static bool test_key_release_multiple(void) {
- BEGIN_TEST;
-
- FakeEventEmitter emitter;
- KeyboardEventSource keyboard(&emitter, 0);
-
- // Set 'ABCD' as pressed.
- hid_keys_t keys = {};
- KEYSET(keys.keymask, HID_USAGE_KEY_A);
- KEYSET(keys.keymask, HID_USAGE_KEY_B);
- KEYSET(keys.keymask, HID_USAGE_KEY_C);
- KEYSET(keys.keymask, HID_USAGE_KEY_D);
- ASSERT_EQ(keyboard.HandleHidKeys(keys), ZX_OK);
- emitter.Reset();
-
- // Release all keys.
- ASSERT_EQ(keyboard.HandleHidKeys(kAllKeysUp), ZX_OK);
-
- ASSERT_EQ(emitter.events(), 5);
- EXPECT_TRUE(emitter.HasKeyRelease(0, 3, HID_USAGE_KEY_A));
- EXPECT_TRUE(emitter.HasKeyRelease(0, 3, HID_USAGE_KEY_B));
- EXPECT_TRUE(emitter.HasKeyRelease(0, 3, HID_USAGE_KEY_C));
- EXPECT_TRUE(emitter.HasKeyRelease(0, 3, HID_USAGE_KEY_D));
- EXPECT_TRUE(emitter.HasBarrier(4));
-
- END_TEST;
-}
-
-// Test keys both being pressed and released in a single HID report.
-static bool test_key_press_and_release(void) {
- BEGIN_TEST;
-
- FakeEventEmitter emitter;
- KeyboardEventSource keyboard(&emitter, 0);
-
- // Set 'AB' as pressed.
- hid_keys_t keys_ab = {};
- KEYSET(keys_ab.keymask, HID_USAGE_KEY_A);
- KEYSET(keys_ab.keymask, HID_USAGE_KEY_B);
- ASSERT_EQ(keyboard.HandleHidKeys(keys_ab), ZX_OK);
- emitter.Reset();
-
- // Release 'AB' and press 'CD'.
- hid_keys_t keys_cd = {};
- KEYSET(keys_cd.keymask, HID_USAGE_KEY_C);
- KEYSET(keys_cd.keymask, HID_USAGE_KEY_D);
- ASSERT_EQ(keyboard.HandleHidKeys(keys_cd), ZX_OK);
-
- ASSERT_EQ(emitter.events(), 5);
- EXPECT_TRUE(emitter.HasKeyPress(0, 3, HID_USAGE_KEY_C));
- EXPECT_TRUE(emitter.HasKeyPress(0, 3, HID_USAGE_KEY_D));
- EXPECT_TRUE(emitter.HasKeyRelease(0, 3, HID_USAGE_KEY_A));
- EXPECT_TRUE(emitter.HasKeyRelease(0, 3, HID_USAGE_KEY_B));
- EXPECT_TRUE(emitter.HasBarrier(4));
-
- END_TEST;
-}
-
-BEGIN_TEST_CASE(virtio_input)
-RUN_TEST(test_key_press);
-RUN_TEST(test_key_press_multiple);
-RUN_TEST(test_key_release);
-RUN_TEST(test_key_release_multiple);
-RUN_TEST(test_key_press_and_release);
-END_TEST_CASE(virtio_input)
diff --git a/system/utest/machina/main.cpp b/system/utest/machina/main.cpp
deleted file mode 100644
index ed1a365..0000000
--- a/system/utest/machina/main.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <unittest/unittest.h>
-
-int main(int argc, char** argv) {
- return unittest_run_all_tests(argc, argv) ? 0 : -1;
-}
diff --git a/system/utest/machina/pci.cpp b/system/utest/machina/pci.cpp
deleted file mode 100644
index 0602422..0000000
--- a/system/utest/machina/pci.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/pci.h>
-
-#include <hw/pci.h>
-#include <hypervisor/bits.h>
-#include <unittest/unittest.h>
-
-#define PCI_CONFIG_ADDRESS_PORT_BASE 0
-#define PCI_CONFIG_DATA_PORT_BASE 4
-
-#define PCI_TYPE1_ADDR(bus, device, function, reg) \
- (0x80000000 | ((bus) << 16) | ((device) << 11) | ((function) << 8) | \
- ((reg)&PCI_TYPE1_REGISTER_MASK))
-
-/* Test we can read multiple fields in 1 32-bit word. */
-static bool pci_device_read_config_register(void) {
- BEGIN_TEST;
-
- Guest guest;
- PciBus bus(&guest, nullptr);
- bus.Init();
- PciDevice& device = bus.root_complex();
-
- // Access Vendor/Device ID as a single 32bit read.
- IoValue value = {};
- value.access_size = 4;
- EXPECT_EQ(device.ReadConfig(PCI_CONFIG_VENDOR_ID, &value), ZX_OK,
- "Failed to read PCI_CONFIG_VENDOR_ID");
- EXPECT_EQ(value.u32, PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35 << 16),
- "Unexpected value of PCI_CONFIG_VENDOR_ID");
-
- END_TEST;
-}
-
-/* Verify we can read portions of a 32 bit word, one byte at a time. */
-static bool pci_device_read_config_register_bytewise(void) {
- BEGIN_TEST;
-
- Guest guest;
- PciBus bus(&guest, nullptr);
- bus.Init();
- PciDevice& device = bus.root_complex();
-
- uint32_t expected_device_vendor = PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35 << 16);
- for (int i = 0; i < 4; ++i) {
- uint16_t reg = static_cast<uint16_t>(PCI_CONFIG_VENDOR_ID + i);
- IoValue value = {};
- value.access_size = 1;
- EXPECT_EQ(device.ReadConfig(reg, &value), ZX_OK,
- "Failed to read PCI_CONFIG_VENDOR_ID");
- EXPECT_EQ(value.u32, bits_shift(expected_device_vendor, i * 8 + 7, i * 8),
- "Unexpected value of PCI_CONFIG_VENDOR_ID");
- }
-
- END_TEST;
-}
-
-/* PCI devices BAR sizes must be a power of 2 and must not support setting any
- * bits in the BAR that are not size aligned. Software often relies on this to
- * read the bar size by writing all 1's to the register and reading back the
- * value.
- *
- * This tests that we properly mask the lowest bits so software can compute the
- * BAR size.
- */
-static bool pci_device_read_bar_size(void) {
- BEGIN_TEST;
-
- Guest guest;
- PciBus bus(&guest, nullptr);
- bus.Init();
- PciDevice& device = bus.root_complex();
-
- // Set all bits in the BAR register. The device will ignore writes to the
- // LSBs which we can read out to determine the size.
- IoValue value;
- value.access_size = 4;
- value.u32 = UINT32_MAX;
- EXPECT_EQ(device.WriteConfig(PCI_CONFIG_BASE_ADDRESSES, value), ZX_OK,
- "Failed to write BAR0 to PCI config space");
-
- // Read out BAR and compute size.
- value.access_size = 4;
- value.u32 = 0;
- EXPECT_EQ(device.ReadConfig(PCI_CONFIG_BASE_ADDRESSES, &value), ZX_OK,
- "Failed to read BAR0 from PCI config space");
- EXPECT_EQ(value.u32 & PCI_BAR_ASPACE_MASK, PCI_BAR_ASPACE_MMIO,
- "Expected PIO bit to be set in BAR");
- const PciBar* bar = device.bar(0);
- ASSERT_NOT_NULL(bar);
- EXPECT_EQ(~(value.u32 & ~PCI_BAR_ASPACE_MASK) + 1, bar->size,
- "Incorrect bar size read from pci device");
-
- END_TEST;
-}
-
-/* Verify stats & cap registers correctly show present capabilities and that
- * capability data is readable.
- */
-static bool pci_device_read_cap_basic(void) {
- BEGIN_TEST;
-
- Guest guest;
- PciBus bus(&guest, nullptr);
- bus.Init();
- PciDevice& device = bus.root_complex();
-
- // Create and install a simple capability. First two bytes are ignored.
- uint8_t cap_data[] = {0, 0, 0xf, 0xa};
- pci_cap_t cap = {
- .id = 0x9,
- .data = cap_data,
- .len = sizeof(cap_data),
- };
- device.set_capabilities(&cap, 1);
-
- // PCI Local Bus Spec 3.0 Table 6-2: Status Register Bits
- //
- // This optional read-only bit indicates whether or not this device
- // implements the pointer for a New Capabilities linked list at offset 34h.
- // A value of zero indicates that no New Capabilities linked list is
- // available. A value of one indicates that the value read at offset 34h is
- // a pointer in Configuration Space to a linked list of new capabilities.
- // Refer to Section 6.7 for details on New Capabilities.
- IoValue status;
- status.access_size = 2;
- status.u16 = 0;
- EXPECT_EQ(device.ReadConfig(PCI_CONFIG_STATUS, &status), ZX_OK,
- "Failed to read status register from PCI config space.\n");
- EXPECT_TRUE(status.u16 & PCI_STATUS_NEW_CAPS,
- "CAP bit not set in status register with a cap list present.\n");
-
- // Read the cap pointer from config space. Here just verify it points to
- // some location beyond the pre-defined header.
- IoValue cap_ptr;
- cap_ptr.access_size = 1;
- cap_ptr.u8 = 0;
- EXPECT_EQ(device.ReadConfig(PCI_CONFIG_CAPABILITIES, &cap_ptr), ZX_OK,
- "Failed to read CAP pointer from PCI config space.\n");
- EXPECT_LT(0x40u, cap_ptr.u8, "CAP pointer does not lie beyond the reserved region.\n");
-
- // Read the capability. This will be the Cap ID, next pointer (0), followed
- // by data bytes (starting at index 2).
- IoValue cap_value;
- cap_value.access_size = 4;
- cap_value.u32 = 0;
- EXPECT_EQ(device.ReadConfig(cap_ptr.u8, &cap_value), ZX_OK,
- "Failed to read CAP value from PCI config space.\n");
- EXPECT_EQ(0x0a0f0009u, cap_value.u32,
- "Incorrect CAP value read from PCI config space.\n");
-
- END_TEST;
-}
-
-/* Build a list of capabilities with no data (only the required ID/next
- * fields). Verify the next pointers are correctly wired up to traverse
- * the linked list.
- */
-static bool pci_device_read_cap_chained(void) {
- BEGIN_TEST;
-
- Guest guest;
- PciBus bus(&guest, nullptr);
- bus.Init();
- PciDevice& device = bus.root_complex();
-
- // Build list of caps.
- pci_cap_t caps[5];
- size_t num_caps = sizeof(caps) / sizeof(caps[0]);
- for (uint8_t i = 0; i < num_caps; ++i) {
- caps[i].id = i;
- caps[i].len = 2;
- }
- device.set_capabilities(caps, num_caps);
-
- IoValue cap_ptr;
- cap_ptr.access_size = 1;
- cap_ptr.u8 = 0;
- EXPECT_EQ(device.ReadConfig(PCI_CONFIG_CAPABILITIES, &cap_ptr), ZX_OK,
- "Failed to read CAP pointer from PCI config space.\n");
- for (uint8_t i = 0; i < num_caps; ++i) {
- IoValue cap_header;
- cap_header.access_size = 4;
- cap_header.u32 = 0;
-
- // Read the current capability.
- EXPECT_EQ(device.ReadConfig(cap_ptr.u8, &cap_header), ZX_OK,
- "Failed to read CAP from PCI config space.\n");
- // ID is the first byte.
- EXPECT_EQ(i, cap_header.u32 & UINT8_MAX, "Incorrect CAP ID read.\n");
- // Next pointer is the second byte.
- cap_ptr.u8 = static_cast<uint8_t>(cap_header.u32 >> 8);
- }
- EXPECT_EQ(0u, cap_ptr.u8, "Failed to read CAP pointer from PCI config space.\n");
-
- END_TEST;
-}
-
-/* Test accesses to the PCI config address ports.
- *
- * Access to the 32-bit PCI config address port is provided by the IO ports
- * 0xcf8 - 0xcfb. Accesses to each port must have the same alignment as the
- * port address used.
- *
- * The device operates on relative port addresses so we'll use 0-3 instead of
- * 0cf8-0xcfb
- *
- * Ex:
- * -------------------------------------
- * | port | valid access widths (bytes) |
- * --------------------------------------|
- * | 0 | 1, 2, 4 |
- * | 1 | 1 |
- * | 2 | 1, 2 |
- * | 3 | 1 |
- * -------------------------------------
- */
-static bool pci_bus_write_config_addr_port(void) {
- BEGIN_TEST;
-
- Guest guest;
- PciBus bus(&guest, nullptr);
- bus.Init();
-
- // 32 bit write.
- IoValue value;
- value.access_size = 4;
- value.u32 = 0x12345678;
- EXPECT_EQ(bus.WriteIoPort(PCI_CONFIG_ADDRESS_PORT_BASE, value), ZX_OK);
- EXPECT_EQ(bus.config_addr(), 0x12345678u);
-
- // 16 bit write to bits 31..16. Other bits remain unchanged.
- value.access_size = 2;
- value.u16 = 0xFACE;
- EXPECT_EQ(bus.WriteIoPort(PCI_CONFIG_ADDRESS_PORT_BASE + 2, value), ZX_OK);
- EXPECT_EQ(bus.config_addr(), 0xFACE5678u);
-
- // 8 bit write to bits (15..8). Other bits remain unchanged.
- value.access_size = 1;
- value.u8 = 0x99;
- EXPECT_EQ(bus.WriteIoPort(PCI_CONFIG_ADDRESS_PORT_BASE + 1, value), ZX_OK);
- EXPECT_EQ(bus.config_addr(), 0xFACE9978u);
-
- END_TEST;
-}
-
-/* Test reading the PCI config address ports.
- *
- * See pci_bus_write_config_addr_port for more details.
- */
-static bool pci_bus_read_config_addr_port(void) {
- BEGIN_TEST;
-
- Guest guest;
- PciBus bus(&guest, nullptr);
- bus.Init();
- bus.set_config_addr(0x12345678);
-
- // 32 bit read (bits 31..0).
- IoValue value = {};
- value.access_size = 4;
- EXPECT_EQ(bus.ReadIoPort(PCI_CONFIG_ADDRESS_PORT_BASE, &value), ZX_OK);
- EXPECT_EQ(value.access_size, 4, "Incorrect IO access_size");
- EXPECT_EQ(value.u32, 0x12345678u, "Incorrect address read from PCI address port");
-
- // 16 bit read (bits 31..16).
- value.access_size = 2;
- value.u16 = 0;
- EXPECT_EQ(bus.ReadIoPort(PCI_CONFIG_ADDRESS_PORT_BASE + 2, &value), ZX_OK);
- EXPECT_EQ(value.access_size, 2, "Incorrect IO access_size");
- EXPECT_EQ(value.u16, 0x1234u, "Incorrect address read from PCI address port");
-
- // 8 bit read (bits 15..8).
- value.access_size = 1;
- value.u8 = 0;
- EXPECT_EQ(bus.ReadIoPort(PCI_CONFIG_ADDRESS_PORT_BASE + 1, &value), ZX_OK);
- EXPECT_EQ(value.access_size, 1, "Incorrect IO access_size");
- EXPECT_EQ(value.u8, 0x56u, "Incorrect address read from PCI address port");
-
- END_TEST;
-}
-
-/* The address written to the data port (0xcf8) is 4b aligned. The offset into
- * the data port range 0xcfc-0xcff is added to the address to access partial
- * words.
- */
-static bool pci_bus_read_config_data_port(void) {
- BEGIN_TEST;
-
- Guest guest;
- PciBus bus(&guest, nullptr);
- bus.Init();
- IoValue value = {};
-
- // 16-bit read.
- bus.set_config_addr(PCI_TYPE1_ADDR(0, 0, 0, 0));
- value.access_size = 2;
- EXPECT_EQ(bus.ReadIoPort(PCI_CONFIG_DATA_PORT_BASE, &value), ZX_OK);
- EXPECT_EQ(value.access_size, 2, "Incorrect IO access_size");
- EXPECT_EQ(value.u16, PCI_VENDOR_ID_INTEL, "Incorrect value read from PCI data port");
-
- // 32-bit read from same address. Result should now contain the Device ID
- // in the upper 16 bits
- value.access_size = 4;
- value.u32 = 0;
- EXPECT_EQ(bus.ReadIoPort(PCI_CONFIG_DATA_PORT_BASE, &value), ZX_OK);
- EXPECT_EQ(value.access_size, 4, "Incorrect IO access_size");
- EXPECT_EQ(value.u32, PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35 << 16),
- "Incorrect value read from PCI data port");
-
- // 16-bit read of upper half-word.
- //
- // Device ID is 2b aligned and the PCI config address register can only hold
- // a 4b aligned address. The offset into the word addressed by the PCI
- // address port is added to the data port address.
- value.access_size = 2;
- value.u16 = 0;
- bus.set_config_addr(PCI_TYPE1_ADDR(0, 0, 0, PCI_CONFIG_DEVICE_ID));
- // Verify we're using a 4b aligned register address.
- EXPECT_EQ(bus.config_addr() & bit_mask<uint32_t>(2), 0u);
- // Add the register offset to the data port base address.
- EXPECT_EQ(
- bus.ReadIoPort(
- PCI_CONFIG_DATA_PORT_BASE + (PCI_CONFIG_DEVICE_ID & bit_mask<uint32_t>(2)),
- &value),
- ZX_OK);
- EXPECT_EQ(value.access_size, 2, "Incorrect IO access_size");
- EXPECT_EQ(value.u16, PCI_DEVICE_ID_INTEL_Q35, "Incorrect value read from PCI data port");
-
- END_TEST;
-}
-
-BEGIN_TEST_CASE(pci)
-RUN_TEST(pci_device_read_config_register)
-RUN_TEST(pci_device_read_config_register_bytewise)
-RUN_TEST(pci_device_read_bar_size)
-RUN_TEST(pci_device_read_cap_basic)
-RUN_TEST(pci_device_read_cap_chained)
-RUN_TEST(pci_bus_write_config_addr_port)
-RUN_TEST(pci_bus_read_config_addr_port)
-RUN_TEST(pci_bus_read_config_data_port)
-END_TEST_CASE(pci)
diff --git a/system/utest/machina/rules.mk b/system/utest/machina/rules.mk
deleted file mode 100644
index 665e1f5..0000000
--- a/system/utest/machina/rules.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2017 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-LOCAL_DIR := $(GET_LOCAL_DIR)
-
-MODULE := $(LOCAL_DIR)
-
-MODULE_NAME := machina-test
-
-MODULE_TYPE := usertest
-
-MODULE_SRCS += \
- $(LOCAL_DIR)/block.cpp \
- $(LOCAL_DIR)/gpu.cpp \
- $(LOCAL_DIR)/input.cpp \
- $(LOCAL_DIR)/main.cpp \
- $(LOCAL_DIR)/pci.cpp \
- $(LOCAL_DIR)/virtio_queue.cpp \
- $(LOCAL_DIR)/virtio_queue_fake.cpp \
-
-MODULE_HEADER_DEPS := \
- system/ulib/ddk \
- system/ulib/hid \
- system/ulib/virtio \
-
-MODULE_LIBS := \
- system/ulib/c \
- system/ulib/fdio \
- system/ulib/machina \
- system/ulib/unittest \
- system/ulib/zircon \
-
-MODULE_STATIC_LIBS := \
- system/ulib/fbl \
- system/ulib/hypervisor \
- system/ulib/zx \
-
-MODULE_CPPFLAGS := \
- -Isystem/ulib/hypervisor/arch/$(ARCH)/include \
- -Isystem/ulib/machina/arch/$(ARCH)/include \
-
-include make/module.mk
diff --git a/system/utest/machina/virtio_queue.cpp b/system/utest/machina/virtio_queue.cpp
deleted file mode 100644
index 199f1d5..0000000
--- a/system/utest/machina/virtio_queue.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <machina/virtio.h>
-#include <unittest/unittest.h>
-
-#include "virtio_queue_fake.h"
-
-#define QUEUE_SIZE 16
-
-#define VIRTIO_TEST_ID 30
-
-class TestDevice : public VirtioDevice {
-public:
- TestDevice()
- : VirtioDevice(VIRTIO_TEST_ID, nullptr, 0, &queue_, 1, 0, UINTPTR_MAX),
- queue_fake_(&queue_) {}
-
- zx_status_t Init() {
- return queue_fake_.Init(QUEUE_SIZE);
- }
-
- virtio_queue_t& queue() { return queue_; }
- VirtioQueueFake& queue_fake() { return queue_fake_; }
-
-private:
- virtio_queue_t queue_;
- VirtioQueueFake queue_fake_;
-};
-
-static bool test_virtio_queue_overflow(void) {
- BEGIN_TEST;
-
- TestDevice device;
- ASSERT_EQ(device.Init(), ZX_OK);
- virtio_queue_t& queue = device.queue();
- VirtioQueueFake& queue_fake = device.queue_fake();
-
- // Setup queu pointers so that the next descriptor will wrap avail->idx
- // to 0.
- queue.avail->idx = UINT16_MAX;
- queue.index = UINT16_MAX;
-
- uint16_t expected_desc;
- uint32_t data = 0x12345678;
- ASSERT_EQ(
- queue_fake.BuildDescriptor()
- .AppendReadable(&data, sizeof(data))
- .Build(&expected_desc),
- ZX_OK);
-
- uint16_t desc;
- ASSERT_EQ(virtio_queue_next_avail(&queue, &desc), ZX_OK);
- ASSERT_EQ(desc, expected_desc);
- ASSERT_EQ(queue.avail->idx, 0);
- ASSERT_EQ(queue.index, 0);
- END_TEST;
-}
-
-BEGIN_TEST_CASE(virtio_queue)
-RUN_TEST(test_virtio_queue_overflow);
-END_TEST_CASE(virtio_queue)
diff --git a/system/utest/machina/virtio_queue_fake.cpp b/system/utest/machina/virtio_queue_fake.cpp
deleted file mode 100644
index b43a5f1..0000000
--- a/system/utest/machina/virtio_queue_fake.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "virtio_queue_fake.h"
-
-#include <string.h>
-
-#include <fbl/alloc_checker.h>
-
-zx_status_t VirtioQueueFake::Init(uint16_t queue_size) {
- fbl::unique_ptr<uint8_t[]> desc;
- fbl::unique_ptr<uint8_t[]> avail;
- fbl::unique_ptr<uint8_t[]> used;
-
- {
- fbl::AllocChecker ac;
- size_t desc_size = queue_->size * sizeof(queue_->desc[0]);
- desc.reset(new (&ac) uint8_t[desc_size]);
- if (!ac.check())
- return ZX_ERR_NO_MEMORY;
- memset(desc.get(), 0, desc_size);
- }
-
- {
- fbl::AllocChecker ac;
- size_t avail_size = sizeof(*queue_->avail) +
- (queue_->size * sizeof(queue_->avail->ring[0])) +
- sizeof(*queue_->used_event);
- avail.reset(new (&ac) uint8_t[avail_size]);
- if (!ac.check())
- return ZX_ERR_NO_MEMORY;
- memset(avail.get(), 0, avail_size);
- }
-
- {
- fbl::AllocChecker ac;
- size_t used_size = sizeof(*queue_->used) + (queue_->size * sizeof(queue_->used->ring[0])) +
- sizeof(*queue_->avail_event);
- used.reset(new (&ac) uint8_t[used_size]);
- if (!ac.check())
- return ZX_ERR_NO_MEMORY;
- memset(used.get(), 0,used_size);
- }
-
- queue_size_ = queue_size;
- desc_buf_ = fbl::move(desc);
- avail_ring_buf_ = fbl::move(avail);
- used_ring_buf_ = fbl::move(used);
-
- queue_->size = queue_size;
- virtio_queue_set_desc_addr(queue_, reinterpret_cast<uint64_t>(desc_buf_.get()));
- virtio_queue_set_avail_addr(queue_, reinterpret_cast<uint64_t>(avail_ring_buf_.get()));
- virtio_queue_set_used_addr(queue_, reinterpret_cast<uint64_t>(used_ring_buf_.get()));
- return ZX_OK;
-}
-
-VirtioQueueFake::~VirtioQueueFake() {
- queue_->addr.desc = 0;
- queue_->desc = nullptr;
- queue_->addr.avail = 0;
- queue_->avail = nullptr;
- queue_->addr.used = 0;
- queue_->used = nullptr;
-}
-
-zx_status_t VirtioQueueFake::SetNext(uint16_t desc_index, uint16_t next_index) {
- if (desc_index >= queue_size_)
- return ZX_ERR_INVALID_ARGS;
- if (next_index >= queue_size_)
- return ZX_ERR_INVALID_ARGS;
-
- volatile vring_desc& desc = queue_->desc[desc_index];
- desc.flags |= VRING_DESC_F_NEXT;
- desc.next = next_index;
- return ZX_OK;
-}
-
-zx_status_t VirtioQueueFake::WriteDescriptor(void* buf, size_t len, uint16_t flags,
- uint16_t* desc_out) {
- uint16_t desc_index = next_free_desc_;
- if (desc_index >= queue_size_)
- return ZX_ERR_NO_MEMORY;
-
- next_free_desc_++;
-
- volatile vring_desc& desc = queue_->desc[desc_index];
- desc.addr = reinterpret_cast<uint64_t>(buf);
- desc.len = static_cast<uint32_t>(len);
- desc.flags = flags;
-
- if (desc_out != nullptr)
- *desc_out = desc_index;
- return ZX_OK;
-}
-
-void VirtioQueueFake::WriteToAvail(uint16_t desc) {
- queue_->avail->ring[queue_->avail->idx++ % queue_size_] = desc;
-}
-
-zx_status_t DescBuilder::Build(uint16_t* desc) {
- if (status_ == ZX_OK) {
- queue_->WriteToAvail(head_desc_);
- if (desc != nullptr)
- *desc = head_desc_;
- head_desc_ = 0;
- prev_desc_ = 0;
- len_ = 0;
- }
- return status_;
-}
-
-DescBuilder& DescBuilder::Append(void* buf, size_t buf_len, bool write) {
- // If a previous Append operation failed just no-op.
- if (status_ != ZX_OK)
- return *this;
-
- uint16_t flags = write ? VRING_DESC_F_WRITE : 0;
- uint16_t desc;
- status_ = queue_->WriteDescriptor(buf, buf_len, flags, &desc);
- if (status_ == ZX_OK) {
- if (len_++ == 0) {
- head_desc_ = desc;
- } else {
- status_ = queue_->SetNext(prev_desc_, desc);
- }
-
- prev_desc_ = desc;
- }
-
- return *this;
-}
diff --git a/system/utest/machina/virtio_queue_fake.h b/system/utest/machina/virtio_queue_fake.h
deleted file mode 100644
index fcd15bb..0000000
--- a/system/utest/machina/virtio_queue_fake.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <fbl/unique_ptr.h>
-#include <machina/virtio.h>
-#include <virtio/virtio.h>
-#include <virtio/virtio_ring.h>
-
-class VirtioQueueFake;
-
-// Helper class for building buffer made up of chained descriptors.
-//
-// When building a descriptor chain, any errors are deferred until a call to
-// DescBuilder::Build in order to make the interface more fluent.
-class DescBuilder {
-public:
- DescBuilder& Append(void* addr, size_t size, bool writeable);
- DescBuilder& Append(uintptr_t addr, size_t size, bool writeable) {
- return Append(reinterpret_cast<void*>(addr), size, writeable);
- }
-
- // Adds a buffer to the chain that is flagged as device writeable.
- DescBuilder& AppendWriteable(void* addr, size_t size) { return Append(addr, size, true); }
- DescBuilder& AppendWriteable(uintptr_t addr, size_t size) { return Append(addr, size, true); }
-
- // Adds a buffer to the chain that is flagged as device writeable.
- DescBuilder& AppendReadable(void* addr, size_t size) { return Append(addr, size, false); }
- DescBuilder& AppendReadable(uintptr_t addr, size_t size) { return Append(addr, size, false); }
-
- // Make this descriptor chain visible to the device by writing the head
- // index to the available ring and incrementing the available index.
- //
- // The index of the head descriptor is written to |desc| if it is non-null.
- zx_status_t Build(uint16_t* desc);
- zx_status_t Build() { return Build(nullptr); }
-
-private:
- friend class VirtioQueueFake;
- DescBuilder(VirtioQueueFake* queue): queue_(queue) {}
-
- VirtioQueueFake* queue_;
- size_t len_ = 0;
- uint16_t prev_desc_ = 0;
- uint16_t head_desc_ = 0;
- zx_status_t status_ = ZX_OK;
-};
-
-// Helper class for creating fake virtio queue requests.
-//
-// The device should be initialized with guest physmem at 0 so that the
-// simulated guest physical address space aliases our address space.
-class VirtioQueueFake {
-public:
- explicit VirtioQueueFake(virtio_queue_t* queue): queue_(queue) {}
- ~VirtioQueueFake();
-
- // Allocate memory for a queue with the given size and wire up the queue
- // to use those buffers.
- zx_status_t Init(uint16_t size);
-
- // Allocate and write a descriptor. |addr|, |len|, and |flags| correspond
- // to the fields in vring_desc.
- //
- // The index of the allocated descriptor is written to |desc|.
- //
- // Descriptors are not reclaimed and it is a programming error to attempt
- // to write to more than descriptors than the queue was initialized with.
- // ZX_ERR_NO_MEMORY is returned if the pool of available desciptors has
- // been exhausted.
- zx_status_t WriteDescriptor(void* addr, size_t len, uint16_t flags, uint16_t* desc);
-
- // Write to |desc| that it is continued via |next|.
- //
- // Returns ZX_ERR_INVALID_ARGS if |desc| or |next| are greater than the
- // queue size.
- zx_status_t SetNext(uint16_t desc, uint16_t next);
-
- // Writes |desc| to the next entry in the available ring, making the
- // descriptor chain visible to the device.
- void WriteToAvail(uint16_t desc);
-
- DescBuilder BuildDescriptor() { return DescBuilder(this); }
-private:
-
- uint16_t queue_size_;
- virtio_queue_t* queue_;
- fbl::unique_ptr<uint8_t[]> desc_buf_;
- fbl::unique_ptr<uint8_t[]> avail_ring_buf_;
- fbl::unique_ptr<uint8_t[]> used_ring_buf_;
-
- // The next entry in the descriptor table that is available.
- uint16_t next_free_desc_ = 0;
-};