Skip to content

Commit e9a734f

Browse files
committed
ref(core/remio): I/O request array and I/O request events
This commit is divided into two parts: - Replace the two-dimensional I/O requests array with a one-dimensional array (1-to-1 vCPU mapping) and move the array into the Remote I/O device. - Replace the I/O request event internal IDs (CPU and vCPU IDs) with a dynamically allocated request ID by the frontend guest using the extended objpool API Signed-off-by: João Peixoto <[email protected]>
1 parent 0e76f37 commit e9a734f

File tree

1 file changed

+77
-78
lines changed

1 file changed

+77
-78
lines changed

src/core/remio.c

Lines changed: 77 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
#define REMIO_MAX_DEVICES 32
2020
#define REMIO_DEVICE_UNINITIALIZED -1
21-
#define REMIO_CPU_NUM PLAT_CPU_NUM
2221
#define REMIO_VCPU_NUM PLAT_CPU_NUM
2322
#define REMIO_NUM_DEV_TYPES (REMIO_DEV_BACKEND - REMIO_DEV_FRONTEND + 1)
2423

@@ -63,12 +62,11 @@ enum REMIO_STATE {
6362
*/
6463
union remio_cpu_msg_data {
6564
struct {
66-
uint8_t id; /**< Remote I/O ID */
67-
uint8_t cpu_id; /**< Frontend CPU ID */
68-
uint8_t vcpu_id; /**< Frontend vCPU ID */
69-
uint8_t interrupt; /**< Interrupt ID */
65+
uint8_t remio_id; /**< Remote I/O ID */
66+
uint8_t request_id; /**< Remote I/O request ID */
67+
uint8_t interrupt; /**< Interrupt ID */
7068
};
71-
uint64_t raw; /**< Raw data */
69+
uint64_t raw; /**< Raw data */
7270
};
7371

7472
/**
@@ -81,6 +79,7 @@ struct remio_request {
8179
unsigned long op; /**< MMIO operation type (read or write) */
8280
unsigned long value; /**< Value to be written or read */
8381
unsigned long reg; /**< vCPU resgiter used during the MMIO access */
82+
cpuid_t cpu_id; /**< CPU ID of the frontend VM that performed the MMIO access */
8483
enum REMIO_STATE state; /**< I/O request state */
8584
};
8685

