// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2014 Travis Geiselbrecht
//
// 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 <assert.h>
#include <err.h>
#include <inttypes.h>
#include <lib/console.h>
#include <lib/ktrace.h>
#include <string.h>
#include <trace.h>
#include <zircon/types.h>

#include <fbl/null_lock.h>
#include <kernel/mutex.h>
#include <kernel/thread_lock.h>
#include <object/diagnostics.h>
#include <vm/fault.h>
#include <vm/pmm.h>
#include <vm/vm.h>
#include <vm/vm_address_region.h>
#include <vm/vm_aspace.h>

#include "vm_priv.h"

#define LOCAL_TRACE MAX(VM_GLOBAL_TRACE, 0)
#define TRACE_PAGE_FAULT 0

// This file mostly contains C wrappers around the underlying C++ objects, conforming to
// the older api.

static inline void vmm_context_switch(VmAspace* oldspace, VmAspace* newaspace) {
  DEBUG_ASSERT(thread_lock_held());

  ArchVmAspace::ContextSwitch(oldspace ? &oldspace->arch_aspace() : nullptr,
                              newaspace ? &newaspace->arch_aspace() : nullptr);
}

void vmm_context_switch(vmm_aspace_t* oldspace, vmm_aspace_t* newaspace) {
  vmm_context_switch(reinterpret_cast<VmAspace*>(oldspace), reinterpret_cast<VmAspace*>(newaspace));
}

zx_status_t vmm_page_fault_handler(vaddr_t addr, uint flags) {
  // hardware fault, mark it as such
  flags |= VMM_PF_FLAG_HW_FAULT;

#if TRACE_PAGE_FAULT || LOCAL_TRACE
  thread_t* current_thread = get_current_thread();
  TRACEF("thread %s va %#" PRIxPTR ", flags 0x%x\n", current_thread->name, addr, flags);
#endif

  ktrace(TAG_PAGE_FAULT, (uint32_t)(addr >> 32), (uint32_t)addr, flags, arch_curr_cpu_num());

  // get the address space object this pointer is in
  VmAspace* aspace = VmAspace::vaddr_to_aspace(addr);
  if (!aspace) {
    return ZX_ERR_NOT_FOUND;
  }

  // page fault it
  zx_status_t status = aspace->PageFault(addr, flags);

  // If it's a user fault, dump info about process memory usage.
  // If it's a kernel fault, the kernel could possibly already
  // hold locks on VMOs, Aspaces, etc, so we can't safely do
  // this.
  if ((status == ZX_ERR_NOT_FOUND) && (flags & VMM_PF_FLAG_USER)) {
    printf("PageFault: %zu free pages\n", pmm_count_free_pages());
    DumpProcessMemoryUsage("PageFault: MemoryUsed: ", 8 * 256);
  } else if (status == ZX_ERR_INTERNAL_INTR_RETRY) {
    // If we get this, then all checks passed but we were suspended while waiting
    // for the request to be fulfilled. Pretend the fault was successful and let
    // the thread re-fault after it is resumed.
    status = ZX_OK;
  }

  ktrace(TAG_PAGE_FAULT_EXIT, (uint32_t)(addr >> 32), (uint32_t)addr, flags, arch_curr_cpu_num());

  return status;
}

template <typename GuardType, typename Lock>
static void vmm_set_active_aspace_internal(vmm_aspace_t* aspace, Lock lock) {
  LTRACEF("aspace %p\n", aspace);

  thread_t* t = get_current_thread();
  DEBUG_ASSERT(t);

  if (aspace == t->aspace) {
    return;
  }

  // grab the thread lock and switch to the new address space
  GuardType __UNUSED lock_guard{lock};

  vmm_aspace_t* old = t->aspace;
  t->aspace = aspace;
  vmm_context_switch(old, t->aspace);
}

void vmm_set_active_aspace(vmm_aspace_t* aspace) {
  vmm_set_active_aspace_internal<Guard<spin_lock_t, IrqSave>>(aspace, ThreadLock::Get());
}

void vmm_set_active_aspace_locked(vmm_aspace_t* aspace) {
  vmm_set_active_aspace_internal<fbl::NullLock>(aspace, fbl::NullLock());
}

vmm_aspace_t* vmm_get_kernel_aspace(void) {
  return reinterpret_cast<vmm_aspace_t*>(VmAspace::kernel_aspace());
}

