syntax = "proto3";

// The protocol defined here is actually two sub-protocols, one protocol for control of the main
// process (MainRequest/MainResponse), and one for control of each VCPU thread
// (VcpuRequest/VcpuResponse). Each protocol works the same: the client creates a protobuf of either
// a MainRequest or VcpuRequest, sends it encoded over the main socket or one of the vcpu sockets,
// reads the the MainResponse or VcpuResponse over the same socket and decodes it as a protobuf. For
// specific information on the purpose of each request, see the C API in crosvm.h. Most requests
// here map 1:1 to a function in that API. Only the intricacies unique to the wire protocol are
// commented on here.

enum AddressSpace {
    IOPORT = 0;
    MMIO = 1;
 }

message CpuidEntry  {
    uint32 function = 1;
    bool has_index = 3;
    uint32 index = 4;
    uint32 eax = 5;
    uint32 ebx = 6;
    uint32 ecx = 7;
    uint32 edx = 8;
}

// A request made to the crosvm main process that affects the global aspects of the VM.
message MainRequest {
    // Every message under the Create namespace will instantiate an object with the given ID. The
    // type of object is determined by the oneof constructor field.
    message Create {
        message IoEvent {
            AddressSpace space = 1;
            uint64 address = 2;
            uint32 length = 3;
            uint64 datamatch = 4;
        }

        message Memory {
            uint64 offset = 1;
            uint64 start = 2;
            uint64 length = 3;
            bool read_only = 4;
            // Must be true for the MemoryDirtyLog method to work on this object.
            bool dirty_log = 5;
        }

        message IrqEvent {
            uint32 irq_id = 1;
            bool resample = 2;
        }

        uint32 id = 1;
        oneof constructor {
            IoEvent io_event = 2;
            // This message also requires a memfd sent over the socket.
            Memory memory = 3;
            IrqEvent irq_event = 4;
        }
    }

    // No matter what the type an object is, it can be destroyed using this common method.
    message Destroy {
        uint32 id = 1;
    }

    message NewConnection {}

    message GetShutdownEventfd {}

    message CheckExtension {
        uint32 extension = 1;
    }

    message CpuidRequest {
    }

    message MsrListRequest {
    }

    message GetNetConfig {}

    message ReserveRange {
        AddressSpace space = 1;
        uint64 start = 2;
        uint64 length = 3;
        bool async_write = 4;
    }

    message SetIrq {
        uint32 irq_id = 1;
        bool active = 2;
    }

    message SetIrqRouting {
        message Route {
            message Irqchip {
                uint32 irqchip = 1;
                uint32 pin = 2;
            }

            message Msi {
                uint64 address = 1;
                uint32 data = 2;
            }

            uint32 irq_id = 1;
            oneof route {
                Irqchip irqchip = 2;
                Msi msi = 3;
            }
        }

        repeated Route routes = 1;
    }

    // Each type refers to certain piece of VM state (such as PIT state).
    // The structure of the data corresponds to the kvm structure.
    enum StateSet {
        // struct kvm_pic_state
        PIC0 = 0;
        // struct kvm_pic_state
        PIC1 = 1;
        // struct kvm_ioapic_state
        IOAPIC = 2;
        // struct kvm_pit_state2
        PIT = 3;
        // struct kvm_clock_data
        CLOCK = 4;
    }

    message GetState {
        StateSet set = 1;
    }

    message SetState {
        StateSet set = 1;
        // The in memory representation of certain state, depending on the value
        // of the StateSet.
        bytes state = 2;
    }

    message SetIdentityMapAddr {
        uint32 address = 1;
    }

    message PauseVcpus {
        uint64 cpu_mask = 1;
        uint64 user = 2;
    }

    message GetVcpus {}
    message Start {}

    message SetCallHint {
        message RegHint {
	    bool match_rax = 1;
	    bool match_rbx = 2;
	    bool match_rcx = 3;
	    bool match_rdx = 4;
	    uint64 rax = 5;
	    uint64 rbx = 6;
	    uint64 rcx = 7;
	    uint64 rdx = 8;
	    bool send_sregs = 9;
	    bool send_debugregs = 10;
	}

        AddressSpace space = 1;
        uint64 address = 2;
        bool on_write = 3;

        repeated RegHint hints = 4;
    }

    message MemoryDirtyLog {
        uint32 id = 1;
    }

    // The type of the message is determined by which of these oneof fields is present in the
    // protobuf.
    oneof message {
        // Common method for instantiating a new object of any type.
        Create create = 1;
        // Common method for destroying an object of any type.
        Destroy destroy = 2;
        NewConnection new_connection = 3;
        GetShutdownEventfd get_shutdown_eventfd = 4;
        CheckExtension check_extension = 5;
        CpuidRequest get_supported_cpuid = 6;
        CpuidRequest get_emulated_cpuid = 7;
        MsrListRequest get_msr_index_list = 8;
        GetNetConfig get_net_config = 9;
        ReserveRange reserve_range = 10;
        SetIrq set_irq = 11;
        SetIrqRouting set_irq_routing = 12;
        GetState get_state = 13;
        SetState set_state = 14;
        SetIdentityMapAddr set_identity_map_addr = 15;
        PauseVcpus pause_vcpus = 16;
        GetVcpus get_vcpus = 17;
        Start start = 18;
        SetCallHint set_call_hint = 19;
        // Method for a Memory type object for retrieving the dirty bitmap. Only valid if the memory
        // object was created with dirty_log set.
        MemoryDirtyLog dirty_log = 101;
    }
}

