// Copyright 2016 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 <inttypes.h>
#include <lib/fit/defer.h>
#include <lib/syscalls/forward.h>
#include <lib/user_copy/user_ptr.h>
#include <trace.h>
#include <zircon/errors.h>
#include <zircon/features.h>
#include <zircon/types.h>

#include <arch/ops.h>
#include <fbl/ref_ptr.h>
#include <object/handle.h>
#include <object/io_buffer_dispatcher.h>
#include <object/process_dispatcher.h>
#include <object/vm_address_region_dispatcher.h>
#include <object/vm_object_dispatcher.h>
#include <vm/vm_address_region.h>
#include <vm/vm_object.h>

#define LOCAL_TRACE 0

// zx_status_t zx_vmar_allocate
zx_status_t sys_vmar_allocate(zx_handle_t parent_vmar_handle, zx_vm_option_t options,
                              uint64_t offset, uint64_t size, zx_handle_t* child_vmar,
                              user_out_ptr<zx_vaddr_t> child_addr) {
  auto* up = ProcessDispatcher::GetCurrent();

  // Compute needed rights from requested mapping protections.
  zx_rights_t vmar_rights = 0u;
  if (options & ZX_VM_CAN_MAP_READ) {
    vmar_rights |= ZX_RIGHT_READ;
  }
  if (options & ZX_VM_CAN_MAP_WRITE) {
    vmar_rights |= ZX_RIGHT_WRITE;
  }
  if (options & ZX_VM_CAN_MAP_EXECUTE) {
    vmar_rights |= ZX_RIGHT_EXECUTE;
  }

  // lookup the dispatcher from handle
  fbl::RefPtr<VmAddressRegionDispatcher> vmar;
  zx_status_t status =
      up->handle_table().GetDispatcherWithRights(*up, parent_vmar_handle, vmar_rights, &vmar);
  if (status != ZX_OK) {
    return status;
  }

  // Create the new VMAR
  KernelHandle<VmAddressRegionDispatcher> handle;
  zx_rights_t new_rights;
  status = vmar->Allocate(offset, size, options, &handle, &new_rights);
  if (status != ZX_OK) {
    return status;
  }

  // Setup a handler to destroy the new VMAR if the syscall is unsuccessful.
  fbl::RefPtr<VmAddressRegionDispatcher> vmar_dispatcher = handle.dispatcher();
  auto cleanup_handler = fit::defer([&vmar_dispatcher]() { vmar_dispatcher->Destroy(); });

  // Create a handle and attach the dispatcher to it
  status = up->MakeAndAddHandle(ktl::move(handle), new_rights, child_vmar);

  if (status == ZX_OK) {
    status = child_addr.copy_to_user(vmar_dispatcher->vmar()->base());
  }

  if (status == ZX_OK) {
    cleanup_handler.cancel();
  }
  return status;
}

// zx_status_t zx_vmar_destroy
zx_status_t sys_vmar_destroy(zx_handle_t handle) {
  auto* up = ProcessDispatcher::GetCurrent();

  // lookup the dispatcher from handle
  fbl::RefPtr<VmAddressRegionDispatcher> vmar;
  zx_status_t status =
      up->handle_table().GetDispatcherWithRights(*up, handle, ZX_RIGHT_OP_CHILDREN, &vmar);
  if (status != ZX_OK) {
    return status;
  }

  return vmar->Destroy();
}

