khypervisor  v1
vdev/vdev_gicd.c
Go to the documentation of this file.
00001 #include "vdev_gicd.h"
00002 #include <context.h>
00003 #include <gic_regs.h>
00004 #include <vdev.h>
00005 
00006 #include <log/print.h>
00007 
00008 #define VGICD_ITLINESNUM    128
00009 #define VGICD_TYPER_DEFAULT ((VGICD_ITLINESNUM >> 5) - 1)   // Lines:128, CPU:0, Security Extenstin:No
00010 #define VGICD_IIDR_DEFAULT  (0x43B) // Cortex-A15 */
00011 #define VGICD_NUM_IGROUPR   (VGICD_ITLINESNUM/32)
00012 #define VGICD_NUM_IENABLER  (VGICD_ITLINESNUM/32)
00013 
00014 /*
00015     1. High Priority Registers to be implemented first for test with linux
00016     2. access size support: 8/16/32bit 
00017     3. notifying enable status changed interrupts to outside
00018     4. API for interrupt enable status change callback registeration
00019    */
00020 
00021 /* Virtual GIC Distributor */
00022 /* Priority of implementation
00023    - [V] CTLR, TYPER
00024    - [V] ICFGR
00025    - [V] ITARGETSR
00026    - [V] IPRIORITYR
00027    - [V] ISCENABLER
00028    -----------------------
00029    - [ ] 
00030  */
00031 struct gicd_regs{
00032     uint32_t CTLR;              /*0x000 RW*/
00033     uint32_t TYPER;             /*      RO*/
00034     uint32_t IIDR;              /*      RO*/
00035 
00036     uint32_t IGROUPR[VGICD_NUM_IGROUPR];       /* 0x080 */
00037     uint32_t ISCENABLER[VGICD_NUM_IENABLER];    /* 0x100, ISENABLER/ICENABLER */
00038     uint32_t ISPENDR[32];       /* 0x200, ISPENDR/ICPENDR */
00039     uint32_t ISACTIVER[32];     /* 0x300, ISACTIVER/ICACTIVER */
00040     uint32_t IPRIORITYR[128];   /* 0x400 */
00041     uint32_t ITARGETSR[128];    /* 0x800 [0]: RO, Otherwise, RW */
00042     uint32_t ICFGR[64];         /* 0xC00 */
00043 
00044                                 /* Cortex-A15 */
00045                                     /* 0xD00 GICD_PPISR RO */
00046                                     /* 0xD04 ~ 0xD1C GICD_SPISRn RO */
00047 
00048     uint32_t NSACR[64];         /* 0xE00 */
00049     uint32_t SGIR;              /* 0xF00 WO */
00050     uint32_t CPENDSGIR[4];      /* 0xF10 CPENDSGIR 0xF20 SPENDGIR */
00051 
00052                                 /* 0xFD0 ~ 0xFFC RO Cortex-A15 PIDRn, CIDRn */
00053 };
00054 
00055 struct gicd_handler_entry {
00056     uint32_t offset;
00057     vdev_callback_t handler;
00058 };
00059 
00060 static hvmm_status_t handler_000(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00061 static hvmm_status_t handler_ISCENABLER(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00062 static hvmm_status_t handler_ISCPENDR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00063 static hvmm_status_t handler_ISCACTIVER(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00064 static hvmm_status_t handler_IPRIORITYR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00065 static hvmm_status_t handler_ITARGETSR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00066 static hvmm_status_t handler_ICFGR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00067 static hvmm_status_t handler_PPISPISR_CA15(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00068 static hvmm_status_t handler_NSACR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00069 static hvmm_status_t handler_F00(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size);
00070 
00071 vgicd_changed_istatus_callback_t _cb_changed_istatus = 0;
00072 
00073 static vdev_info_t _vdev_info;
00074 static struct gicd_regs _regs[NUM_GUESTS_STATIC]; 
00075 
00076 static struct gicd_handler_entry _handler_map[0x10] = {
00077 /* 0x00 ~ 0x0F */
00078     { 0x00, handler_000 },              /* CTLR, TYPER, IIDR, IGROUPR */
00079     { 0x01, handler_ISCENABLER },       /* ISENABLER, ICENABLER */
00080     { 0x02, handler_ISCPENDR },         /* ISPENDR, ICPENDR */
00081     { 0x03, handler_ISCACTIVER },       /* ISACTIVER */
00082     { 0x04, handler_IPRIORITYR },       /* IPRIORITYR */
00083     { 0x05, handler_IPRIORITYR },  
00084     { 0x06, handler_IPRIORITYR },  
00085     { 0x07, handler_IPRIORITYR },
00086     { 0x08, handler_ITARGETSR },        /* ITARGETSR */
00087     { 0x09, handler_ITARGETSR },
00088     { 0x0A, handler_ITARGETSR },
00089     { 0x0B, handler_ITARGETSR },
00090     { 0x0C, handler_ICFGR },            /* ICFGR */
00091     { 0x0D, handler_PPISPISR_CA15 },    /* PPISPISR */
00092     { 0x0E, handler_NSACR },            /* NSACR */
00093     { 0x0F, handler_F00 },              /* SGIR, CPENDSGIR, SPENDGIR, ICPIDR2 */
00094 };    
00095 
00096 static hvmm_status_t access_handler(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00097 {
00098     printh( "%s: %s offset:%d value:%x\n", __FUNCTION__, write ? "write" : "read", offset, write ? *pvalue : (uint32_t) pvalue );
00099 
00100     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00101     uint8_t offsetidx = (uint8_t) ((offset & 0xF00) >> 8);
00102     result = _handler_map[offsetidx].handler(write, offset, pvalue, access_size);
00103     return result;
00104 }
00105 
00106 
00107 
00108 static hvmm_status_t handler_000(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00109 {
00110     //CTLR;              /*0x000 RW*/
00111     //TYPER;             /*      RO*/
00112     //IIDR;              /*      RO*/
00113     //IGROUPR[32];       /* 0x080 ~ 0x0FF */
00114 
00115     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00116     vmid_t vmid = context_current_vmid();
00117     struct gicd_regs *regs = &_regs[vmid];
00118     uint32_t woffset = offset/4;
00119 
00120     switch(woffset) {
00121         case GICD_CTLR: /* RW */
00122             if ( write ) {
00123                 regs->CTLR = *pvalue;
00124             } else {
00125                 *pvalue = regs->CTLR;
00126             }
00127             result = HVMM_STATUS_SUCCESS;
00128             break;
00129 
00130         case GICD_TYPER:    /* RO */
00131             if ( write == 0 ) {
00132                 *pvalue = VGICD_TYPER_DEFAULT;
00133                 result = HVMM_STATUS_SUCCESS;
00134             }
00135             break;
00136 
00137         case GICD_IIDR:     /* RO */
00138             if ( write == 0 ) {
00139                 *pvalue = VGICD_IIDR_DEFAULT;
00140                 result = HVMM_STATUS_SUCCESS;
00141             }
00142             break;
00143 
00144         default:            /* RW GICD_IGROUPR */
00145             {
00146                 int igroup = woffset - GICD_IGROUPR;
00147                 if ( igroup >= 0 && igroup < VGICD_NUM_IGROUPR ) {
00148                     if ( write ) {
00149                         regs->IGROUPR[igroup] = *pvalue;
00150                     } else {
00151                         *pvalue = regs->IGROUPR[igroup];
00152                     }
00153                     result = HVMM_STATUS_SUCCESS;
00154                 }
00155             }
00156             break;
00157     }
00158 
00159     if ( result != HVMM_STATUS_SUCCESS ) {
00160         printh("vgicd: invalid access offset:%x write:%d\n", offset, write );
00161     }
00162 
00163     return result;
00164 }
00165 
00166 void vgicd_set_callback_changed_istatus(vgicd_changed_istatus_callback_t callback) 
00167 {
00168     _cb_changed_istatus = callback;
00169 }
00170 
00171 void vgicd_changed_istatus( vmid_t vmid, uint32_t istatus, uint8_t word_offset )
00172 {
00173     if ( _cb_changed_istatus != 0 ) {
00174         _cb_changed_istatus( vmid, istatus, word_offset );
00175     }
00176 
00177 }
00178 
00179 static hvmm_status_t handler_ISCENABLER(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00180 {
00181     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00182     vmid_t vmid = context_current_vmid();
00183     struct gicd_regs *regs = &_regs[vmid];
00184     uint32_t *preg_s;
00185     uint32_t *preg_c;
00186     if( write && *pvalue == 0) {
00187         /* Writes 0 -> Has no effect. */
00188         result = HVMM_STATUS_SUCCESS; 
00189         return result;
00190     }
00191     
00192     preg_s = &(regs->ISCENABLER[(offset >> 2 ) - GICD_ISENABLER]);
00193     preg_c = &(regs->ISCENABLER[(offset >> 2 ) - GICD_ICENABLER]);
00194 
00195     if ( access_size == VDEV_ACCESS_WORD ) {
00196         if ( (offset >> 2 ) < (GICD_ISENABLER + VGICD_NUM_IENABLER) ) {
00197         /* ISENABLER */
00198             if ( write ) {
00199                 *preg_s |= *pvalue;     
00200                 vgicd_changed_istatus(vmid, *preg_s, (offset >> 2) - GICD_ISENABLER );
00201             } else {
00202                 *pvalue = *preg_s;
00203             }
00204             result = HVMM_STATUS_SUCCESS;
00205         } else if ( (offset >> 2 ) >= GICD_ICENABLER && (offset >> 2 ) < (GICD_ICENABLER + VGICD_NUM_IENABLER) ) {
00206             /* ICENABLER */
00207             if ( write ){
00208                 *preg_c &= ~(*pvalue);
00209                 vgicd_changed_istatus(vmid, *preg_c, (offset >> 2) - GICD_ICENABLER );
00210             } else {
00211                 *pvalue = *preg_c;
00212             }
00213             result = HVMM_STATUS_SUCCESS;
00214         }
00215     } else if ( access_size == VDEV_ACCESS_HWORD ) {
00216         if ( (offset >> 2) < ( GICD_ISENABLER + VGICD_NUM_IENABLER) )  {
00217             uint16_t *preg_s16 = (uint16_t *)preg_s;
00218             preg_s16 += (offset & 0x3) >> 1;
00219             if ( write ) {
00220                 *preg_s16 |= (uint16_t)(*pvalue & 0xFFFF);
00221                 vgicd_changed_istatus(vmid, *preg_s, (offset >> 2) - GICD_ISENABLER );
00222             } else {
00223                 *pvalue = (uint32_t)*preg_s16;
00224             }
00225             result = HVMM_STATUS_SUCCESS;
00226         } else if ( (offset >> 2 ) >= GICD_ICENABLER && (offset >> 2 ) < (GICD_ICENABLER + VGICD_NUM_IENABLER) ) {
00227             uint16_t *preg_c16 = (uint16_t *)preg_c;
00228             preg_c16 += (offset & 0x3) >> 1;
00229             if( write ){
00230                 *preg_c16 &= ~((uint16_t)(*pvalue & 0xFFFF));
00231                 vgicd_changed_istatus(vmid, *preg_c, (offset >> 2) - GICD_ICENABLER );
00232             } else {
00233                 *pvalue = (uint32_t)*preg_c16;
00234             }
00235             result = HVMM_STATUS_SUCCESS;
00236         }
00237 
00238     } else if ( access_size == VDEV_ACCESS_BYTE ) {
00239         if ( (offset >> 2) < ( GICD_ISENABLER + VGICD_NUM_IENABLER) )  {
00240             uint8_t *preg_s8 = (uint8_t *)preg_s;
00241             preg_s8 += (offset & 0x3);
00242             if ( write ) {
00243                 *preg_s8 |= (uint8_t)(*pvalue & 0xFF);
00244                 vgicd_changed_istatus(vmid, *preg_s, (offset >> 2) - GICD_ISENABLER );
00245             } else {
00246                 *pvalue = (uint32_t)*preg_s8;
00247             }
00248             result = HVMM_STATUS_SUCCESS;
00249         } else if( ( offset >> 2 ) >= GICD_ICENABLER && ( offset >> 2 ) < (GICD_ICENABLER + VGICD_NUM_IENABLER) ) {
00250             uint8_t *preg_c8 = (uint8_t *)preg_c;
00251             preg_c8 += ( offset & 0x3 );
00252             if ( write ){
00253                 *preg_c8 &= ~((uint8_t)(*pvalue & 0xFF));
00254                 vgicd_changed_istatus(vmid, *preg_c, (offset >> 2) - GICD_ICENABLER );
00255             } else {
00256                 *pvalue = (uint32_t)*preg_c8;
00257             }
00258             result = HVMM_STATUS_SUCCESS;
00259         }
00260     }
00261     return result;
00262 }
00263 
00264 static hvmm_status_t handler_ISCPENDR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00265 {
00266     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00267     vmid_t vmid = context_current_vmid();
00268     struct gicd_regs *regs = &_regs[vmid];
00269     uint32_t *preg_s;
00270     uint32_t *preg_c;  
00271 
00272     preg_s = &(regs->ISPENDR[(offset >> 2 ) - GICD_ISPENDR]);
00273     preg_c = &(regs->ISPENDR[(offset >> 2 ) - GICD_ICPENDR]);
00274     offset >>= 2;
00275 
00276     if ( access_size == VDEV_ACCESS_WORD ) {
00277         if ( (offset >> 2 ) < (GICD_ISPENDR + VGICD_NUM_IENABLER) ) {
00278         /* ISPEND */
00279             if ( write ) {
00280                 *preg_s |= *pvalue;     
00281             } else {
00282                 *pvalue = *preg_s;
00283             }
00284             result = HVMM_STATUS_SUCCESS;
00285         } else if ( (offset >> 2 ) >= GICD_ICPENDR && (offset >> 2 ) < (GICD_ICPENDR + VGICD_NUM_IENABLER) ) {
00286             /* ICPEND */
00287             if ( write ){
00288                 *preg_c &= ~(*pvalue);
00289             } else {
00290                 *pvalue = *preg_c;
00291             }
00292             result = HVMM_STATUS_SUCCESS;
00293         }
00294     } 
00295 
00296     printh( "vgicd:%s: not implemented\n", __FUNCTION__ );
00297     return result;
00298 }
00299 
00300 static hvmm_status_t handler_ISCACTIVER(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00301 {
00302     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00303     printh( "vgicd:%s: not implemented\n", __FUNCTION__ );
00304     return result;
00305 }
00306 
00307 static hvmm_status_t handler_IPRIORITYR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00308 {
00309     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00310     vmid_t vmid;
00311     struct gicd_regs *regs;
00312     uint32_t *preg;
00313 
00314     vmid = context_current_vmid();
00315     regs = &_regs[vmid];
00316 
00317     /* FIXME: Support 8/16/32bit access */
00318     offset >>= 2;
00319     preg = &(regs->ICFGR[offset - GICD_IPRIORITYR]);
00320     if ( write ) {
00321         *preg = *pvalue;
00322     } else {
00323         *pvalue = *preg;
00324     }
00325 
00326     result = HVMM_STATUS_SUCCESS;
00327     return result;
00328 }
00329 
00330 static hvmm_status_t handler_ITARGETSR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00331 {
00332     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00333     vmid_t vmid;
00334     struct gicd_regs *regs;
00335     uint32_t *preg;
00336 
00337     vmid = context_current_vmid();
00338     regs = &_regs[vmid];
00339 
00340     preg = &(regs->ITARGETSR[(offset >>2) - GICD_ITARGETSR]);
00341     if ( access_size == VDEV_ACCESS_WORD ) {
00342         offset >>= 2;
00343         if ( write ) {
00344             if ( offset > (GICD_ITARGETSR + 7) ) {
00345                 /* RO: ITARGETSR0 ~ 7 */
00346                 *preg = *pvalue;
00347             }
00348         } else {
00349             *pvalue = *preg;
00350         }
00351     } else if ( access_size == VDEV_ACCESS_HWORD ) {
00352         uint16_t *preg16 = (uint16_t *) preg;
00353         preg16 += (offset & 0x3) >> 1;
00354         if ( write ) {
00355             if ( (offset >>2) > (GICD_ITARGETSR + 7) )
00356                 *preg16 = (uint16_t) (*pvalue & 0xFFFF);
00357         } else {
00358             *pvalue = (uint32_t) *preg16;
00359         }
00360     } else if ( access_size == VDEV_ACCESS_BYTE ) {
00361         uint8_t *preg8 = (uint8_t *) preg;
00362         preg8 += (offset & 0x3);
00363         if ( write ) {
00364             if ( (offset >>2) > (GICD_ITARGETSR + 7) )
00365                 *preg8 = (uint8_t) (*pvalue & 0xFF);
00366         } else {
00367             *pvalue = (uint32_t) *preg8;
00368         }
00369     }
00370 
00371     result = HVMM_STATUS_SUCCESS;
00372     return result;
00373 }
00374 
00375 static hvmm_status_t handler_ICFGR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00376 {
00377     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00378     vmid_t vmid;
00379     struct gicd_regs *regs;
00380     uint32_t *preg;
00381 
00382     vmid = context_current_vmid();
00383     regs = &_regs[vmid];
00384 
00385     /* FIXME: Support 8/16/32bit access */
00386     offset >>= 2;
00387     preg = &(regs->ICFGR[offset - GICD_ICFGR]);
00388     if ( write ) {
00389         *preg = *pvalue;
00390     } else {
00391         *pvalue = *preg;
00392     }
00393 
00394     result = HVMM_STATUS_SUCCESS;
00395     return result;
00396 }
00397 
00398 static hvmm_status_t handler_PPISPISR_CA15(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00399 {
00400     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00401     printh( "vgicd:%s: not implemented\n", __FUNCTION__ );
00402     return result;
00403 }
00404 
00405 static hvmm_status_t handler_NSACR(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00406 {
00407     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00408     printh( "vgicd:%s: not implemented\n", __FUNCTION__ );
00409     return result;
00410 }
00411 
00412 static hvmm_status_t handler_F00(uint32_t write, uint32_t offset, uint32_t *pvalue, vdev_access_size_t access_size)
00413 {
00414     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00415     printh( "vgicd:%s: not implemented\n", __FUNCTION__ );
00416     return result;
00417 }
00418 
00419 static void vdev_gicd_reset_values(void)
00420 {
00421     int i;
00422     for (i = 0; i < NUM_GUESTS_STATIC; i++ ) {
00423         /* ITARGETS[0~ 7], CPU Targets are set to 0, due to current single-core support design */
00424         int j = 0;
00425         for ( j = 0; j < 7; j++ ) {
00426             _regs[i].ITARGETSR[j] = 0;
00427         }
00428 
00429     }
00430 }
00431 
00432 
00433 hvmm_status_t vdev_gicd_init(uint32_t base_addr)
00434 {
00435     hvmm_status_t result = HVMM_STATUS_BUSY;
00436 
00437     vdev_gicd_reset_values();
00438 
00439     _vdev_info.name     = "vgicd";
00440     _vdev_info.base     = base_addr; 
00441     _vdev_info.size     = 4096;
00442     _vdev_info.handler  = access_handler;
00443 
00444     result = vdev_reg_device(&_vdev_info);
00445     if ( result == HVMM_STATUS_SUCCESS ) {
00446         printh("%s: vdev registered:'%s'\n", __FUNCTION__, _vdev_info.name);
00447     } else {
00448         printh("%s: Unable to register vdev:'%s' code=%x\n", __FUNCTION__, _vdev_info.name, result);
00449     }
00450     return result;
00451 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines