summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_rm_emulation.h
blob: 9ff74e9fa4defadc5c00288110ae1174fab3acc3 (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
/*
 * GSP-RM Emulation (physical-path) for Host-Side vGPU
 *
 * Emulates the GSP-RM firmware's msgq-based RPC channel for a guest driver
 * that believes it is driving a real physical GPU. The guest driver:
 *   - boots the "GSP" (falcon stages emulated in gsp_emulation.c)
 *   - programs libos init args address into GSP MAILBOX0/1
 *   - expects GSP-RM to msgqInit the status queue in *guest system memory*
 *     (shared command/status queue buffer described by GSP_ARGUMENTS_CACHED)
 *   - polls the status queue for NV_VGPU_MSG_EVENT_GSP_INIT_DONE and then
 *     issues the RM RPC sequence on the command queue.
 *
 * Since there is no real GSP engine, this module performs the "virtual DMA"
 * on behalf of the device using vfio_dma_rw() (CPU copies through the VFIO
 * container's IOMMU mappings, IOVA == guest physical address).
 */

#ifndef _GSP_RM_EMULATION_H_
#define _GSP_RM_EMULATION_H_

#include <linux/types.h>

#include "nvidia-vgpu-vfio.h"

struct gsp_emu_context;

/* Wire constants (from NVIDIA OpenRM 570.144 msgq/rpc headers - the guest
 * driver is the 570.144 stock runfile, whose GSP_MSG_QUEUE_ELEMENT has NO
 * MCTP/NVDM transport headers: authTag[16]+aad[16]+checkSum+seqNum+elemCount
 * +rpc@0x30). */
#define GSPRM_MSGQ_VERSION		0
#define GSPRM_MSGQ_FLAGS_SWAP_RX	1
#define GSPRM_RPC_SIGNATURE		0x43505256  /* NV_VGPU_MSG_SIGNATURE_VALID */
#define GSPRM_RPC_HEADER_VERSION	0x03000000  /* MAJOR_TOT(3)<<24|MINOR_TOT(0)<<16 */

/* RPC function/event numbers (rpc_global_enums.h) */
#define GSPRM_RPC_FUNC_SET_GUEST_SYSTEM_INFO	1
#define GSPRM_RPC_FUNC_ALLOC_ROOT		2
#define GSPRM_RPC_FUNC_GET_GSP_STATIC_INFO	65
#define GSPRM_RPC_FUNC_GSP_SET_SYSTEM_INFO	72
#define GSPRM_RPC_FUNC_SET_REGISTRY		73
#define GSPRM_RPC_FUNC_CONTINUATION_RECORD	71
#define GSPRM_RPC_FUNC_SET_PAGE_DIRECTORY	54
#define GSPRM_RPC_FUNC_UNSET_PAGE_DIRECTORY	79
#define GSPRM_RPC_FUNC_GSP_RM_CONTROL		76
#define GSPRM_RPC_FUNC_GSP_RM_ALLOC		103
#define GSPRM_RPC_FUNC_FREE			10
#define GSPRM_RPC_EVENT_POST_EVENT		0x1003
#define GSPRM_MAX_EVENTS			128
#define GSPRM_RPC_EVENT_GSP_INIT_DONE		0x1001

/* rpc_set_guest_system_info_v03_00: version fields the driver reads back
 * from the reply to negotiate the RPC interface version (ipVersion). */
#define GSPRM_SET_GUEST_INFO_SIZE	0x324
#define GSPRM_VGX_VERSION_MAJOR		0x29
#define GSPRM_VGX_VERSION_MINOR		0x0C

/* "RMARGS" packed big-endian into u64 by _kgspGenerateInitArgId() */
#define GSPRM_LIBOS_ID_RMARGS		0x524D41524753ULL

#define GSPRM_MAX_LIBOS_REGIONS		32
#define GSPRM_QUEUE_ELEMENT_SIZE	0x1000
#define GSPRM_STATUS_QUEUE_SIZE		0x40000

/* msgqTxHeader (msgq_priv.h) */
struct gsprm_msgq_tx_header {
	u32 version;
	u32 size;
	u32 msgSize;
	u32 msgCount;
	u32 writePtr;
	u32 flags;
	u32 rxHdrOff;
	u32 entryOff;
};

/* rpc_message_header_v03_00 (g_rpc-message-header.h) */
struct gsprm_rpc_header {
	u32 header_version;
	u32 signature;
	u32 length;
	u32 function;
	u32 rpc_result;
	u32 rpc_result_private;
	u32 sequence;
	u32 spare;		/* rpc_message_rpc_union_field_v (spare/cpuRmGfid) */
};

/* LibosMemoryRegionInitArgument (libos_init_args.h) - natural alignment, 32B */
struct gsprm_libos_region {
	u64 id8;
	u64 pa;
	u64 size;
	u8  kind;
	u8  loc;
	u8  pad[6];
};

/* MESSAGE_QUEUE_INIT_ARGUMENTS (gsp_init_args.h), x86_64 NvLength=u64 */
struct gsprm_mq_init_args {
	u64 sharedMemPhysAddr;
	u32 pageTableEntryCount;
	u32 pad0;
	u64 cmdQueueOffset;
	u64 statQueueOffset;
	u64 queueElementHdrSize;
	u64 queueElementSizeMin;
	u64 queueElementSizeMax;
	u32 queueHeaderAlign;
	u32 queueElementAlign;
};

struct gsp_rm_emu {
	struct nv_vgpu_device *vgpu;

	bool		parsed;		/* queue chain parsed + status queue linked */
	bool		active;

	unsigned long	last_parse_retry;	/* jiffies of last on_booter_done retry */

	u64		libos_args_gpa;	/* from GSP MAILBOX0/1 */
	u64		gsp_args_gpa;	/* RMARGS region pa */

	/* queue buffer description (from GSP_ARGUMENTS_CACHED) */
	struct gsprm_mq_init_args mq;
	u64		*ptes;		/* pageTableEntryCount guest-phys addrs */

	/* computed queue geometry. cmd_off/stat_off are offsets into the shared
	 * buffer (linear); GPAs must be computed per-access via the page table
	 * (buffer is NV_MEMORY_NONCONTIGUOUS). */
	u64		cmd_off;
	u64		stat_off;
	u64		cmd_gpa;	/* GPA of command queue base (diagnostic) */
	u64		stat_gpa;	/* GPA of status queue base (diagnostic) */
	u32		cmd_size;	/* bytes */
	u32		stat_size;	/* bytes */
	u32		cmd_msgcount;
	u32		stat_msgcount;
	u32		entry_off;	/* 0x1000 (msgq entryOff, both queues) */

	/* GSP-side cursors */
	u32		cmd_read;	/* elements consumed from command queue */
	u32		stat_write;	/* elements written to status queue */
	u32		stat_seq;	/* status record sequence numbers */
	bool		init_done_sent;

	/*
	 * Client page-table geometry, learned from
	 * NV90F1_CTRL_CMD_VASPACE_COPY_SERVER_RESERVED_PDES (0x90f10106):
	 * the client hands us the PHYSICAL addresses of its page-table
	 * levels (root PDE ... leaf PTE) plus the VA range/page shifts.
	 * Used to translate client GPU VAs (e.g. semaphore/pushbuffer VAs)
	 * to guest physical addresses.
	 */
	struct {
		u64	va_lo;
		u64	va_hi;
		u64	page_size;	/* coverage of the root level */
		u32	num_levels;
		struct {
			u64 phys;
			u64 size;
			u32 aperture;	/* 1=sysmem(PA), 2=vidmem(offset) */
			u8  page_shift;
		} levels[6];
	} pt;

	/* stats */
	u64		rpcs_seen;
	u64		rpcs_replied;
	u64		unknown_rpcs;
	u32		alloc_dumps;	/* raw GSP_RM_ALLOC dumps emitted */
	u32		alloc_param_dumps;	/* alloc param dumps emitted */
	u32		ctrl_param_dumps;	/* control param dumps emitted */

	/*
	 * NV01_EVENT objects (class 0x5, allocated via class 0x79 in the
	 * guest ABI). Each carries {hSrcResource, notifyIndex, data}; the
	 * driver allocates one per channel and waits for the GPU to post the
	 * event before it considers submitted work complete.
	 */
	struct mutex	stat_lock;	/* serializes status-queue writers */
	struct {
		u32	h_src;		/* source object (channel handle) */
		u32	h_event;	/* event handle */
		u32	h_client;	/* owning client */
		u32	notify_index;
		u32	data;
		bool	valid;
	} events[GSPRM_MAX_EVENTS];
	u32		events_n;
	u64		events_posted;
};

int  gsp_rm_emu_init(struct nv_vgpu_device *vgpu, struct gsp_emu_context *ctx);
void gsp_rm_emu_fini(struct gsp_emu_context *ctx);
int  gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src);
int  gsp_rm_force_post(struct nv_vgpu_device *vgpu, u32 idx);
int  gsp_rm_post_all_events(struct nv_vgpu_device *vgpu);
int  gsp_rm_dump_state(struct nv_vgpu_device *vgpu);
int  gsp_rm_scan_guest_ram(struct nv_vgpu_device *vgpu, u64 needle,
			   u64 start, u64 end, u32 max_hits);
int  gsp_rm_scan_guest_ram_seq(struct nv_vgpu_device *vgpu, const u32 *pat,
			       u32 npat, u64 start, u64 end, u32 max_hits);
int  gsp_rm_scan_guest_ram_pt(struct nv_vgpu_device *vgpu, u64 pa,
			      u64 start, u64 end, u32 max_hits);
int  gsp_rm_scan_guest_ram_masked(struct nv_vgpu_device *vgpu, u64 value,
				  u64 mask, u64 start, u64 end, u32 max_hits);
void gsp_rm_emu_reset(struct gsp_emu_context *ctx);
void gsp_rm_emu_on_booter_done(struct gsp_emu_context *ctx);
void gsp_rm_emu_poll(struct gsp_emu_context *ctx);

#endif /* _GSP_RM_EMULATION_H_ */