summaryrefslogtreecommitdiffstats
path: root/include/VBox/msi.h
blob: 34aae831edda3612d23bca620d862ac77a115543 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/** @file
 * MSI - Message signalled interrupts support.
 */

/*
 * Copyright (C) 2010-2022 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
 * in the VirtualBox distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 *
 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
 */

#ifndef VBOX_INCLUDED_msi_h
#define VBOX_INCLUDED_msi_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <iprt/assert.h>

#include <VBox/pci.h>

/* Constants for Intel APIC MSI messages */
#define VBOX_MSI_DATA_VECTOR_SHIFT           0
#define VBOX_MSI_DATA_VECTOR_MASK            0x000000ff
#define VBOX_MSI_DATA_VECTOR(v)              (((v) << VBOX_MSI_DATA_VECTOR_SHIFT) & \
                                                  VBOX_MSI_DATA_VECTOR_MASK)
#define VBOX_MSI_DATA_DELIVERY_MODE_SHIFT    8
#define  VBOX_MSI_DATA_DELIVERY_FIXED        (0 << VBOX_MSI_DATA_DELIVERY_MODE_SHIFT)
#define  VBOX_MSI_DATA_DELIVERY_LOWPRI       (1 << VBOX_MSI_DATA_DELIVERY_MODE_SHIFT)

#define VBOX_MSI_DATA_LEVEL_SHIFT            14
#define  VBOX_MSI_DATA_LEVEL_DEASSERT        (0 << VBOX_MSI_DATA_LEVEL_SHIFT)
#define  VBOX_MSI_DATA_LEVEL_ASSERT          (1 << VBOX_MSI_DATA_LEVEL_SHIFT)

#define VBOX_MSI_DATA_TRIGGER_SHIFT          15
#define  VBOX_MSI_DATA_TRIGGER_EDGE          (0 << VBOX_MSI_DATA_TRIGGER_SHIFT)
#define  VBOX_MSI_DATA_TRIGGER_LEVEL         (1 << VBOX_MSI_DATA_TRIGGER_SHIFT)

/**
 * MSI Interrupt Delivery modes.
 * In accordance with the Intel spec.
 * See Intel spec. "10.11.2 Message Data Register Format".
 */
#define VBOX_MSI_DELIVERY_MODE_FIXED         (0)
#define VBOX_MSI_DELIVERY_MODE_LOWEST_PRIO   (1)
#define VBOX_MSI_DELIVERY_MODE_SMI           (2)
#define VBOX_MSI_DELIVERY_MODE_NMI           (4)
#define VBOX_MSI_DELIVERY_MODE_INIT          (5)
#define VBOX_MSI_DELIVERY_MODE_EXT_INT       (7)

/**
 * MSI region, actually same as LAPIC MMIO region, but listens on bus,
 * not CPU, accesses.
 */
#define VBOX_MSI_ADDR_BASE                   0xfee00000
#define VBOX_MSI_ADDR_SIZE                   0x100000

#define VBOX_MSI_ADDR_SHIFT                  20

#define VBOX_MSI_ADDR_DEST_MODE_SHIFT        2
#define  VBOX_MSI_ADDR_DEST_MODE_PHYSICAL    (0 << VBOX_MSI_ADDR_DEST_MODE_SHIFT)
#define  VBOX_MSI_ADDR_DEST_MODE_LOGICAL     (1 << VBOX_MSI_ADDR_DEST_MODE_SHIFT)

#define VBOX_MSI_ADDR_REDIRECTION_SHIFT      3
#define  VBOX_MSI_ADDR_REDIRECTION_CPU       (0 << VBOX_MSI_ADDR_REDIRECTION_SHIFT)
                                        /* dedicated cpu */
#define  VBOX_MSI_ADDR_REDIRECTION_LOWPRI    (1 << VBOX_MSI_ADDR_REDIRECTION_SHIFT)
                                        /* lowest priority */

#define VBOX_MSI_ADDR_DEST_ID_SHIFT          12
#define  VBOX_MSI_ADDR_DEST_ID_MASK          0x00ffff0
#define  VBOX_MSI_ADDR_DEST_ID(dest)         (((dest) << VBOX_MSI_ADDR_DEST_ID_SHIFT) & \
                                         VBOX_MSI_ADDR_DEST_ID_MASK)
#define VBOX_MSI_ADDR_EXT_DEST_ID(dest)      ((dest) & 0xffffff00)

#define VBOX_MSI_ADDR_IR_EXT_INT             (1 << 4)
#define VBOX_MSI_ADDR_IR_SHV                 (1 << 3)
#define VBOX_MSI_ADDR_IR_INDEX1(index)       ((index & 0x8000) >> 13)
#define VBOX_MSI_ADDR_IR_INDEX2(index)       ((index & 0x7fff) << 5)

