khypervisor
v1
|
#include "vdev_gicd.h"
#include <context.h>
#include <gic_regs.h>
#include <vdev.h>
#include <log/print.h>
Go to the source code of this file.
#define VGICD_IIDR_DEFAULT (0x43B) |
Definition at line 10 of file vdev_gicd.c.
#define VGICD_ITLINESNUM 128 |
Definition at line 8 of file vdev_gicd.c.
#define VGICD_NUM_IENABLER (VGICD_ITLINESNUM/32) |
Definition at line 12 of file vdev_gicd.c.
#define VGICD_NUM_IGROUPR (VGICD_ITLINESNUM/32) |
Definition at line 11 of file vdev_gicd.c.
#define VGICD_TYPER_DEFAULT ((VGICD_ITLINESNUM >> 5) - 1) |
Definition at line 9 of file vdev_gicd.c.
static hvmm_status_t access_handler | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 96 of file vdev_gicd.c.
{ printh( "%s: %s offset:%d value:%x\n", __FUNCTION__, write ? "write" : "read", offset, write ? *pvalue : (uint32_t) pvalue ); hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; uint8_t offsetidx = (uint8_t) ((offset & 0xF00) >> 8); result = _handler_map[offsetidx].handler(write, offset, pvalue, access_size); return result; }
static hvmm_status_t handler_000 | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 108 of file vdev_gicd.c.
{ //CTLR; /*0x000 RW*/ //TYPER; /* RO*/ //IIDR; /* RO*/ //IGROUPR[32]; /* 0x080 ~ 0x0FF */ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; vmid_t vmid = context_current_vmid(); struct gicd_regs *regs = &_regs[vmid]; uint32_t woffset = offset/4; switch(woffset) { case GICD_CTLR: /* RW */ if ( write ) { regs->CTLR = *pvalue; } else { *pvalue = regs->CTLR; } result = HVMM_STATUS_SUCCESS; break; case GICD_TYPER: /* RO */ if ( write == 0 ) { *pvalue = VGICD_TYPER_DEFAULT; result = HVMM_STATUS_SUCCESS; } break; case GICD_IIDR: /* RO */ if ( write == 0 ) { *pvalue = VGICD_IIDR_DEFAULT; result = HVMM_STATUS_SUCCESS; } break; default: /* RW GICD_IGROUPR */ { int igroup = woffset - GICD_IGROUPR; if ( igroup >= 0 && igroup < VGICD_NUM_IGROUPR ) { if ( write ) { regs->IGROUPR[igroup] = *pvalue; } else { *pvalue = regs->IGROUPR[igroup]; } result = HVMM_STATUS_SUCCESS; } } break; } if ( result != HVMM_STATUS_SUCCESS ) { printh("vgicd: invalid access offset:%x write:%d\n", offset, write ); } return result; }
static hvmm_status_t handler_F00 | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 412 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; printh( "vgicd:%s: not implemented\n", __FUNCTION__ ); return result; }
static hvmm_status_t handler_ICFGR | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 375 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; vmid_t vmid; struct gicd_regs *regs; uint32_t *preg; vmid = context_current_vmid(); regs = &_regs[vmid]; /* FIXME: Support 8/16/32bit access */ offset >>= 2; preg = &(regs->ICFGR[offset - GICD_ICFGR]); if ( write ) { *preg = *pvalue; } else { *pvalue = *preg; } result = HVMM_STATUS_SUCCESS; return result; }
static hvmm_status_t handler_IPRIORITYR | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 307 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; vmid_t vmid; struct gicd_regs *regs; uint32_t *preg; vmid = context_current_vmid(); regs = &_regs[vmid]; /* FIXME: Support 8/16/32bit access */ offset >>= 2; preg = &(regs->ICFGR[offset - GICD_IPRIORITYR]); if ( write ) { *preg = *pvalue; } else { *pvalue = *preg; } result = HVMM_STATUS_SUCCESS; return result; }
static hvmm_status_t handler_ISCACTIVER | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 300 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; printh( "vgicd:%s: not implemented\n", __FUNCTION__ ); return result; }
static hvmm_status_t handler_ISCENABLER | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 179 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; vmid_t vmid = context_current_vmid(); struct gicd_regs *regs = &_regs[vmid]; uint32_t *preg_s; uint32_t *preg_c; if( write && *pvalue == 0) { /* Writes 0 -> Has no effect. */ result = HVMM_STATUS_SUCCESS; return result; } preg_s = &(regs->ISCENABLER[(offset >> 2 ) - GICD_ISENABLER]); preg_c = &(regs->ISCENABLER[(offset >> 2 ) - GICD_ICENABLER]); if ( access_size == VDEV_ACCESS_WORD ) { if ( (offset >> 2 ) < (GICD_ISENABLER + VGICD_NUM_IENABLER) ) { /* ISENABLER */ if ( write ) { *preg_s |= *pvalue; vgicd_changed_istatus(vmid, *preg_s, (offset >> 2) - GICD_ISENABLER ); } else { *pvalue = *preg_s; } result = HVMM_STATUS_SUCCESS; } else if ( (offset >> 2 ) >= GICD_ICENABLER && (offset >> 2 ) < (GICD_ICENABLER + VGICD_NUM_IENABLER) ) { /* ICENABLER */ if ( write ){ *preg_c &= ~(*pvalue); vgicd_changed_istatus(vmid, *preg_c, (offset >> 2) - GICD_ICENABLER ); } else { *pvalue = *preg_c; } result = HVMM_STATUS_SUCCESS; } } else if ( access_size == VDEV_ACCESS_HWORD ) { if ( (offset >> 2) < ( GICD_ISENABLER + VGICD_NUM_IENABLER) ) { uint16_t *preg_s16 = (uint16_t *)preg_s; preg_s16 += (offset & 0x3) >> 1; if ( write ) { *preg_s16 |= (uint16_t)(*pvalue & 0xFFFF); vgicd_changed_istatus(vmid, *preg_s, (offset >> 2) - GICD_ISENABLER ); } else { *pvalue = (uint32_t)*preg_s16; } result = HVMM_STATUS_SUCCESS; } else if ( (offset >> 2 ) >= GICD_ICENABLER && (offset >> 2 ) < (GICD_ICENABLER + VGICD_NUM_IENABLER) ) { uint16_t *preg_c16 = (uint16_t *)preg_c; preg_c16 += (offset & 0x3) >> 1; if( write ){ *preg_c16 &= ~((uint16_t)(*pvalue & 0xFFFF)); vgicd_changed_istatus(vmid, *preg_c, (offset >> 2) - GICD_ICENABLER ); } else { *pvalue = (uint32_t)*preg_c16; } result = HVMM_STATUS_SUCCESS; } } else if ( access_size == VDEV_ACCESS_BYTE ) { if ( (offset >> 2) < ( GICD_ISENABLER + VGICD_NUM_IENABLER) ) { uint8_t *preg_s8 = (uint8_t *)preg_s; preg_s8 += (offset & 0x3); if ( write ) { *preg_s8 |= (uint8_t)(*pvalue & 0xFF); vgicd_changed_istatus(vmid, *preg_s, (offset >> 2) - GICD_ISENABLER ); } else { *pvalue = (uint32_t)*preg_s8; } result = HVMM_STATUS_SUCCESS; } else if( ( offset >> 2 ) >= GICD_ICENABLER && ( offset >> 2 ) < (GICD_ICENABLER + VGICD_NUM_IENABLER) ) { uint8_t *preg_c8 = (uint8_t *)preg_c; preg_c8 += ( offset & 0x3 ); if ( write ){ *preg_c8 &= ~((uint8_t)(*pvalue & 0xFF)); vgicd_changed_istatus(vmid, *preg_c, (offset >> 2) - GICD_ICENABLER ); } else { *pvalue = (uint32_t)*preg_c8; } result = HVMM_STATUS_SUCCESS; } } return result; }
static hvmm_status_t handler_ISCPENDR | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 264 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; vmid_t vmid = context_current_vmid(); struct gicd_regs *regs = &_regs[vmid]; uint32_t *preg_s; uint32_t *preg_c; preg_s = &(regs->ISPENDR[(offset >> 2 ) - GICD_ISPENDR]); preg_c = &(regs->ISPENDR[(offset >> 2 ) - GICD_ICPENDR]); offset >>= 2; if ( access_size == VDEV_ACCESS_WORD ) { if ( (offset >> 2 ) < (GICD_ISPENDR + VGICD_NUM_IENABLER) ) { /* ISPEND */ if ( write ) { *preg_s |= *pvalue; } else { *pvalue = *preg_s; } result = HVMM_STATUS_SUCCESS; } else if ( (offset >> 2 ) >= GICD_ICPENDR && (offset >> 2 ) < (GICD_ICPENDR + VGICD_NUM_IENABLER) ) { /* ICPEND */ if ( write ){ *preg_c &= ~(*pvalue); } else { *pvalue = *preg_c; } result = HVMM_STATUS_SUCCESS; } } printh( "vgicd:%s: not implemented\n", __FUNCTION__ ); return result; }
static hvmm_status_t handler_ITARGETSR | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 330 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; vmid_t vmid; struct gicd_regs *regs; uint32_t *preg; vmid = context_current_vmid(); regs = &_regs[vmid]; preg = &(regs->ITARGETSR[(offset >>2) - GICD_ITARGETSR]); if ( access_size == VDEV_ACCESS_WORD ) { offset >>= 2; if ( write ) { if ( offset > (GICD_ITARGETSR + 7) ) { /* RO: ITARGETSR0 ~ 7 */ *preg = *pvalue; } } else { *pvalue = *preg; } } else if ( access_size == VDEV_ACCESS_HWORD ) { uint16_t *preg16 = (uint16_t *) preg; preg16 += (offset & 0x3) >> 1; if ( write ) { if ( (offset >>2) > (GICD_ITARGETSR + 7) ) *preg16 = (uint16_t) (*pvalue & 0xFFFF); } else { *pvalue = (uint32_t) *preg16; } } else if ( access_size == VDEV_ACCESS_BYTE ) { uint8_t *preg8 = (uint8_t *) preg; preg8 += (offset & 0x3); if ( write ) { if ( (offset >>2) > (GICD_ITARGETSR + 7) ) *preg8 = (uint8_t) (*pvalue & 0xFF); } else { *pvalue = (uint32_t) *preg8; } } result = HVMM_STATUS_SUCCESS; return result; }
static hvmm_status_t handler_NSACR | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 405 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; printh( "vgicd:%s: not implemented\n", __FUNCTION__ ); return result; }
static hvmm_status_t handler_PPISPISR_CA15 | ( | uint32_t | write, |
uint32_t | offset, | ||
uint32_t * | pvalue, | ||
vdev_access_size_t | access_size | ||
) | [static] |
Definition at line 398 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BAD_ACCESS; printh( "vgicd:%s: not implemented\n", __FUNCTION__ ); return result; }
hvmm_status_t vdev_gicd_init | ( | uint32_t | base_addr | ) |
Definition at line 433 of file vdev_gicd.c.
{ hvmm_status_t result = HVMM_STATUS_BUSY; vdev_gicd_reset_values(); _vdev_info.name = "vgicd"; _vdev_info.base = base_addr; _vdev_info.size = 4096; _vdev_info.handler = access_handler; result = vdev_reg_device(&_vdev_info); if ( result == HVMM_STATUS_SUCCESS ) { printh("%s: vdev registered:'%s'\n", __FUNCTION__, _vdev_info.name); } else { printh("%s: Unable to register vdev:'%s' code=%x\n", __FUNCTION__, _vdev_info.name, result); } return result; }
static void vdev_gicd_reset_values | ( | void | ) | [static] |
Definition at line 419 of file vdev_gicd.c.
{ int i; for (i = 0; i < NUM_GUESTS_STATIC; i++ ) { /* ITARGETS[0~ 7], CPU Targets are set to 0, due to current single-core support design */ int j = 0; for ( j = 0; j < 7; j++ ) { _regs[i].ITARGETSR[j] = 0; } } }
void vgicd_changed_istatus | ( | vmid_t | vmid, |
uint32_t | istatus, | ||
uint8_t | word_offset | ||
) |
Definition at line 171 of file vdev_gicd.c.
{ if ( _cb_changed_istatus != 0 ) { _cb_changed_istatus( vmid, istatus, word_offset ); } }
void vgicd_set_callback_changed_istatus | ( | vgicd_changed_istatus_callback_t | callback | ) |
Definition at line 166 of file vdev_gicd.c.
{ _cb_changed_istatus = callback; }
Definition at line 71 of file vdev_gicd.c.
struct gicd_handler_entry _handler_map[0x10] [static] |
{ { 0x00, handler_000 }, { 0x01, handler_ISCENABLER }, { 0x02, handler_ISCPENDR }, { 0x03, handler_ISCACTIVER }, { 0x04, handler_IPRIORITYR }, { 0x05, handler_IPRIORITYR }, { 0x06, handler_IPRIORITYR }, { 0x07, handler_IPRIORITYR }, { 0x08, handler_ITARGETSR }, { 0x09, handler_ITARGETSR }, { 0x0A, handler_ITARGETSR }, { 0x0B, handler_ITARGETSR }, { 0x0C, handler_ICFGR }, { 0x0D, handler_PPISPISR_CA15 }, { 0x0E, handler_NSACR }, { 0x0F, handler_F00 }, }
Definition at line 76 of file vdev_gicd.c.
struct gicd_regs _regs[NUM_GUESTS_STATIC] [static] |
Definition at line 74 of file vdev_gicd.c.
vdev_info_t _vdev_info [static] |
Definition at line 73 of file vdev_gicd.c.