namespace {
zx_status_t vmar_map_common(zx_vm_option_t options, fbl::RefPtr<VmAddressRegionDispatcher> vmar,
                            uint64_t vmar_offset, zx_rights_t vmar_rights,
                            fbl::RefPtr<VmObject> vmo, uint64_t vmo_offset, zx_rights_t vmo_rights,
                            uint64_t len, user_out_ptr<zx_vaddr_t> mapped_addr) {
  // Test to see if we should even be able to map this.
  if (!(vmo_rights & ZX_RIGHT_MAP)) {
    return ZX_ERR_ACCESS_DENIED;
  }

  if ((options & ZX_VM_PERM_READ_IF_XOM_UNSUPPORTED)) {
    if (!(arch_vm_features() & ZX_VM_FEATURE_CAN_MAP_XOM)) {
      options |= ZX_VM_PERM_READ;
    }
  }

  if (!VmAddressRegionDispatcher::is_valid_mapping_protection(options)) {
    return ZX_ERR_INVALID_ARGS;
  }

  bool do_map_range = false;
  if (options & ZX_VM_MAP_RANGE) {
    do_map_range = true;
    options &= ~ZX_VM_MAP_RANGE;
  }

  if (do_map_range && (options & ZX_VM_SPECIFIC_OVERWRITE)) {
    return ZX_ERR_INVALID_ARGS;
  }

  // Usermode is not allowed to specify these flags on mappings, though we may
  // set them below.
  if (options & (ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_EXECUTE)) {
    return ZX_ERR_INVALID_ARGS;
  }

  // Permissions allowed by both the VMO and the VMAR.
  const bool can_read = (vmo_rights & ZX_RIGHT_READ) && (vmar_rights & ZX_RIGHT_READ);
  const bool can_write = (vmo_rights & ZX_RIGHT_WRITE) && (vmar_rights & ZX_RIGHT_WRITE);
  const bool can_exec = (vmo_rights & ZX_RIGHT_EXECUTE) && (vmar_rights & ZX_RIGHT_EXECUTE);

  // Test to see if the requested mapping protections are allowed.
  if ((options & ZX_VM_PERM_READ) && !can_read) {
    return ZX_ERR_ACCESS_DENIED;
  }
  if ((options & ZX_VM_PERM_WRITE) && !can_write) {
    return ZX_ERR_ACCESS_DENIED;
  }
  if ((options & ZX_VM_PERM_EXECUTE) && !can_exec) {
    return ZX_ERR_ACCESS_DENIED;
  }

  // If a permission is allowed by both the VMO and the VMAR, add it to the
  // flags for the new mapping, so that the VMO's rights as of now can be used
  // to constrain future permission changes via Protect().
  if (can_read) {
    options |= ZX_VM_CAN_MAP_READ;
  }
  if (can_write) {
    options |= ZX_VM_CAN_MAP_WRITE;
  }
  if (can_exec) {
    options |= ZX_VM_CAN_MAP_EXECUTE;
  }

  zx::result<VmAddressRegionDispatcher::MapResult> map_result =
      vmar->Map(vmar_offset, ktl::move(vmo), vmo_offset, len, options);
  if (map_result.is_error()) {
    return map_result.status_value();
  }

  // Setup a handler to destroy the new mapping if the syscall is unsuccessful.
  auto cleanup_handler = fit::defer([&map_result]() { map_result->mapping->Destroy(); });

  if (do_map_range) {
    // Mappings may have already been created due to memory priority, so need to ignore existing.
    // Ignoring existing mappings is safe here as we are always free to populate and destroy page
    // table mappings for user addresses.
    zx_status_t status =
        map_result->mapping->MapRange(0, len, /*commit=*/false, /*ignore_existing=*/true);
    if (status != ZX_OK) {
      return status;
    }
  }

  zx_status_t status = mapped_addr.copy_to_user(map_result->base);

  if (status != ZX_OK) {
    return status;
  }

  cleanup_handler.cancel();

  // This mapping will now always be used via the aspace so it is free to be merged into different
  // actual mapping objects.
  VmMapping::MarkMergeable(ktl::move(map_result->mapping));

  return ZX_OK;
}
}  // namespace

// zx_status_t zx_vmar_map
zx_status_t sys_vmar_map(zx_handle_t handle, zx_vm_option_t options, uint64_t vmar_offset,
                         zx_handle_t vmo_handle, uint64_t vmo_offset, uint64_t len,
                         user_out_ptr<zx_vaddr_t> mapped_addr) {
  auto* up = ProcessDispatcher::GetCurrent();

  // lookup the VMAR dispatcher from handle
  fbl::RefPtr<VmAddressRegionDispatcher> vmar;
  zx_rights_t vmar_rights;
  zx_status_t status = up->handle_table().GetDispatcherAndRights(*up, handle, &vmar, &vmar_rights);
  if (status != ZX_OK) {
    return status;
  }

  // lookup the VMO dispatcher from handle
  fbl::RefPtr<VmObjectDispatcher> vmo;
  zx_rights_t vmo_rights;
  status = up->handle_table().GetDispatcherAndRights(*up, vmo_handle, &vmo, &vmo_rights);
  if (status != ZX_OK) {
    return status;
  }

  return vmar_map_common(options, ktl::move(vmar), vmar_offset, vmar_rights, vmo->vmo(), vmo_offset,
                         vmo_rights, len, mapped_addr);
}

