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 */
6463union 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 */
9493struct 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 */
121119struct 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 */
129128struct 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 */
237234static 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 */
375371static 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