message MainResponse {
    // Depending on the object that was created, an fd might also come from the socket.
    message Create {}
    message Destroy {}
    // NewMessage receives a socket fd along with the data from reading this socket.
    // The returned socket can be used totally independently of the original socket, and can perform
    // requests and responses independent of the other sockets.
    message NewConnection {}
    message GetShutdownEventfd {}
    message CheckExtension {
        bool has_extension = 1;
    }
    message CpuidResponse {
        repeated CpuidEntry entries = 1;
    }
    message MsrListResponse {
        repeated uint32 indices = 1;
    }

    // GetNetConfig messages also return a file descriptor for the tap device.
    message GetNetConfig {
        bytes host_mac_address = 1;
        fixed32 host_ipv4_address = 2;
        fixed32 netmask = 3;
    }

    message ReserveRange {}
    message SetIrq {}
    message SetIrqRouting {}
    message GetState {
        // The in memory representation of a state, depending on what StateSet was
        // requested in GetState.
        bytes state = 1;
    }
    message SetState {}
    message SetIdentityMapAddr {}
    message PauseVcpus {}
    // This message should also receive a socket fd per VCPU along with the data from reading this
    // socket. The VcpuRequest/VcpuResponse protocol is run over each of the returned fds.
    message GetVcpus {}
    message Start {}
    message SetCallHint {}
    message MemoryDirtyLog {
        bytes bitmap = 1;
    }

    // This is zero on success, and a negative integer on failure.
    sint32 errno = 1;
    // The field present here is always the same as the one present in the corresponding
    // MainRequest.
    oneof message {
        Create create = 2;
        Destroy destroy = 3;
        NewConnection new_connection = 4;
        GetShutdownEventfd get_shutdown_eventfd = 5;
        CheckExtension check_extension = 6;
        CpuidResponse get_supported_cpuid = 7;
        CpuidResponse get_emulated_cpuid = 8;
        MsrListResponse get_msr_index_list = 9;
        GetNetConfig get_net_config = 10;
        ReserveRange reserve_range = 11;
        SetIrq set_irq = 12;
        SetIrqRouting set_irq_routing = 13;
        GetState get_state = 14;
        SetState set_state = 15;
        SetIdentityMapAddr set_identity_map_addr = 16;
        PauseVcpus pause_vcpus = 17;
        GetVcpus get_vcpus = 18;
        Start start = 19;
        SetCallHint set_call_hint = 20;
        MemoryDirtyLog dirty_log = 101;
    }
}

