1/*
2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6#pragma once
7
8/***
9 * @module ioports.h
10 * The ioports interface provides a useful abstraction for initialising, registering and handling ioport events
11 * for a guest VM instance. This is independent from the x86 libsel4vm ioports interface. This interface is intended
12 * to be more generic and architecture independent, useful for usecases that require ioports without architecture
13 * support (virtio PCI).
14 */
15
16#include <stdlib.h>
17#include <stdint.h>
18#include <stdbool.h>
19
20typedef int (*ioport_in_fn)(void *cookie, unsigned int port_no, unsigned int size, unsigned int *result);
21typedef int (*ioport_out_fn)(void *cookie, unsigned int port_no, unsigned int size, unsigned int value);
22
23typedef enum ioport_type {
24    IOPORT_FREE,
25    IOPORT_ADDR
26} ioport_type_t;
27
28/***
29 * @struct ioport_range
30 * Range of ioport handler
31 * @param {uint16_t} start  Start address of ioport range
32 * @param {uint16_t} end    End address of ioport range
33 * @param {uint16_t} size   Size of ioport range
34 */
35typedef struct ioport_range {
36    uint16_t start;
37    uint16_t end;
38    uint16_t size;
39} ioport_range_t;
40
41/***
42 * @struct ioport_interface
43 * Datastructure used for ioport emulation, containing handlers for the ioport range
44 * @param {void *} cookie           User supplied cookie to pass onto handlers
45 * @param {ioport_in_fn} port_in    IO in operation handler
46 * @param {ioport_out_fn} port_out  IO out operation handler
47 * @param {const char *} desc       IOPort description, useful for debugging
48 */
49typedef struct ioport_interface {
50    void *cookie;
51    ioport_in_fn port_in;
52    ioport_out_fn port_out;
53    const char *desc;
54} ioport_interface_t;
55
56/***
57 * @struct ioport_entry
58 * Datastructure used to present a registered ioport range
59 * @param {ioport_range_t} range            IO address range of ioport entry
60 * @param {ioport_interface_t} interface    Emulation interface for ioport range
61 */
62typedef struct ioport_entry {
63    ioport_range_t range;
64    ioport_interface_t interface;
65} ioport_entry_t;
66
67/***
68 * @struct vmm_io_list
69 * Parent datastructure used to maintain a list of registered ioports
70 * @param {int} num_ioports         Total number of registered ioports
71 * @param {ioport_entry_t **}       List of registered ioport objects
72 * @param {uint16_t} alloc_addr      Base ioport address we can safely bump allocate from, used when registering ioport handlers of type 'IOPORT_FREE'
73 */
74typedef struct vmm_io_list {
75    int num_ioports;
76    /* Sorted list of ioport functions */
77    ioport_entry_t **ioports;
78    uint16_t alloc_addr;
79} vmm_io_port_list_t;
80
81/***
82 * @function vmm_io_port_init(io_list, ioport_alloc_addr)
83 * Initialize the io port list manager.
84 * @param {vmm_io_port_list_t **} io_list       Pointer to io_port list handle. This will be allocated and initialised
85 * @param {uint16_t} ioport_alloc_addr          Base ioport address we can safely bump allocate from (doesn't conflict with other ioports).
86 *                                              This is used when registering ioport handlers of type 'IOPORT_FREE'
87 * @return                                      0 for success, otherwise -1 for error
88 */
89int vmm_io_port_init(vmm_io_port_list_t **io_list, uint16_t ioport_alloc_addr);
90
91/***
92 * @function vmm_io_port_add_handler(io_list, ioport_range, ioport_interface, port_type)
93 * Add an io port range for emulation
94 * @param {vmm_io_port_list_t *} io_list            Handle to ioport list. This is where the new ioport handler will be appended to
95 * @param {ioport_range_t} ioport_range             Range the ioport handler will emulate
96 * @param {ioport_interface_t} ioport_interface     IOPort emulation interface
97 * @param {ioport_type_t} port_type                 The type of ioport being registered - IOPORT_FREE, IOPORT_ADDR
98 * @return                                          NULL for error, otherwise pointer to newly created ioport entry
99 */
100ioport_entry_t *vmm_io_port_add_handler(vmm_io_port_list_t *io_list, ioport_range_t ioport_range,
101                                        ioport_interface_t ioport_interface, ioport_type_t port_type);
102
103/***
104 * @function emulate_io_handler(io_port, port_no, is_in, size, data)
105 * From a set of registered ioports, emulate an io instruction given a current ioport access.
106 * @param {vmm_io_port_list_t *} io_port        List of registered ioports with in/out handlers
107 * @param {unsigned int} port_no                IOPort address being accessed
108 * @param {bool} is_in                          True if we are performing an io in operation, otherwise False
109 * @param {size_t} size                         Size of io access
110 * @param {unsigned int *} data                 Pointer with the data being written if io-out op, otherwise will be populated with data from an io-in op
111 * @return                                      0 if handled, 1 if unhandled, otherwise -1 for error
112 */
113int emulate_io_handler(vmm_io_port_list_t *io_port, unsigned int port_no, bool is_in, size_t size, unsigned int *data);
114