static int cmd_vmm(int argc, const cmd_args* argv, uint32_t flags) {
  if (argc < 2) {
  notenoughargs:
    printf("not enough arguments\n");
  usage:
    printf("usage:\n");
    printf("%s aspaces\n", argv[0].str);
    printf("%s kaspace\n", argv[0].str);
    printf("%s alloc <size> <align_pow2>\n", argv[0].str);
    printf("%s alloc_physical <paddr> <size> <align_pow2>\n", argv[0].str);
    printf("%s alloc_contig <size> <align_pow2>\n", argv[0].str);
    printf("%s free_region <address>\n", argv[0].str);
    printf("%s create_aspace\n", argv[0].str);
    printf("%s create_test_aspace\n", argv[0].str);
    printf("%s free_aspace <address>\n", argv[0].str);
    printf("%s set_test_aspace <address>\n", argv[0].str);
    return ZX_ERR_INTERNAL;
  }

  static fbl::RefPtr<VmAspace> test_aspace;
  if (!test_aspace) {
    test_aspace = fbl::WrapRefPtr(VmAspace::kernel_aspace());
  }

  if (!strcmp(argv[1].str, "aspaces")) {
    DumpAllAspaces(true);
  } else if (!strcmp(argv[1].str, "kaspace")) {
    VmAspace::kernel_aspace()->Dump(true);
  } else if (!strcmp(argv[1].str, "alloc")) {
    if (argc < 3) {
      goto notenoughargs;
    }

    void* ptr = (void*)0x99;
    uint8_t align = (argc >= 4) ? (uint8_t)argv[3].u : 0u;
    zx_status_t err = test_aspace->Alloc("alloc test", argv[2].u, &ptr, align, 0, 0);
    printf("VmAspace::Alloc returns %d, ptr %p\n", err, ptr);
  } else if (!strcmp(argv[1].str, "alloc_physical")) {
    if (argc < 4) {
      goto notenoughargs;
    }

    void* ptr = (void*)0x99;
    uint8_t align = (argc >= 5) ? (uint8_t)argv[4].u : 0u;
    zx_status_t err = test_aspace->AllocPhysical(
        "physical test", argv[3].u, &ptr, align, argv[2].u, 0,
        ARCH_MMU_FLAG_UNCACHED_DEVICE | ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_PERM_WRITE);
    printf("VmAspace::AllocPhysical returns %d, ptr %p\n", err, ptr);
  } else if (!strcmp(argv[1].str, "alloc_contig")) {
    if (argc < 3) {
      goto notenoughargs;
    }

    void* ptr = (void*)0x99;
    uint8_t align = (argc >= 4) ? (uint8_t)argv[3].u : 0u;
    zx_status_t err =
        test_aspace->AllocContiguous("contig test", argv[2].u, &ptr, align, 0,
                                     ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_PERM_WRITE);
    printf("VmAspace::AllocContiguous returns %d, ptr %p\n", err, ptr);
  } else if (!strcmp(argv[1].str, "free_region")) {
    if (argc < 2) {
      goto notenoughargs;
    }

    zx_status_t err = test_aspace->FreeRegion(reinterpret_cast<vaddr_t>(argv[2].u));
    printf("VmAspace::FreeRegion returns %d\n", err);
  } else if (!strcmp(argv[1].str, "create_aspace")) {
    fbl::RefPtr<VmAspace> aspace = VmAspace::Create(0, "test");
    printf("VmAspace::Create aspace %p\n", aspace.get());
  } else if (!strcmp(argv[1].str, "create_test_aspace")) {
    fbl::RefPtr<VmAspace> aspace = VmAspace::Create(0, "test");
    printf("VmAspace::Create aspace %p\n", aspace.get());

    test_aspace = aspace;
    get_current_thread()->aspace = reinterpret_cast<vmm_aspace_t*>(aspace.get());
    thread_sleep(1);  // XXX hack to force it to reschedule and thus load the aspace
  } else if (!strcmp(argv[1].str, "free_aspace")) {
    if (argc < 2) {
      goto notenoughargs;
    }

    fbl::RefPtr<VmAspace> aspace = fbl::WrapRefPtr((VmAspace*)(void*)argv[2].u);
    if (test_aspace == aspace) {
      test_aspace = nullptr;
    }

    if (get_current_thread()->aspace == reinterpret_cast<vmm_aspace_t*>(aspace.get())) {
      get_current_thread()->aspace = nullptr;
      thread_sleep(1);  // hack
    }

    zx_status_t err = aspace->Destroy();
    printf("VmAspace::Destroy() returns %d\n", err);
  } else if (!strcmp(argv[1].str, "set_test_aspace")) {
    if (argc < 2) {
      goto notenoughargs;
    }

    test_aspace = fbl::WrapRefPtr((VmAspace*)(void*)argv[2].u);
    get_current_thread()->aspace = reinterpret_cast<vmm_aspace_t*>(test_aspace.get());
    thread_sleep(1);  // XXX hack to force it to reschedule and thus load the aspace
  } else {
    printf("unknown command\n");
    goto usage;
  }

  return ZX_OK;
}

STATIC_COMMAND_START
#if LK_DEBUGLEVEL > 0
STATIC_COMMAND("vmm", "virtual memory manager", &cmd_vmm)
#endif
STATIC_COMMAND_END(vmm)
