// Copyright (C) 2019 The Android Open Source Project
// Copyright (C) 2019 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <memory>
#include <fcntl.h>
#include <lib/zx/channel.h>
#include <lib/zx/vmo.h>
#include <log/log.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <zircon/process.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>

#include "goldfish_address_space.h"
#include "android/base/synchronization/AndroidLock.h"
#include "services/service_connector.h"

#include <unordered_map>

using android::base::guest::AutoLock;
using android::base::guest::Lock;

using fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr;
using fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr;
using fuchsia::hardware::goldfish::AddressSpaceChildDriverType;
using fuchsia::hardware::goldfish::AddressSpaceChildDriverPingMessage;

GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice) {

    if (subdevice != GoldfishAddressSpaceSubdeviceType::NoSubdevice) {
        ALOGE("%s: Tried to use a nontrivial subdevice when support has not been added\n", __func__);
        abort();
    }

    zx::channel channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME));
    if (!channel) {
        ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME,
              __FUNCTION__);
        return;
    }
    m_device.Bind(std::move(channel));

    zx_status_t status = (*m_device).OpenChildDriver(
        static_cast<fuchsia::hardware::goldfish::AddressSpaceChildDriverType>(0 /* graphics */),
        m_child_driver.NewRequest());

    if (status != ZX_OK) {
        ALOGE("%s: failed to open child driver: %d",
              __FUNCTION__, status);
        return;
    }
}

GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
{
}

bool GoldfishAddressSpaceBlockProvider::is_opened() const
{
    return m_device.is_bound();
}

// void GoldfishAddressSpaceBlockProvider::close() - not implemented
// address_space_handle_t GoldfishAddressSpaceBlockProvider::release() - not imeplemented

GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
    : m_driver(NULL)
    , m_vmo(ZX_HANDLE_INVALID)
    , m_mmaped_ptr(NULL)
    , m_phys_addr(0)
    , m_host_addr(0)
    , m_offset(0)
    , m_size(0) {}

GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
{
    destroy();
}

GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
{
    m_vmo = rhs.m_vmo;
    m_mmaped_ptr = rhs.m_mmaped_ptr;
    m_phys_addr = rhs.m_phys_addr;
    m_host_addr = rhs.m_host_addr;
    m_offset = rhs.m_offset;
    m_size = rhs.m_size;
    m_driver = rhs.m_driver;

    return *this;
}

bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
{
    ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
         (unsigned long long)size);

    destroy();

    if (!provider->is_opened()) {
        return false;
    }

    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* driver = &provider->m_child_driver;

    int32_t res = ZX_OK;
    zx::vmo vmo;
    zx_status_t status = (*driver)->AllocateBlock(size, &res, &m_phys_addr, &vmo);
    if (status != ZX_OK || res != ZX_OK) {
        ALOGE("%s: allocate block failed: %d:%d", __func__, status, res);
        return false;
    }

    m_size = size;
    m_vmo = vmo.release();
    m_offset = 0;
    m_is_shared_mapping = false;

    ALOGD("%s: allocate returned offset 0x%llx size 0x%llx\n", __func__,
          (unsigned long long)m_offset,
          (unsigned long long)m_size);

    m_driver = driver;
    return true;
}

bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size)
{
    ALOGE("%s: FATAL: not supported\n", __func__);
    abort();
}

uint64_t GoldfishAddressSpaceBlock::physAddr() const
{
    return m_phys_addr;
}

uint64_t GoldfishAddressSpaceBlock::hostAddr() const
{
    return m_host_addr;
}

void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
{
    if (m_size == 0) {
        ALOGE("%s: called with zero size\n", __func__);
        return NULL;
    }
    if (m_mmaped_ptr) {
        ALOGE("'mmap' called for an already mmaped address block");
        ::abort();
    }

    zx_vaddr_t ptr = 0;
    zx_status_t status = zx_vmar_map(zx_vmar_root_self(),
                                     ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
                                     0, m_vmo,
                                     m_offset,
                                     m_size,
                                     &ptr);
    if (status != ZX_OK) {
        ALOGE("%s: host memory map failed with size 0x%llx "
              "off 0x%llx status %d\n",
              __func__,
              (unsigned long long)m_size,
              (unsigned long long)m_offset, status);
        return NULL;
    } else {
        m_mmaped_ptr = (void*)ptr;
        m_host_addr = host_addr;
        return guestPtr();
    }
}

