// 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 #include #include #include #include #include #include #include #include #include #include "priv.h" zx_status_t sys_guest_create(zx_handle_t resource, uint32_t options, user_out_handle* guest_handle, user_out_handle* vmar_handle) { if (options != 0u) return ZX_ERR_INVALID_ARGS; zx_status_t status = validate_resource(resource, ZX_RSRC_KIND_HYPERVISOR); if (status != ZX_OK) return status; fbl::RefPtr guest_dispatcher, vmar_dispatcher; zx_rights_t guest_rights, vmar_rights; status = GuestDispatcher::Create(&guest_dispatcher, &guest_rights, &vmar_dispatcher, &vmar_rights); if (status != ZX_OK) return status; status = guest_handle->make(fbl::move(guest_dispatcher), guest_rights); if (status != ZX_OK) return status; return vmar_handle->make(fbl::move(vmar_dispatcher), vmar_rights); } zx_status_t sys_guest_set_trap(zx_handle_t guest_handle, uint32_t kind, zx_vaddr_t addr, size_t len, zx_handle_t port_handle, uint64_t key) { auto up = ProcessDispatcher::GetCurrent(); fbl::RefPtr guest; zx_status_t status = up->GetDispatcherWithRights(guest_handle, ZX_RIGHT_WRITE, &guest); if (status != ZX_OK) return status; fbl::RefPtr port; if (port_handle != ZX_HANDLE_INVALID) { status = up->GetDispatcherWithRights(port_handle, ZX_RIGHT_WRITE, &port); if (status != ZX_OK) return status; } return guest->SetTrap(kind, addr, len, fbl::move(port), key); } zx_status_t sys_vcpu_create(zx_handle_t guest_handle, uint32_t options, zx_vaddr_t entry, user_out_handle* out) { if (options != 0u) return ZX_ERR_INVALID_ARGS; auto up = ProcessDispatcher::GetCurrent(); fbl::RefPtr guest; zx_status_t status = up->GetDispatcherWithRights(guest_handle, ZX_RIGHT_MANAGE_PROCESS, &guest); if (status != ZX_OK) return status; fbl::RefPtr dispatcher; zx_rights_t rights; status = VcpuDispatcher::Create(guest, entry, &dispatcher, &rights); if (status != ZX_OK) return status; return out->make(fbl::move(dispatcher), rights); } zx_status_t sys_vcpu_resume(zx_handle_t vcpu_handle, user_out_ptr user_packet) { auto up = ProcessDispatcher::GetCurrent(); fbl::RefPtr vcpu; zx_status_t status = up->GetDispatcherWithRights(vcpu_handle, ZX_RIGHT_EXECUTE, &vcpu); if (status != ZX_OK) return status; zx_port_packet packet; status = vcpu->Resume(&packet); if (status != ZX_OK) return status; status = user_packet.copy_to_user(packet); if (status != ZX_OK) return status; return ZX_OK; } zx_status_t sys_vcpu_interrupt(zx_handle_t vcpu_handle, uint32_t vector) { auto up = ProcessDispatcher::GetCurrent(); fbl::RefPtr vcpu; zx_status_t status = up->GetDispatcherWithRights(vcpu_handle, ZX_RIGHT_SIGNAL, &vcpu); if (status != ZX_OK) return status; return vcpu->Interrupt(vector); } zx_status_t sys_vcpu_read_state(zx_handle_t vcpu_handle, uint32_t kind, user_out_ptr user_buffer, size_t len) { auto up = ProcessDispatcher::GetCurrent(); fbl::RefPtr vcpu; zx_status_t status = up->GetDispatcherWithRights(vcpu_handle, ZX_RIGHT_READ, &vcpu); if (status != ZX_OK) return status; alignas(alignof(zx_vcpu_state_t)) uint8_t buffer[sizeof(zx_vcpu_state_t)]; if (len > sizeof(buffer)) return ZX_ERR_INVALID_ARGS; status = vcpu->ReadState(kind, buffer, len); if (status != ZX_OK) return status; status = user_buffer.copy_array_to_user(buffer, len); if (status != ZX_OK) return ZX_ERR_INVALID_ARGS; return ZX_OK; } zx_status_t sys_vcpu_write_state(zx_handle_t vcpu_handle, uint32_t kind, user_in_ptr user_buffer, size_t len) { auto up = ProcessDispatcher::GetCurrent(); fbl::RefPtr vcpu; zx_status_t status = up->GetDispatcherWithRights(vcpu_handle, ZX_RIGHT_WRITE, &vcpu); if (status != ZX_OK) return status; alignas(alignof(zx_vcpu_state_t)) uint8_t buffer[sizeof(zx_vcpu_state_t)]; if (len > sizeof(buffer)) return ZX_ERR_INVALID_ARGS; status = user_buffer.copy_array_from_user(buffer, len); if (status != ZX_OK) return ZX_ERR_INVALID_ARGS; return vcpu->WriteState(kind, buffer, len); }