// A request made for a specific VCPU. These requests are sent over the sockets returned from the
// GetVcpu MainRequest.
message VcpuRequest {
    // This message will block until a non-empty response can be sent. The first response will
    // always be an Init wait reason.
    message Wait {
    }

    message Resume {
        // The data is only necessary for non-write (read) I/O accesses. In all other cases, data is
        // ignored.
        bytes data = 1;

        // The following tracks what deferred set calls to apply.
        bytes regs = 2;
        bytes sregs = 3;
        bytes debugregs = 4;
    }

    // Each type refers to certain piece of VCPU state (a set registers, or something else).
    // The structure of the data corresponds to the kvm structure.
    enum StateSet {
        // struct kvm_regs
        REGS = 0;
        // struct kvm_sregs
        SREGS = 1;
        // struct kvm_fpu
        FPU = 2;
        // struct kvm_debugregs
        DEBUGREGS = 3;
        // struct kvm_lapic_state
        LAPIC = 4;
        // struct kvm_mp_state
        MP = 5;
        // struct kvm_xcrs
        XCREGS = 6;
        // struct kvm_vcpu_events
        EVENTS = 7;
    }

    message GetState {
        StateSet set = 1;
    }

    message SetState {
        StateSet set = 1;
        // The in memory representation of a struct kvm_regs, struct kvm_sregs,
        // struct kvm_fpu, struct kvm_debugregs, struct kvm_lapic_state,
        // struct kvm_mp_state, struct kvm_xcrs or struct kvm_vcpu_events
        // depending on the value of the StateSet.
        bytes state = 2;
    }

    message CpuidRequest {
    }

    message GetMsrs {
        // The entry data will be returned in the same order as this in the
        // VcpuResponse::GetMsrs::entry_data array.
        repeated uint32 entry_indices = 1;
    }

    message MsrEntry {
        uint32 index = 1;
        uint64 data = 2;
    }

    message SetMsrs {
        repeated MsrEntry entries = 1;
    }

    message SetCpuid {
        repeated CpuidEntry entries = 1;
    }

    message Shutdown {
    }

    message EnableCapability {
        uint32 capability = 1;
    }

    // The type of the message is determined by which of these oneof fields is present in the
    // protobuf.
    oneof message {
        Wait wait = 1;
        Resume resume = 2;
        GetState get_state = 3;
        SetState set_state = 4;
        GetMsrs get_msrs = 5;
        SetMsrs set_msrs = 6;
        SetCpuid set_cpuid = 7;
        Shutdown shutdown = 8;
        CpuidRequest get_hyperv_cpuid = 9;
        EnableCapability enable_capability = 10;
    }
}


message VcpuResponse  {
    // Depending on the reason a VCPU has exited, the Wait request will unblock and return a field
    // in the oneof exit. This is called the "wait reason."
    message Wait {
        // This request will always be the first wait reason returend by the first wait request.
        message Init {
        }

        // This type of wait reason is only generated if the access occurred on this VCPU on an
        // address previously reserved by a ReserveRange main request.
        message Io {
            AddressSpace space = 1;
            uint64 address = 2;
            bool is_write = 3;
            bool no_resume = 4;
            bytes data = 5;

            // The following can be eagerly provided.
            bytes regs = 6;
            bytes sregs = 7;
            bytes debugregs = 8;
        }

        // This type of wait reason is only generated after a PauseVcpus request on this VCPU.
        message User {
            uint64 user = 1;
        }

        message HypervCall {
            uint64 input = 1;
            uint64 params0 = 2;
            uint64 params1 = 3;
        }

        message HypervSynic {
            uint32 msr = 1;
            uint64 control = 2;
            uint64 evt_page = 3;
            uint64 msg_page = 4;
        }

        oneof exit {
            Init init = 1;
            Io io = 2;
            User user = 3;
            HypervCall hyperv_call = 4;
            HypervSynic hyperv_synic = 5;
        }
    }

    message GetState {
        // The in memory representation of a struct kvm_regs, struct kvm_sregs,
        // struct kvm_fpu, struct kvm_debugregs, struct kvm_lapic_state,
        // struct kvm_mp_state, struct kvm_xcrs or struct kvm_vcpu_events
        // depending on the value of the StateSet.
        bytes state = 1;
    }

    message SetState {
    }

    message CpuidResponse {
        repeated CpuidEntry entries = 1;
    }

    message GetMsrs {
        // The order of the entry_data values is the same order as the array of indices given in the
        // corresponding request.
        repeated uint64 entry_data = 1;
    }

    message SetMsrs {}

    message SetCpuid {}

    message EnableCapability {}

    // This is zero on success, and a negative integer on failure.
    sint32 errno = 1;
    // The field present here is always the same as the one present in the corresponding
    // VcpuRequest.
    oneof message {
        Wait wait = 2;
        // resume was 3 but no longer gets a reply.
        GetState get_state = 4;
        SetState set_state = 5;
        GetMsrs get_msrs = 6;
        SetMsrs set_msrs = 7;
        SetCpuid set_cpuid = 8;
        CpuidResponse get_hyperv_cpuid = 9;
        EnableCapability enable_capability = 10;
    }
}