void *GoldfishAddressSpaceBlock::guestPtr() const
{
    return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
}

void GoldfishAddressSpaceBlock::destroy()
{
    if (m_mmaped_ptr && m_size) {
        zx_vmar_unmap(zx_vmar_root_self(),
                      (zx_vaddr_t)m_mmaped_ptr,
                      m_size);
        m_mmaped_ptr = NULL;
    }

    if (m_size) {
        zx_handle_close(m_vmo);
        m_vmo = ZX_HANDLE_INVALID;
        if (m_is_shared_mapping) {
            // TODO
            ALOGE("%s: unsupported: GoldfishAddressSpaceBlock destroy() for shared regions\n", __func__);
            abort();
            // int32_t res = ZX_OK;
            // zx_status_t status = (*m_driver)->UnclaimShared(m_offset, &res);
            // if (status != ZX_OK || res != ZX_OK) {
            //     ALOGE("%s: unclaim shared block failed: %d:%d", __func__, status, res);
            // }
        } else {
            int32_t res = ZX_OK;
            zx_status_t status = (*m_driver)->DeallocateBlock(m_phys_addr, &res);
            if (status != ZX_OK || res != ZX_OK) {
                ALOGE("%s: deallocate block failed: %d:%d", __func__, status, res);
            }
        }
        m_driver = NULL;
        m_phys_addr = 0;
        m_host_addr = 0;
        m_offset = 0;
        m_size = 0;
    }
}

GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator()
  : m_provider(GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator) { }

long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size)
{
    return 0;
}

void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block)
{
}

class VmoStore {
public:
    struct Info {
        zx_handle_t vmo = ZX_HANDLE_INVALID;
        uint64_t phys_addr = 0;
    };

    void add(uint64_t offset, const Info& info) {
        AutoLock lock(mLock);
        mInfo[offset] = info;
    }

    void remove(uint64_t offset) {
        AutoLock lock(mLock);
        mInfo.erase(offset);
    }

    Info get(uint64_t offset) {
        Info res;
        AutoLock lock(mLock);
        auto it = mInfo.find(offset);
        if (it == mInfo.end()) {
            ALOGE("VmoStore::%s cannot find info on offset 0x%llx\n", __func__,
                  (unsigned long long)offset);
            return res;
        }
        res = it->second;
        return res;
    }

private:
    Lock mLock;
    std::unordered_map<uint64_t, Info> mInfo;
};

static Lock sVmoStoreInitLock;
static VmoStore* sVmoStore = nullptr;

static VmoStore* getVmoStore() {
    AutoLock lock(sVmoStoreInitLock);
    if (!sVmoStore) sVmoStore = new VmoStore;
    return sVmoStore;
}

address_space_handle_t goldfish_address_space_open() {
    zx::channel channel(GetConnectToServiceFunction()(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME));
    if (!channel) {
        ALOGE("%s: failed to get service handle for " GOLDFISH_ADDRESS_SPACE_DEVICE_NAME,
              __FUNCTION__);
        return 0;
    }
    fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr*
        deviceSync = new fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr;
    deviceSync->Bind(std::move(channel));
    return (address_space_handle_t)deviceSync;
}

void goldfish_address_space_close(address_space_handle_t handle) {
    fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr* deviceSync =
        reinterpret_cast<
            fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr*>(handle);
    delete deviceSync;
}

bool goldfish_address_space_set_subdevice_type(
    address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
    address_space_handle_t* handle_out) {

    fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr* deviceSync =
        reinterpret_cast<
            fuchsia::hardware::goldfish::AddressSpaceDeviceSyncPtr*>(handle);

    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*
        childSync = new fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr;

    zx_status_t res = (*(*deviceSync)).OpenChildDriver(
        static_cast<fuchsia::hardware::goldfish::AddressSpaceChildDriverType>(type),
        (*childSync).NewRequest());

    // On creating a subdevice, in our use cases we wont be needing the
    // original device sync anymore, so get rid of it.
    delete deviceSync;

    *handle_out = (void*)childSync;

    return true;
}

