blob: 8063d1698dfe0b5302b4587f33278ba58216f7d5 [file] [log] [blame]
// 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.
#ifndef GARNET_LIB_MACHINA_IO_H_
#define GARNET_LIB_MACHINA_IO_H_
#include <fbl/canary.h>
#include <lib/async/cpp/trap.h>
#include <trace/event.h>
#include <zircon/types.h>
namespace machina {
class Guest;
struct IoValue {
uint8_t access_size;
union {
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
uint8_t data[8];
};
};
// Callback interface to be implemented by devices.
//
// IoHandlers may be called from multiple VCPU threads concurrently so
// implementations must implement proper internal synchronization.
class IoHandler {
public:
virtual ~IoHandler() = default;
// Read |value.access_size| bytes from |addr| into |value|.
virtual zx_status_t Read(uint64_t addr, IoValue* value) const = 0;
// Write |value.access_size| bytes to |addr| from |value|.
virtual zx_status_t Write(uint64_t addr, const IoValue& value) = 0;
};
// Represents a single mapping of an |IoHandler| to an address range.
//
// A single handler may be mapped to multiple distinct address ranges.
class IoMapping {
public:
static IoMapping* FromPortKey(uint64_t key) {
return reinterpret_cast<IoMapping*>(key);
}
// Constructs an IoMapping.
//
// Any accesses starting at |base| for |size| bytes are to be handled by
// |handler|. When invoking |handler| the address is provides as relative
// to |base|. Additionally an |offset| can also be provided to add a
// displacement into |handler|.
//
// Specifically, an access to |base| would invoke the |handler| with the
// address |offset| and increase linearly from there with additional
// displacement into |base|. This implies that |handler| should be prepared
// handle accesses between |offset| (inclusive) and |offset| + |size|
// (exclusive).
IoMapping(uint32_t kind, uint64_t base, size_t size, uint64_t offset,
IoHandler* handler);
uint64_t base() const {
canary_.Assert();
return base_;
}
size_t size() const {
canary_.Assert();
return size_;
}
uint32_t kind() const {
canary_.Assert();
return kind_;
}
zx_status_t Read(uint64_t addr, IoValue* value) const {
canary_.Assert();
const uint64_t address = addr - base_ + offset_;
TRACE_DURATION("machina", "read", "address", address, "access_size",
value->access_size);
return handler_->Read(address, value);
}
zx_status_t Write(uint64_t addr, const IoValue& value) {
canary_.Assert();
const uint64_t address = addr - base_ + offset_;
TRACE_DURATION("machina", "write", "address", address, "access_size",
value.access_size);
return handler_->Write(address, value);
}
zx_status_t SetTrap(Guest* guest);
protected:
void CallIoHandlerAsync(async_dispatcher_t* dispatcher,
async::GuestBellTrapBase* trap, zx_status_t status,
const zx_packet_guest_bell_t* bell);
fbl::Canary<fbl::magic("IOMP")> canary_;
const uint32_t kind_;
const uint64_t base_;
const size_t size_;
const uint64_t offset_;
IoHandler* handler_;
async::GuestBellTrapMethod<IoMapping, &IoMapping::CallIoHandlerAsync>
async_trap_;
};
} // namespace machina
#endif // GARNET_LIB_MACHINA_IO_H_