khypervisor
v1
|
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 }