/* Maximum number of vectors, per device/function */
#define VBOX_MSI_MAX_ENTRIES                  32

/* Offsets in MSI PCI capability structure (VBOX_PCI_CAP_ID_MSI) */
#define VBOX_MSI_CAP_MESSAGE_CONTROL          0x02
#define VBOX_MSI_CAP_MESSAGE_ADDRESS_32       0x04
#define VBOX_MSI_CAP_MESSAGE_ADDRESS_LO       0x04
#define VBOX_MSI_CAP_MESSAGE_ADDRESS_HI       0x08
#define VBOX_MSI_CAP_MESSAGE_DATA_32          0x08
#define VBOX_MSI_CAP_MESSAGE_DATA_64          0x0c
#define VBOX_MSI_CAP_MASK_BITS_32             0x0c
#define VBOX_MSI_CAP_PENDING_BITS_32          0x10
#define VBOX_MSI_CAP_MASK_BITS_64             0x10
#define VBOX_MSI_CAP_PENDING_BITS_64          0x14

/* We implement MSI with per-vector masking */
#define VBOX_MSI_CAP_SIZE_32                  0x14
#define VBOX_MSI_CAP_SIZE_64                  0x18

/**
 * MSI-X differs from MSI by the fact that a dedicated physical page (in device
 * memory) is assigned for MSI-X table, and Pending Bit Array (PBA), which is
 * recommended to be separated from the main table by at least 2K.
 *
 * @{
 */
/** Size of a MSI-X page */
#define VBOX_MSIX_PAGE_SIZE                   0x1000
/** Pending interrupts (PBA) */
#define VBOX_MSIX_PAGE_PENDING                (VBOX_MSIX_PAGE_SIZE / 2)
/** Maximum number of vectors, per device/function */
#define VBOX_MSIX_MAX_ENTRIES                 2048
/** Size of MSI-X PCI capability */
#define VBOX_MSIX_CAP_SIZE                    12
/** Offsets in MSI-X PCI capability structure (VBOX_PCI_CAP_ID_MSIX) */
#define VBOX_MSIX_CAP_MESSAGE_CONTROL         0x02
#define VBOX_MSIX_TABLE_BIROFFSET             0x04
#define VBOX_MSIX_PBA_BIROFFSET               0x08
/** Size of single MSI-X table entry */
#define VBOX_MSIX_ENTRY_SIZE                  16
/** @} */

/**
 * MSI Address Register.
 */
typedef union MSIADDR
{
    /*
     * Intel and AMD xAPIC format.
     * See Intel spec. 10.11.1 "Message Address Register Format".
     * This also conforms to the AMD IOMMU spec. which omits specifying
     * individual fields but specifies reserved bits.
     */
    struct
    {
        uint32_t   u2Ign0      :  2;    /**< Bits 1:0   - Ignored (read as 0, writes ignored). */
        uint32_t   u1DestMode  :  1;    /**< Bit  2     - DM: Destination Mode. */
        uint32_t   u1RedirHint :  1;    /**< Bit  3     - RH: Redirection Hint. */
        uint32_t   u8Rsvd0     :  8;    /**< Bits 11:4  - Reserved. */
        uint32_t   u8DestId    :  8;    /**< Bits 19:12 - Destination Id. */
        uint32_t   u12Addr     : 12;    /**< Bits 31:20 - Address. */
        uint32_t   u32Rsvd0;            /**< Bits 63:32 - Reserved. */
    } n;

    /*
     * Intel x2APIC Format.
     * See Intel VT-d spec. 5.1.6.2 "Programming in Intel 64 x2APIC Mode".
     */
    struct
    {
        uint32_t   u2Ign0      :  2;    /**< Bits 1:0   - Ignored (read as 0, writes ignored). */
        uint32_t   u1DestMode  :  1;    /**< Bit  2     - DM: Destination Mode. */
        uint32_t   u1RedirHint :  1;    /**< Bit  3     - RH: Redirection Hint. */
        uint32_t   u8Rsvd0     :  8;    /**< Bits 11:4  - Reserved. */
        uint32_t   u8DestIdLo  :  8;    /**< Bits 19:12 - Destination Id (bits 7:0). */
        uint32_t   u12Addr     : 12;    /**< Bits 31:20 - Address. */
        uint32_t   u8Rsvd      :  8;    /**< Bits 39:32 - Reserved. */
        uint32_t   u24DestIdHi : 24;    /**< Bits 63:40 - Destination Id (bits 31:8). */
    } x2apic;

    /*
     * Intel IOMMU Remappable Interrupt Format.
     * See Intel VT-d spec. 5.1.2.2 "Interrupt Requests in Remappable Format".
     */
    struct
    {
        uint32_t   u2Ign0         :  2; /**< Bits 1:0   - Ignored (read as 0, writes ignored). */
        uint32_t   u1IntrIndexHi  :  1; /**< Bit  2     - Interrupt Index[15]. */
        uint32_t   fShv           :  1; /**< Bit  3     - Sub-Handle Valid. */
        uint32_t   fIntrFormat    :  1; /**< Bit  4     - Interrupt Format (1=remappable, 0=compatibility). */
        uint32_t   u14IntrIndexLo : 15; /**< Bits 19:5  - Interrupt Index[14:0]. */
        uint32_t   u12Addr        : 12; /**< Bits 31:20 - Address. */
        uint32_t   u32Rsvd0;            /**< Bits 63:32 - Reserved. */
    } dmar_remap;

    /** The 32-bit unsigned integer view. */
    uint32_t    au32[2];

    /** The 64-bit unsigned integer view. */
    uint64_t    u64;
} MSIADDR;
AssertCompileSize(MSIADDR, 8);
/** Pointer to an MSI address register. */
typedef MSIADDR *PMSIADDR;
/** Pointer to a const MSI address register. */
typedef MSIADDR const *PCMSIADDR;