@@ -92,9 +91,8 @@ struct remio_request {
9291
* CPUs and vCPUs slots to find the next I/O request to be processed
9392
*/
9493
struct remio_request_event {
95-
node_t node; /** Node */
96-
cpuid_t cpu_id; /** CPU ID of the frontend VM that issued the I/O request */
97-
vcpuid_t vcpu_id; /** vCPU ID of the frontend VM that issued the I/O request */
94+
node_t node; /** Node */
95+
objpool_id_t id; /** ID */
9896
};
9997

10098
/**
@@ -119,18 +117,16 @@ struct remio_device_config {
119117
* @brief This structure comprises all the information needed about a Remote I/O device
120118
*/
121119
struct remio_device {
122-
node_t node; /**< Node */
123-
remio_id_t id; /**< Remote I/O device ID */
124-
struct remio_device_config config; /**< Remote I/O device configuration */
125-
struct list request_event_list; /**< List of pending I/O requests events */
120+
node_t node; /**< Node */
121+
remio_id_t id; /**< Remote I/O device ID */
122+
struct remio_device_config config; /**< Remote I/O device configuration */
123+
struct list request_event_list; /**< List of pending I/O requests events */
124+
struct remio_request requests[REMIO_VCPU_NUM]; /**< Array of Remote I/O requests */
126125
};
127126

128127
/** List of Remote I/O devices */
129128
struct list remio_device_list;
130129

131-
/** Array of Remote I/O requests */
132-
struct remio_request remio_requests[REMIO_CPU_NUM][REMIO_VCPU_NUM];
133-
134130
/**
135131
* @brief Remote I/O CPU message handler
136132
* @param event Message event (REMIO_CPU_MSG_*)
@@ -158,6 +154,7 @@ static void remio_create_request(struct emul_access* acc, struct remio_request*
158154
request->reg = acc->reg;
159155
request->access_width = acc->width;
160156
request->state = REMIO_STATE_PENDING;
157+
request->cpu_id = cpu()->id;
161158

162159
if (acc->write) {
163160
long unsigned int value = vcpu_readreg(cpu()->vcpu, acc->reg);
@@ -171,62 +168,62 @@ static void remio_create_request(struct emul_access* acc, struct remio_request*
171168

172169
/**
173170
* @brief Gets the Remote I/O request indexed by the CPU ID and vCPU ID
174-
* @param cpu_id CPU ID of the frontend VM that issued the I/O request
175-
* @param vcpu_id vCPU ID of the frontend VM that issued the I/O request
171+
* @param device Pointer to the Remote I/O device
172+
* @param id Remote I/O request ID
176173
* @return Returns the Remote I/O request
177174
*/
178-
static inline struct remio_request* remio_get_request(unsigned long cpu_id, unsigned long vcpu_id)
175+
static inline struct remio_request* remio_get_request(struct remio_device* device, unsigned long id)
179176
{
180-
return &remio_requests[cpu_id][vcpu_id];
177+
return &device->requests[id];
181178
}
182179

183180
/**
184181
* @brief Inserts a new Remote I/O request
185-
* @param cpu_id CPU ID of the frontend VM that issued the I/O request
186-
* @param vcpu_id vCPU ID of the frontend VM that issued the I/O request
182+
* @param device Pointer to the Remote I/O device
183+
* @param id Remote I/O request ID
187184
* @param request Pointer to the Remote I/O request
188185
*/
189-
static inline void remio_insert_request(unsigned long cpu_id, unsigned long vcpu_id,
186+
static inline void remio_insert_request(struct remio_device* device, unsigned long id,
190187
struct remio_request* request)
191188
{
192-
remio_requests[cpu_id][vcpu_id] = *request;
189+
device->requests[id] = *request;
193190
}
194191

195192
/**
196193
* @brief Sets the state of a Remote I/O request
197-
* @param cpu_id CPU ID of the frontend VM that issued the I/O request
198-
* @param vcpu_id vCPU ID of the frontend VM that issued the I/O request
194+
* @param device Pointer to the Remote I/O device
195+
* @param id Remote I/O request ID
199196
* @param state New state of the I/O request
200197
*/
201-
static inline void remio_set_request_state(unsigned long cpu_id, unsigned long vcpu_id,
198+
static inline void remio_set_request_state(struct remio_device* device, unsigned long id,
202199
enum REMIO_STATE state)
203200
{
204-
struct remio_request* request = remio_get_request(cpu_id, vcpu_id);
201+
struct remio_request* request = remio_get_request(device, id);
205202
request->state = state;
206203
}
207204

208205
/**
209206
* @brief Gets the state of a Remote I/O request
210-
* @param cpu_id CPU ID of the frontend VM that issued the I/O request
211-
* @param vcpu_id vCPU ID of the frontend VM that issued the I/O request
207+
* @param device Pointer to the Remote I/O device
208+
* @param id Remote I/O request ID
212209
* @return Returns the state of the I/O request
213210
*/
214-
static inline enum REMIO_STATE remio_get_request_state(unsigned long cpu_id, unsigned long vcpu_id)
211+
static inline enum REMIO_STATE remio_get_request_state(struct remio_device* device, unsigned long id)
215212
{
216-
struct remio_request* request = remio_get_request(cpu_id, vcpu_id);
213+
struct remio_request* request = remio_get_request(device, id);
217214
return request->state;
218215
}
219216

220217
/**
221218
* @brief Sets the value of a Remote I/O request
222-
* @param cpu_id CPU ID of the frontend VM that issued the I/O request
223-
* @param vcpu_id vCPU ID of the frontend VM that issued the I/O request
219+
* @param device Pointer to the Remote I/O device
220+
* @param id Remote I/O request ID
224221
* @param value New value of the I/O request
225222
*/
226-
static inline void remio_set_request_value(unsigned long cpu_id, unsigned long vcpu_id,
223+
static inline void remio_set_request_value(struct remio_device* device, unsigned long id,
227224
unsigned long value)
228225
{
229-
struct remio_request* request = remio_get_request(cpu_id, vcpu_id);
226+
struct remio_request* request = remio_get_request(device, id);
230227
request->value = value;
231228
}
232229

@@ -236,14 +233,14 @@ static inline void remio_set_request_value(unsigned long cpu_id, unsigned long v
236233
*/
237234
static struct remio_request_event* remio_create_event(void)
238235
{
239-
struct remio_request_event* event = objpool_alloc(&remio_request_event_pool);
236+
objpool_id_t id;
237+
struct remio_request_event* event = objpool_alloc_with_id(&remio_request_event_pool, &id);
240238
if (event == NULL) {
241239
return NULL;
242240
}
243241

244-
/** Fill the I/O request event information */
245-
event->cpu_id = cpu()->id;
246-
event->vcpu_id = cpu()->vcpu->id;
242+
/** Fill the I/O request event ID */
243+
event->id = id;
247244

248245
return event;
249246
}
@@ -367,18 +364,16 @@ static struct remio_device* remio_find_vm_dev_by_addr(struct vm* vm, unsigned lo
367364
* @brief Sends a Remote I/O CPU message to the target CPU
368365
* @param event Message event (REMIO_CPU_MSG_*)
369366
* @param target_cpu Target CPU ID
370-
* @param id Remote I/O device ID
371-
* @param cpu_id CPU ID of the frontend VM that issued the I/O request
372-
* @param vcpu_id vCPU ID of the frontend VM that issued the I/O request
367+
* @param remio_id Remote I/O device ID
368+
* @param request_id Remote I/O request ID
373369
* @param interrupt Interrupt ID
374370
*/
375371
static void remio_cpu_send_msg(enum REMIO_CPU_MSG_EVENT event, unsigned long target_cpu,
376-
unsigned long id, unsigned long cpu_id, unsigned long long vcpu_id, unsigned long interrupt)
372+
unsigned long remio_id, unsigned long request_id, unsigned long interrupt)
377373
{
378374
union remio_cpu_msg_data data = {
379-
.id = (uint8_t)id,
380-
.cpu_id = (uint8_t)cpu_id,
381-
.vcpu_id = (uint8_t)vcpu_id,
375+
.remio_id = (uint8_t)remio_id,
376+
.request_id = (uint8_t)request_id,
382377
.interrupt = (uint8_t)interrupt,
383378
};
384379
struct cpu_msg msg = { (uint32_t)REMIO_CPUMSG_ID, event, data.raw };
@@ -481,9 +476,9 @@ void remio_init(void)
481476
}
482477

483478
/** Initialize the Remote I/O requests array */
484-
for (size_t cpu_idx = 0; cpu_idx < REMIO_CPU_NUM; cpu_idx++) {
485-
for (size_t vcpu_idx = 0; vcpu_idx < REMIO_VCPU_NUM; vcpu_idx++) {
486-
remio_set_request_state(cpu_idx, vcpu_idx, REMIO_STATE_FREE);
479+
list_foreach (remio_device_list, struct remio_device, dev) {
480+
for (size_t i = 0; i < REMIO_VCPU_NUM; i++) {
481+
dev->requests[i].state = REMIO_STATE_FREE;
487482
}
488483
}
489484
}
@@ -521,45 +516,42 @@ static long int remio_handle_ask(unsigned long addr, unsigned long value,
521516
return ret;
522517
}
523518

524-
if (remio_get_request_state(event->cpu_id, event->vcpu_id) != REMIO_STATE_PENDING) {
525-
objpool_free(&remio_request_event_pool, event);
519+
if (remio_get_request_state(device, event->id) != REMIO_STATE_PENDING) {
526520
return ret;
527521
}
528522

529523
/** Calculate the remaining number of pending I/O requests */
530524
ret = (long int)remio_get_request_event_count(device);
531525

532-
remio_set_request_state(event->cpu_id, event->vcpu_id, REMIO_STATE_PROCESSING);
526+
remio_set_request_state(device, event->id, REMIO_STATE_PROCESSING);
533527

534-
struct remio_request* request = remio_get_request(event->cpu_id, event->vcpu_id);
528+
struct remio_request* request = remio_get_request(device, event->id);
535529

536530
/** Write the I/O request information to the backend VM's vCPU registers */
537531
vcpu_writereg(cpu()->vcpu, HYPCALL_OUT_ARG_REG(0), request->addr);
538532
vcpu_writereg(cpu()->vcpu, HYPCALL_OUT_ARG_REG(1), request->op);
539533
vcpu_writereg(cpu()->vcpu, HYPCALL_OUT_ARG_REG(2), request->value);
540534
vcpu_writereg(cpu()->vcpu, HYPCALL_OUT_ARG_REG(3), request->access_width);
541-
vcpu_writereg(cpu()->vcpu, HYPCALL_OUT_ARG_REG(4), event->cpu_id);
542-
vcpu_writereg(cpu()->vcpu, HYPCALL_OUT_ARG_REG(5), event->vcpu_id);
543-
544-
objpool_free(&remio_request_event_pool, event);
535+
vcpu_writereg(cpu()->vcpu, HYPCALL_OUT_ARG_REG(4), event->id);
545536

546537
return ret;
547538
}
548539

549540
/**
550541
* @brief Handles the Remote I/O read and write operations
551542
* @param value Value to be written or read
552-
* @param cpu_id CPU ID of the frontend VM that issued the I/O request
553-
* @param vcpu_id vCPU ID of the frontend VM that issued the I/O request
543+
* @param request_id Remote I/O request ID
544+
* @param device Pointer to the Remote I/O device
554545
* @return Returns true if the operation was successful, false otherwise
555546
*/
556-
static bool remio_handle_rw(unsigned long value, unsigned long cpu_id, unsigned long vcpu_id)
547+
static bool remio_handle_rw(unsigned long value, unsigned long request_id,
548+
struct remio_device* device)
557549
{
558-
if (remio_get_request_state(cpu_id, vcpu_id) != REMIO_STATE_PROCESSING) {
550+
if (remio_get_request_state(device, request_id) != REMIO_STATE_PROCESSING) {
559551
return false;
560552
}
561-
remio_set_request_value(cpu_id, vcpu_id, value);
562-
remio_set_request_state(cpu_id, vcpu_id, REMIO_STATE_COMPLETE);
553+
remio_set_request_value(device, request_id, value);
554+
remio_set_request_state(device, request_id, REMIO_STATE_COMPLETE);
563555
return true;
564556
}
565557

@@ -568,16 +560,18 @@ static bool remio_handle_rw(unsigned long value, unsigned long cpu_id, unsigned
568560
* @note This function is executed by the frontend VM and is responsible for updating the
569561
* vCPU register in case of a read operation and activating the frontend vCPU
570562
* @param event Message event (REMIO_CPU_MSG_*)
571-
* @param cpu_id CPU ID of the frontend VM that issued the I/O request
572-
* @param vcpu_id vCPU ID of the frontend VM that issued the I/O request
563+
* @param remio_id Remote I/O device ID
564+
* @param request_id Remote I/O request ID
573565
* @return Returns true if the operation was successful, false otherwise
574566
*/
575-
static bool remio_cpu_post_work(uint32_t event, uint8_t cpu_id, uint8_t vcpu_id)
567+
static bool remio_cpu_post_work(uint32_t event, uint8_t remio_id, uint8_t request_id)
576568
{
577-
if (remio_get_request_state(cpu_id, vcpu_id) != REMIO_STATE_COMPLETE) {
569+
struct remio_device* device = remio_find_dev_by_id(remio_id);
570+
571+
if (remio_get_request_state(device, request_id) != REMIO_STATE_COMPLETE) {
578572
return false;
579573
}
580-
struct remio_request* request = remio_get_request(cpu_id, vcpu_id);
574+
struct remio_request* request = remio_get_request(device, request_id);
581575

582576
switch (event) {
583577
case REMIO_CPU_MSG_READ:
@@ -587,7 +581,13 @@ static bool remio_cpu_post_work(uint32_t event, uint8_t cpu_id, uint8_t vcpu_id)
587581
break;
588582
}
589583

590-
remio_set_request_state(cpu_id, vcpu_id, REMIO_STATE_FREE);
584+
remio_set_request_state(device, request_id, REMIO_STATE_FREE);
585+
586+
struct remio_request_event* request_event =
587+
objpool_get_by_id(&remio_request_event_pool, request_id);
588+
if (request_event != NULL) {
589+
objpool_free(&remio_request_event_pool, request_event);
590+
}
591591

592592
cpu()->vcpu->active = true;
593593

@@ -601,8 +601,7 @@ long int remio_hypercall(unsigned long arg0, unsigned long arg1, unsigned long a
601601
unsigned long addr = arg1;
602602
unsigned long op = arg2;
603603
unsigned long value = vcpu_readreg(cpu()->vcpu, HYPCALL_IN_ARG_REG(3));
604-
unsigned long cpu_id = vcpu_readreg(cpu()->vcpu, HYPCALL_IN_ARG_REG(4));
605-
unsigned long vcpu_id = vcpu_readreg(cpu()->vcpu, HYPCALL_IN_ARG_REG(5));
604+
unsigned long request_id = vcpu_readreg(cpu()->vcpu, HYPCALL_IN_ARG_REG(4));
606605
struct remio_device* device = NULL;
607606
struct vm* vm = cpu()->vcpu->vm;
608607

@@ -628,20 +627,20 @@ long int remio_hypercall(unsigned long arg0, unsigned long arg1, unsigned long a
628627
switch (op) {
629628
case REMIO_HYP_WRITE:
630629
case REMIO_HYP_READ:
631-
if (!remio_handle_rw(value, cpu_id, vcpu_id)) {
630+
if (!remio_handle_rw(value, request_id, device)) {
632631
ret = -HC_E_FAILURE;
633632
} else {
634633
/** Send a CPU message to the backend VM to execute the post work */
635634
remio_cpu_send_msg(op == REMIO_HYP_WRITE ? REMIO_CPU_MSG_WRITE : REMIO_CPU_MSG_READ,
636-
cpu_id, remio_dev_id, cpu_id, vcpu_id, 0);
635+
device->requests[request_id].cpu_id, remio_dev_id, request_id, 0);
637636
}
638637
break;
639638
case REMIO_HYP_ASK:
640639
ret = remio_handle_ask(addr, value, device);
641640
break;
642641
case REMIO_HYP_NOTIFY:
643642
/** Send a CPU message to the frontend VM to inject an interrupt */
644-
remio_cpu_send_msg(REMIO_CPU_MSG_NOTIFY, device->config.frontend.cpu_id, 0, 0, 0,
643+
remio_cpu_send_msg(REMIO_CPU_MSG_NOTIFY, device->config.frontend.cpu_id, 0, 0,
645644
device->config.frontend.interrupt);
646645
break;
647646
default:
@@ -670,13 +669,13 @@ bool remio_mmio_emul_handler(struct emul_access* acc)
670669
struct remio_request_event* event = remio_create_event();
671670

672671
/** Insert the I/O request into the Remote I/O request array */
673-
remio_insert_request(event->cpu_id, event->vcpu_id, &request);
672+
remio_insert_request(device, event->id, &request);
674673

675674
/** Push the I/O request event into the Remote I/O device list */
676675
remio_push_request_event(device, event);
677676

678677
/** Send a CPU message to the backend VM to then inject an interrupt */
679-
remio_cpu_send_msg(REMIO_CPU_MSG_NOTIFY, device->config.backend.cpu_id, 0, 0, 0,
678+
remio_cpu_send_msg(REMIO_CPU_MSG_NOTIFY, device->config.backend.cpu_id, 0, 0,
680679
device->config.backend.interrupt);
681680

682681
/** Pause the current vCPU to wait for the MMIO emulation to be completed */
@@ -691,7 +690,7 @@ static void remio_cpu_handler(uint32_t event, uint64_t data)
691690
switch (event) {
692691
case REMIO_CPU_MSG_WRITE:
693692
case REMIO_CPU_MSG_READ:
694-
if (!remio_cpu_post_work(event, ipc_data.cpu_id, ipc_data.vcpu_id)) {
693+
if (!remio_cpu_post_work(event, ipc_data.remio_id, ipc_data.request_id)) {
695694
ERROR("Failed to perform the post work after the completion of the I/O request");
696695
}
697696
break;

0 commit comments

Comments
 (0)