// zx_status_t zx_vmar_unmap
zx_status_t sys_vmar_unmap(zx_handle_t handle, zx_vaddr_t addr, uint64_t len) {
  auto* up = ProcessDispatcher::GetCurrent();

  // lookup the dispatcher from handle
  fbl::RefPtr<VmAddressRegionDispatcher> vmar;
  zx_rights_t vmar_rights;
  zx_status_t status = up->handle_table().GetDispatcherAndRights(*up, handle, &vmar, &vmar_rights);
  if (status != ZX_OK) {
    return status;
  }

  return vmar->Unmap(addr, len, VmAddressRegionDispatcher::op_children_from_rights(vmar_rights));
}

// zx_status_t zx_vmar_protect
zx_status_t sys_vmar_protect(zx_handle_t handle, zx_vm_option_t options, zx_vaddr_t addr,
                             uint64_t len) {
  auto* up = ProcessDispatcher::GetCurrent();

  if ((options & ZX_VM_PERM_READ_IF_XOM_UNSUPPORTED)) {
    if (!(arch_vm_features() & ZX_VM_FEATURE_CAN_MAP_XOM)) {
      options |= ZX_VM_PERM_READ;
    }
  }

  zx_rights_t vmar_rights = 0u;
  if (options & ZX_VM_PERM_READ) {
    vmar_rights |= ZX_RIGHT_READ;
  }
  if (options & ZX_VM_PERM_WRITE) {
    vmar_rights |= ZX_RIGHT_WRITE;
  }
  if (options & ZX_VM_PERM_EXECUTE) {
    vmar_rights |= ZX_RIGHT_EXECUTE;
  }

  // lookup the dispatcher from handle
  fbl::RefPtr<VmAddressRegionDispatcher> vmar;
  zx_status_t status =
      up->handle_table().GetDispatcherWithRights(*up, handle, vmar_rights, &vmar, &vmar_rights);
  if (status != ZX_OK) {
    return status;
  }

  if (!VmAddressRegionDispatcher::is_valid_mapping_protection(options)) {
    return ZX_ERR_INVALID_ARGS;
  }

  return vmar->Protect(addr, len, options,
                       VmAddressRegionDispatcher::op_children_from_rights(vmar_rights));
}

// zx_status_t zx_vmar_op_range
zx_status_t sys_vmar_op_range(zx_handle_t handle, uint32_t op, zx_vaddr_t addr, uint64_t len,
                              user_inout_ptr<void> _buffer, size_t buffer_size) {
  auto* up = ProcessDispatcher::GetCurrent();

  fbl::RefPtr<VmAddressRegionDispatcher> vmar;
  zx_rights_t vmar_rights;
  zx_status_t status = up->handle_table().GetDispatcherAndRights(*up, handle, &vmar, &vmar_rights);
  if (status != ZX_OK) {
    return status;
  }

  return vmar->RangeOp(op, addr, len, vmar_rights, _buffer, buffer_size);
}

// zx_status_t zx_vmar_map_iob
zx_status_t sys_vmar_map_iob(zx_handle_t handle, zx_vm_option_t options, size_t vmar_offset,
                             zx_handle_t ep, uint32_t region_index, size_t region_offset,
                             size_t region_length, user_out_ptr<vaddr_t> mapped_addr) {
  auto* up = ProcessDispatcher::GetCurrent();

  // Lookup the VMAR dispatcher from handle.
  fbl::RefPtr<VmAddressRegionDispatcher> vmar;
  zx_rights_t vmar_rights;
  zx_status_t status = up->handle_table().GetDispatcherAndRights(*up, handle, &vmar, &vmar_rights);
  if (status != ZX_OK) {
    return status;
  }

  // Lookup the iob dispatcher from handle.
  fbl::RefPtr<IoBufferDispatcher> iobuffer_disp;
  zx_rights_t iobuffer_rights;
  status = up->handle_table().GetDispatcherAndRights(*up, ep, &iobuffer_disp, &iobuffer_rights);
  if (status != ZX_OK) {
    return status;
  }

  if (region_index >= iobuffer_disp->RegionCount()) {
    return ZX_ERR_OUT_OF_RANGE;
  }

  zx::result<fbl::RefPtr<VmObject>> vmo = iobuffer_disp->CreateMappableVmoForRegion(region_index);
  if (vmo.is_error()) {
    return vmo.status_value();
  }
  zx_rights_t region_rights = iobuffer_disp->GetMapRights(iobuffer_rights, region_index);
  return vmar_map_common(options, ktl::move(vmar), vmar_offset, vmar_rights, ktl::move(*vmo),
                         region_offset, region_rights, region_length, mapped_addr);
}