/** Mask of valid bits in the MSI address register. According to the AMD IOMMU spec.
 *  and presumably the PCI spec., the top 32-bits are not reserved. From a PCI/IOMMU
 *  standpoint this makes sense. However, when dealing with the CPU side of things
 *  we might want to ensure the upper bits are reserved. Does x86/x64 really
 *  support a 64-bit MSI address? */
#define VBOX_MSI_ADDR_VALID_MASK           UINT64_C(0xfffffffffffffffc)
#define VBOX_MSI_ADDR_ADDR_MASK            UINT64_C(0x00000000fff00000)

/**
 * MSI Data Register.
 */
typedef union MSIDATA
{
    /*
     * Intel and AMD xAPIC format.
     * See Intel spec. 10.11.2 "Message Data Register Format".
     * This also conforms to the AMD IOMMU spec. which omits specifying
     * individual fields but specifies reserved bits.
     */
    struct
    {
        uint32_t    u8Vector       : 8;     /**< Bits 7:0   - Vector. */
        uint32_t    u3DeliveryMode : 3;     /**< Bits 10:8  - Delivery Mode. */
        uint32_t    u3Rsvd0        : 3;     /**< Bits 13:11 - Reserved. */
        uint32_t    u1Level        : 1;     /**< Bit  14    - Level. */
        uint32_t    u1TriggerMode  : 1;     /**< Bit  15    - Trigger Mode (0=edge, 1=level). */
        uint32_t    u16Rsvd0       : 16;    /**< Bits 31:16 - Reserved. */
    } n;

    /*
     * Intel x2APIC Format.
     * See Intel VT-d spec. 5.1.6.2 "Programming in Intel 64 x2APIC Mode".
     */
    struct
    {
        uint32_t    u8Vector       :  8;    /**< Bits 7:0   - Vector. */
        uint32_t    u1DeliveryMode :  1;    /**< Bit  8     - Delivery Mode (0=fixed, 1=lowest priority). */
        uint32_t    u23Rsvd0       : 23;    /**< Bits 31:9  - Reserved. */
    } x2apic;

    /*
     * Intel IOMMU Remappable Interrupt Format.
     * See Intel VT-d spec. 5.1.2.2 "Interrupt Requests in Remappable Format".
     */
    struct
    {
        uint16_t    u16SubHandle;
        uint16_t    u16Rsvd0;
    } dmar_remap;

    /** The 32-bit unsigned integer view. */
    uint32_t    u32;
} MSIDATA;
AssertCompileSize(MSIDATA, 4);
/** Pointer to an MSI data register. */
typedef MSIDATA *PMSIDATA;
/** Pointer to a const MSI data register. */
typedef MSIDATA const *PCMSIDATA;

/** Mask of valid bits in the MSI data register. */
#define VBOX_MSI_DATA_VALID_MASK           UINT64_C(0x000000000000ffff)

/**
 * MSI Message (Address and Data Register Pair).
 */
typedef struct MSIMSG
{
    /** The MSI Address Register. */
    MSIADDR      Addr;
    /** The MSI Data Register. */
    MSIDATA     Data;
} MSIMSG;

#endif /* !VBOX_INCLUDED_msi_h */