bool goldfish_address_space_allocate(
    address_space_handle_t handle,
    size_t size, uint64_t* phys_addr, uint64_t* offset) {
    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
        reinterpret_cast<
            fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);

    int32_t res = ZX_OK;
    zx::vmo vmo;
    zx_status_t status = (*(*deviceSync)).AllocateBlock(size, &res, phys_addr, &vmo);
    if (status != ZX_OK || res != ZX_OK) {
        ALOGE("%s: allocate block failed: %d:%d", __func__, status, res);
        return false;
    }

    *offset = 0;

    VmoStore::Info info = {
        vmo.release(),
        *phys_addr,
    };

    getVmoStore()->add(*offset, info);
    return true;
}

bool goldfish_address_space_free(
    address_space_handle_t handle, uint64_t offset) {
    auto info = getVmoStore()->get(offset);
    if (info.vmo == ZX_HANDLE_INVALID) return false;
    zx_handle_close(info.vmo);

    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
        reinterpret_cast<
            fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);

    int32_t res = ZX_OK;
    zx_status_t status = (*(*deviceSync)).DeallocateBlock(info.phys_addr, &res);
    if (status != ZX_OK || res != ZX_OK) {
        ALOGE("%s: deallocate block failed: %d:%d", __func__, status, res);
        return false;
    }

    return true;
}

bool goldfish_address_space_claim_shared(
    address_space_handle_t handle, uint64_t offset, uint64_t size) {

    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
        reinterpret_cast<
            fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
    zx::vmo vmo;
    zx_status_t res;
    zx_status_t status = (*(*deviceSync)).ClaimSharedBlock(offset, size, &res, &vmo);

    VmoStore::Info info = {
        vmo.release(),
    };

    getVmoStore()->add(offset, info);

    if (status != ZX_OK) return false;

    return true;
}

bool goldfish_address_space_unclaim_shared(
    address_space_handle_t handle, uint64_t offset) {
    fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr* deviceSync =
        reinterpret_cast<
            fuchsia::hardware::goldfish::AddressSpaceChildDriverSyncPtr*>(handle);
    zx::vmo vmo;
    zx_status_t res;
    zx_status_t status = (*(*deviceSync)).UnclaimSharedBlock(offset, &res);

    if (status != ZX_OK) return false;

    getVmoStore()->remove(offset);
    return true;
}

// pgoff is the offset into the page to return in the result
void* goldfish_address_space_map(
    address_space_handle_t handle,
    uint64_t offset, uint64_t size,
    uint64_t pgoff) {

    auto info = getVmoStore()->get(offset);
    if (info.vmo == ZX_HANDLE_INVALID) return nullptr;

    zx_vaddr_t ptr = 0;
    zx_status_t status =
        zx_vmar_map(zx_vmar_root_self(),
                    ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
                    0, info.vmo,
                    0, size,
                    &ptr);
    return (void*)(((char*)ptr) + (uintptr_t)(pgoff & (PAGE_SIZE - 1)));
}

void goldfish_address_space_unmap(void* ptr, uint64_t size) {
    zx_vmar_unmap(zx_vmar_root_self(),
                  (zx_vaddr_t)(((uintptr_t)ptr) & (uintptr_t)(~(PAGE_SIZE - 1))),
                  size);
}

bool goldfish_address_space_ping(
    address_space_handle_t handle,
    struct goldfish_address_space_ping* ping) {

    AddressSpaceChildDriverPingMessage fuchsiaPing =
        *(AddressSpaceChildDriverPingMessage*)ping;

    AddressSpaceChildDriverSyncPtr* deviceSync =
        reinterpret_cast<
            AddressSpaceChildDriverSyncPtr*>(handle);

    AddressSpaceChildDriverPingMessage res;
    zx_status_t pingStatus;
    zx_status_t status = (*(*deviceSync)).Ping(fuchsiaPing, &pingStatus, &res);

    if (pingStatus != ZX_OK) {
        return false;
    }

    *ping = *(struct goldfish_address_space_ping*)(&res);
    return true;
}
