Annotation of qemu/xen-all.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2010       Citrix Ltd.
        !             3:  *
        !             4:  * This work is licensed under the terms of the GNU GPL, version 2.  See
        !             5:  * the COPYING file in the top-level directory.
        !             6:  *
        !             7:  */
        !             8: 
        !             9: #include <sys/mman.h>
        !            10: 
        !            11: #include "hw/pci.h"
        !            12: #include "hw/pc.h"
        !            13: #include "hw/xen_common.h"
        !            14: #include "hw/xen_backend.h"
        !            15: 
        !            16: #include "range.h"
        !            17: #include "xen-mapcache.h"
        !            18: #include "trace.h"
        !            19: 
        !            20: #include <xen/hvm/ioreq.h>
        !            21: #include <xen/hvm/params.h>
        !            22: 
        !            23: //#define DEBUG_XEN
        !            24: 
        !            25: #ifdef DEBUG_XEN
        !            26: #define DPRINTF(fmt, ...) \
        !            27:     do { fprintf(stderr, "xen: " fmt, ## __VA_ARGS__); } while (0)
        !            28: #else
        !            29: #define DPRINTF(fmt, ...) \
        !            30:     do { } while (0)
        !            31: #endif
        !            32: 
        !            33: /* Compatibility with older version */
        !            34: #if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a
        !            35: static inline uint32_t xen_vcpu_eport(shared_iopage_t *shared_page, int i)
        !            36: {
        !            37:     return shared_page->vcpu_iodata[i].vp_eport;
        !            38: }
        !            39: static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
        !            40: {
        !            41:     return &shared_page->vcpu_iodata[vcpu].vp_ioreq;
        !            42: }
        !            43: #  define FMT_ioreq_size PRIx64
        !            44: #else
        !            45: static inline uint32_t xen_vcpu_eport(shared_iopage_t *shared_page, int i)
        !            46: {
        !            47:     return shared_page->vcpu_ioreq[i].vp_eport;
        !            48: }
        !            49: static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
        !            50: {
        !            51:     return &shared_page->vcpu_ioreq[vcpu];
        !            52: }
        !            53: #  define FMT_ioreq_size "u"
        !            54: #endif
        !            55: 
        !            56: #define BUFFER_IO_MAX_DELAY  100
        !            57: 
        !            58: typedef struct XenPhysmap {
        !            59:     target_phys_addr_t start_addr;
        !            60:     ram_addr_t size;
        !            61:     target_phys_addr_t phys_offset;
        !            62: 
        !            63:     QLIST_ENTRY(XenPhysmap) list;
        !            64: } XenPhysmap;
        !            65: 
        !            66: typedef struct XenIOState {
        !            67:     shared_iopage_t *shared_page;
        !            68:     buffered_iopage_t *buffered_io_page;
        !            69:     QEMUTimer *buffered_io_timer;
        !            70:     /* the evtchn port for polling the notification, */
        !            71:     evtchn_port_t *ioreq_local_port;
        !            72:     /* the evtchn fd for polling */
        !            73:     XenEvtchn xce_handle;
        !            74:     /* which vcpu we are serving */
        !            75:     int send_vcpu;
        !            76: 
        !            77:     struct xs_handle *xenstore;
        !            78:     CPUPhysMemoryClient client;
        !            79:     QLIST_HEAD(, XenPhysmap) physmap;
        !            80:     const XenPhysmap *log_for_dirtybit;
        !            81: 
        !            82:     Notifier exit;
        !            83: } XenIOState;
        !            84: 
        !            85: /* Xen specific function for piix pci */
        !            86: 
        !            87: int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
        !            88: {
        !            89:     return irq_num + ((pci_dev->devfn >> 3) << 2);
        !            90: }
        !            91: 
        !            92: void xen_piix3_set_irq(void *opaque, int irq_num, int level)
        !            93: {
        !            94:     xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
        !            95:                               irq_num & 3, level);
        !            96: }
        !            97: 
        !            98: void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
        !            99: {
        !           100:     int i;
        !           101: 
        !           102:     /* Scan for updates to PCI link routes (0x60-0x63). */
        !           103:     for (i = 0; i < len; i++) {
        !           104:         uint8_t v = (val >> (8 * i)) & 0xff;
        !           105:         if (v & 0x80) {
        !           106:             v = 0;
        !           107:         }
        !           108:         v &= 0xf;
        !           109:         if (((address + i) >= 0x60) && ((address + i) <= 0x63)) {
        !           110:             xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v);
        !           111:         }
        !           112:     }
        !           113: }
        !           114: 
        !           115: void xen_cmos_set_s3_resume(void *opaque, int irq, int level)
        !           116: {
        !           117:     pc_cmos_set_s3_resume(opaque, irq, level);
        !           118:     if (level) {
        !           119:         xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
        !           120:     }
        !           121: }
        !           122: 
        !           123: /* Xen Interrupt Controller */
        !           124: 
        !           125: static void xen_set_irq(void *opaque, int irq, int level)
        !           126: {
        !           127:     xc_hvm_set_isa_irq_level(xen_xc, xen_domid, irq, level);
        !           128: }
        !           129: 
        !           130: qemu_irq *xen_interrupt_controller_init(void)
        !           131: {
        !           132:     return qemu_allocate_irqs(xen_set_irq, NULL, 16);
        !           133: }
        !           134: 
        !           135: /* Memory Ops */
        !           136: 
        !           137: static void xen_ram_init(ram_addr_t ram_size)
        !           138: {
        !           139:     RAMBlock *new_block;
        !           140:     ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
        !           141: 
        !           142:     new_block = qemu_mallocz(sizeof (*new_block));
        !           143:     pstrcpy(new_block->idstr, sizeof (new_block->idstr), "xen.ram");
        !           144:     new_block->host = NULL;
        !           145:     new_block->offset = 0;
        !           146:     new_block->length = ram_size;
        !           147: 
        !           148:     QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
        !           149: 
        !           150:     ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
        !           151:                                        new_block->length >> TARGET_PAGE_BITS);
        !           152:     memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
        !           153:            0xff, new_block->length >> TARGET_PAGE_BITS);
        !           154: 
        !           155:     if (ram_size >= 0xe0000000 ) {
        !           156:         above_4g_mem_size = ram_size - 0xe0000000;
        !           157:         below_4g_mem_size = 0xe0000000;
        !           158:     } else {
        !           159:         below_4g_mem_size = ram_size;
        !           160:     }
        !           161: 
        !           162:     cpu_register_physical_memory(0, below_4g_mem_size, new_block->offset);
        !           163: #if TARGET_PHYS_ADDR_BITS > 32
        !           164:     if (above_4g_mem_size > 0) {
        !           165:         cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
        !           166:                                      new_block->offset + below_4g_mem_size);
        !           167:     }
        !           168: #endif
        !           169: }
        !           170: 
        !           171: void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size)
        !           172: {
        !           173:     unsigned long nr_pfn;
        !           174:     xen_pfn_t *pfn_list;
        !           175:     int i;
        !           176: 
        !           177:     trace_xen_ram_alloc(ram_addr, size);
        !           178: 
        !           179:     nr_pfn = size >> TARGET_PAGE_BITS;
        !           180:     pfn_list = qemu_malloc(sizeof (*pfn_list) * nr_pfn);
        !           181: 
        !           182:     for (i = 0; i < nr_pfn; i++) {
        !           183:         pfn_list[i] = (ram_addr >> TARGET_PAGE_BITS) + i;
        !           184:     }
        !           185: 
        !           186:     if (xc_domain_populate_physmap_exact(xen_xc, xen_domid, nr_pfn, 0, 0, pfn_list)) {
        !           187:         hw_error("xen: failed to populate ram at %lx", ram_addr);
        !           188:     }
        !           189: 
        !           190:     qemu_free(pfn_list);
        !           191: }
        !           192: 
        !           193: static XenPhysmap *get_physmapping(XenIOState *state,
        !           194:                                    target_phys_addr_t start_addr, ram_addr_t size)
        !           195: {
        !           196:     XenPhysmap *physmap = NULL;
        !           197: 
        !           198:     start_addr &= TARGET_PAGE_MASK;
        !           199: 
        !           200:     QLIST_FOREACH(physmap, &state->physmap, list) {
        !           201:         if (range_covers_byte(physmap->start_addr, physmap->size, start_addr)) {
        !           202:             return physmap;
        !           203:         }
        !           204:     }
        !           205:     return NULL;
        !           206: }
        !           207: 
        !           208: #if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 340
        !           209: static int xen_add_to_physmap(XenIOState *state,
        !           210:                               target_phys_addr_t start_addr,
        !           211:                               ram_addr_t size,
        !           212:                               target_phys_addr_t phys_offset)
        !           213: {
        !           214:     unsigned long i = 0;
        !           215:     int rc = 0;
        !           216:     XenPhysmap *physmap = NULL;
        !           217:     target_phys_addr_t pfn, start_gpfn;
        !           218:     RAMBlock *block;
        !           219: 
        !           220:     if (get_physmapping(state, start_addr, size)) {
        !           221:         return 0;
        !           222:     }
        !           223:     if (size <= 0) {
        !           224:         return -1;
        !           225:     }
        !           226: 
        !           227:     /* Xen can only handle a single dirty log region for now and we want
        !           228:      * the linear framebuffer to be that region.
        !           229:      * Avoid tracking any regions that is not videoram and avoid tracking
        !           230:      * the legacy vga region. */
        !           231:     QLIST_FOREACH(block, &ram_list.blocks, next) {
        !           232:         if (!strcmp(block->idstr, "vga.vram") && block->offset == phys_offset
        !           233:                 && start_addr > 0xbffff) {
        !           234:             goto go_physmap;
        !           235:         }
        !           236:     }
        !           237:     return -1;
        !           238: 
        !           239: go_physmap:
        !           240:     DPRINTF("mapping vram to %llx - %llx, from %llx\n",
        !           241:             start_addr, start_addr + size, phys_offset);
        !           242: 
        !           243:     pfn = phys_offset >> TARGET_PAGE_BITS;
        !           244:     start_gpfn = start_addr >> TARGET_PAGE_BITS;
        !           245:     for (i = 0; i < size >> TARGET_PAGE_BITS; i++) {
        !           246:         unsigned long idx = pfn + i;
        !           247:         xen_pfn_t gpfn = start_gpfn + i;
        !           248: 
        !           249:         rc = xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
        !           250:         if (rc) {
        !           251:             DPRINTF("add_to_physmap MFN %"PRI_xen_pfn" to PFN %"
        !           252:                     PRI_xen_pfn" failed: %d\n", idx, gpfn, rc);
        !           253:             return -rc;
        !           254:         }
        !           255:     }
        !           256: 
        !           257:     physmap = qemu_malloc(sizeof (XenPhysmap));
        !           258: 
        !           259:     physmap->start_addr = start_addr;
        !           260:     physmap->size = size;
        !           261:     physmap->phys_offset = phys_offset;
        !           262: 
        !           263:     QLIST_INSERT_HEAD(&state->physmap, physmap, list);
        !           264: 
        !           265:     xc_domain_pin_memory_cacheattr(xen_xc, xen_domid,
        !           266:                                    start_addr >> TARGET_PAGE_BITS,
        !           267:                                    (start_addr + size) >> TARGET_PAGE_BITS,
        !           268:                                    XEN_DOMCTL_MEM_CACHEATTR_WB);
        !           269:     return 0;
        !           270: }
        !           271: 
        !           272: static int xen_remove_from_physmap(XenIOState *state,
        !           273:                                    target_phys_addr_t start_addr,
        !           274:                                    ram_addr_t size)
        !           275: {
        !           276:     unsigned long i = 0;
        !           277:     int rc = 0;
        !           278:     XenPhysmap *physmap = NULL;
        !           279:     target_phys_addr_t phys_offset = 0;
        !           280: 
        !           281:     physmap = get_physmapping(state, start_addr, size);
        !           282:     if (physmap == NULL) {
        !           283:         return -1;
        !           284:     }
        !           285: 
        !           286:     phys_offset = physmap->phys_offset;
        !           287:     size = physmap->size;
        !           288: 
        !           289:     DPRINTF("unmapping vram to %llx - %llx, from %llx\n",
        !           290:             phys_offset, phys_offset + size, start_addr);
        !           291: 
        !           292:     size >>= TARGET_PAGE_BITS;
        !           293:     start_addr >>= TARGET_PAGE_BITS;
        !           294:     phys_offset >>= TARGET_PAGE_BITS;
        !           295:     for (i = 0; i < size; i++) {
        !           296:         unsigned long idx = start_addr + i;
        !           297:         xen_pfn_t gpfn = phys_offset + i;
        !           298: 
        !           299:         rc = xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
        !           300:         if (rc) {
        !           301:             fprintf(stderr, "add_to_physmap MFN %"PRI_xen_pfn" to PFN %"
        !           302:                     PRI_xen_pfn" failed: %d\n", idx, gpfn, rc);
        !           303:             return -rc;
        !           304:         }
        !           305:     }
        !           306: 
        !           307:     QLIST_REMOVE(physmap, list);
        !           308:     if (state->log_for_dirtybit == physmap) {
        !           309:         state->log_for_dirtybit = NULL;
        !           310:     }
        !           311:     free(physmap);
        !           312: 
        !           313:     return 0;
        !           314: }
        !           315: 
        !           316: #else
        !           317: static int xen_add_to_physmap(XenIOState *state,
        !           318:                               target_phys_addr_t start_addr,
        !           319:                               ram_addr_t size,
        !           320:                               target_phys_addr_t phys_offset)
        !           321: {
        !           322:     return -ENOSYS;
        !           323: }
        !           324: 
        !           325: static int xen_remove_from_physmap(XenIOState *state,
        !           326:                                    target_phys_addr_t start_addr,
        !           327:                                    ram_addr_t size)
        !           328: {
        !           329:     return -ENOSYS;
        !           330: }
        !           331: #endif
        !           332: 
        !           333: static void xen_client_set_memory(struct CPUPhysMemoryClient *client,
        !           334:                                   target_phys_addr_t start_addr,
        !           335:                                   ram_addr_t size,
        !           336:                                   ram_addr_t phys_offset,
        !           337:                                   bool log_dirty)
        !           338: {
        !           339:     XenIOState *state = container_of(client, XenIOState, client);
        !           340:     ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
        !           341:     hvmmem_type_t mem_type;
        !           342: 
        !           343:     if (!(start_addr != phys_offset
        !           344:           && ( (log_dirty && flags < IO_MEM_UNASSIGNED)
        !           345:                || (!log_dirty && flags == IO_MEM_UNASSIGNED)))) {
        !           346:         return;
        !           347:     }
        !           348: 
        !           349:     trace_xen_client_set_memory(start_addr, size, phys_offset, log_dirty);
        !           350: 
        !           351:     start_addr &= TARGET_PAGE_MASK;
        !           352:     size = TARGET_PAGE_ALIGN(size);
        !           353:     phys_offset &= TARGET_PAGE_MASK;
        !           354: 
        !           355:     switch (flags) {
        !           356:     case IO_MEM_RAM:
        !           357:         xen_add_to_physmap(state, start_addr, size, phys_offset);
        !           358:         break;
        !           359:     case IO_MEM_ROM:
        !           360:         mem_type = HVMMEM_ram_ro;
        !           361:         if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type,
        !           362:                                 start_addr >> TARGET_PAGE_BITS,
        !           363:                                 size >> TARGET_PAGE_BITS)) {
        !           364:             DPRINTF("xc_hvm_set_mem_type error, addr: "TARGET_FMT_plx"\n",
        !           365:                     start_addr);
        !           366:         }
        !           367:         break;
        !           368:     case IO_MEM_UNASSIGNED:
        !           369:         if (xen_remove_from_physmap(state, start_addr, size) < 0) {
        !           370:             DPRINTF("physmapping does not exist at "TARGET_FMT_plx"\n", start_addr);
        !           371:         }
        !           372:         break;
        !           373:     }
        !           374: }
        !           375: 
        !           376: static int xen_sync_dirty_bitmap(XenIOState *state,
        !           377:                                  target_phys_addr_t start_addr,
        !           378:                                  ram_addr_t size)
        !           379: {
        !           380:     target_phys_addr_t npages = size >> TARGET_PAGE_BITS;
        !           381:     target_phys_addr_t vram_offset = 0;
        !           382:     const int width = sizeof(unsigned long) * 8;
        !           383:     unsigned long bitmap[(npages + width - 1) / width];
        !           384:     int rc, i, j;
        !           385:     const XenPhysmap *physmap = NULL;
        !           386: 
        !           387:     physmap = get_physmapping(state, start_addr, size);
        !           388:     if (physmap == NULL) {
        !           389:         /* not handled */
        !           390:         return -1;
        !           391:     }
        !           392: 
        !           393:     if (state->log_for_dirtybit == NULL) {
        !           394:         state->log_for_dirtybit = physmap;
        !           395:     } else if (state->log_for_dirtybit != physmap) {
        !           396:         return -1;
        !           397:     }
        !           398:     vram_offset = physmap->phys_offset;
        !           399: 
        !           400:     rc = xc_hvm_track_dirty_vram(xen_xc, xen_domid,
        !           401:                                  start_addr >> TARGET_PAGE_BITS, npages,
        !           402:                                  bitmap);
        !           403:     if (rc) {
        !           404:         return rc;
        !           405:     }
        !           406: 
        !           407:     for (i = 0; i < ARRAY_SIZE(bitmap); i++) {
        !           408:         unsigned long map = bitmap[i];
        !           409:         while (map != 0) {
        !           410:             j = ffsl(map) - 1;
        !           411:             map &= ~(1ul << j);
        !           412:             cpu_physical_memory_set_dirty(vram_offset + (i * width + j) * TARGET_PAGE_SIZE);
        !           413:         };
        !           414:     }
        !           415: 
        !           416:     return 0;
        !           417: }
        !           418: 
        !           419: static int xen_log_start(CPUPhysMemoryClient *client, target_phys_addr_t phys_addr, ram_addr_t size)
        !           420: {
        !           421:     XenIOState *state = container_of(client, XenIOState, client);
        !           422: 
        !           423:     return xen_sync_dirty_bitmap(state, phys_addr, size);
        !           424: }
        !           425: 
        !           426: static int xen_log_stop(CPUPhysMemoryClient *client, target_phys_addr_t phys_addr, ram_addr_t size)
        !           427: {
        !           428:     XenIOState *state = container_of(client, XenIOState, client);
        !           429: 
        !           430:     state->log_for_dirtybit = NULL;
        !           431:     /* Disable dirty bit tracking */
        !           432:     return xc_hvm_track_dirty_vram(xen_xc, xen_domid, 0, 0, NULL);
        !           433: }
        !           434: 
        !           435: static int xen_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
        !           436:                                         target_phys_addr_t start_addr,
        !           437:                                         target_phys_addr_t end_addr)
        !           438: {
        !           439:     XenIOState *state = container_of(client, XenIOState, client);
        !           440: 
        !           441:     return xen_sync_dirty_bitmap(state, start_addr, end_addr - start_addr);
        !           442: }
        !           443: 
        !           444: static int xen_client_migration_log(struct CPUPhysMemoryClient *client,
        !           445:                                     int enable)
        !           446: {
        !           447:     return 0;
        !           448: }
        !           449: 
        !           450: static CPUPhysMemoryClient xen_cpu_phys_memory_client = {
        !           451:     .set_memory = xen_client_set_memory,
        !           452:     .sync_dirty_bitmap = xen_client_sync_dirty_bitmap,
        !           453:     .migration_log = xen_client_migration_log,
        !           454:     .log_start = xen_log_start,
        !           455:     .log_stop = xen_log_stop,
        !           456: };
        !           457: 
        !           458: /* VCPU Operations, MMIO, IO ring ... */
        !           459: 
        !           460: static void xen_reset_vcpu(void *opaque)
        !           461: {
        !           462:     CPUState *env = opaque;
        !           463: 
        !           464:     env->halted = 1;
        !           465: }
        !           466: 
        !           467: void xen_vcpu_init(void)
        !           468: {
        !           469:     CPUState *first_cpu;
        !           470: 
        !           471:     if ((first_cpu = qemu_get_cpu(0))) {
        !           472:         qemu_register_reset(xen_reset_vcpu, first_cpu);
        !           473:         xen_reset_vcpu(first_cpu);
        !           474:     }
        !           475: }
        !           476: 
        !           477: /* get the ioreq packets from share mem */
        !           478: static ioreq_t *cpu_get_ioreq_from_shared_memory(XenIOState *state, int vcpu)
        !           479: {
        !           480:     ioreq_t *req = xen_vcpu_ioreq(state->shared_page, vcpu);
        !           481: 
        !           482:     if (req->state != STATE_IOREQ_READY) {
        !           483:         DPRINTF("I/O request not ready: "
        !           484:                 "%x, ptr: %x, port: %"PRIx64", "
        !           485:                 "data: %"PRIx64", count: %" FMT_ioreq_size ", size: %" FMT_ioreq_size "\n",
        !           486:                 req->state, req->data_is_ptr, req->addr,
        !           487:                 req->data, req->count, req->size);
        !           488:         return NULL;
        !           489:     }
        !           490: 
        !           491:     xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */
        !           492: 
        !           493:     req->state = STATE_IOREQ_INPROCESS;
        !           494:     return req;
        !           495: }
        !           496: 
        !           497: /* use poll to get the port notification */
        !           498: /* ioreq_vec--out,the */
        !           499: /* retval--the number of ioreq packet */
        !           500: static ioreq_t *cpu_get_ioreq(XenIOState *state)
        !           501: {
        !           502:     int i;
        !           503:     evtchn_port_t port;
        !           504: 
        !           505:     port = xc_evtchn_pending(state->xce_handle);
        !           506:     if (port != -1) {
        !           507:         for (i = 0; i < smp_cpus; i++) {
        !           508:             if (state->ioreq_local_port[i] == port) {
        !           509:                 break;
        !           510:             }
        !           511:         }
        !           512: 
        !           513:         if (i == smp_cpus) {
        !           514:             hw_error("Fatal error while trying to get io event!\n");
        !           515:         }
        !           516: 
        !           517:         /* unmask the wanted port again */
        !           518:         xc_evtchn_unmask(state->xce_handle, port);
        !           519: 
        !           520:         /* get the io packet from shared memory */
        !           521:         state->send_vcpu = i;
        !           522:         return cpu_get_ioreq_from_shared_memory(state, i);
        !           523:     }
        !           524: 
        !           525:     /* read error or read nothing */
        !           526:     return NULL;
        !           527: }
        !           528: 
        !           529: static uint32_t do_inp(pio_addr_t addr, unsigned long size)
        !           530: {
        !           531:     switch (size) {
        !           532:         case 1:
        !           533:             return cpu_inb(addr);
        !           534:         case 2:
        !           535:             return cpu_inw(addr);
        !           536:         case 4:
        !           537:             return cpu_inl(addr);
        !           538:         default:
        !           539:             hw_error("inp: bad size: %04"FMT_pioaddr" %lx", addr, size);
        !           540:     }
        !           541: }
        !           542: 
        !           543: static void do_outp(pio_addr_t addr,
        !           544:         unsigned long size, uint32_t val)
        !           545: {
        !           546:     switch (size) {
        !           547:         case 1:
        !           548:             return cpu_outb(addr, val);
        !           549:         case 2:
        !           550:             return cpu_outw(addr, val);
        !           551:         case 4:
        !           552:             return cpu_outl(addr, val);
        !           553:         default:
        !           554:             hw_error("outp: bad size: %04"FMT_pioaddr" %lx", addr, size);
        !           555:     }
        !           556: }
        !           557: 
        !           558: static void cpu_ioreq_pio(ioreq_t *req)
        !           559: {
        !           560:     int i, sign;
        !           561: 
        !           562:     sign = req->df ? -1 : 1;
        !           563: 
        !           564:     if (req->dir == IOREQ_READ) {
        !           565:         if (!req->data_is_ptr) {
        !           566:             req->data = do_inp(req->addr, req->size);
        !           567:         } else {
        !           568:             uint32_t tmp;
        !           569: 
        !           570:             for (i = 0; i < req->count; i++) {
        !           571:                 tmp = do_inp(req->addr, req->size);
        !           572:                 cpu_physical_memory_write(req->data + (sign * i * req->size),
        !           573:                         (uint8_t *) &tmp, req->size);
        !           574:             }
        !           575:         }
        !           576:     } else if (req->dir == IOREQ_WRITE) {
        !           577:         if (!req->data_is_ptr) {
        !           578:             do_outp(req->addr, req->size, req->data);
        !           579:         } else {
        !           580:             for (i = 0; i < req->count; i++) {
        !           581:                 uint32_t tmp = 0;
        !           582: 
        !           583:                 cpu_physical_memory_read(req->data + (sign * i * req->size),
        !           584:                         (uint8_t*) &tmp, req->size);
        !           585:                 do_outp(req->addr, req->size, tmp);
        !           586:             }
        !           587:         }
        !           588:     }
        !           589: }
        !           590: 
        !           591: static void cpu_ioreq_move(ioreq_t *req)
        !           592: {
        !           593:     int i, sign;
        !           594: 
        !           595:     sign = req->df ? -1 : 1;
        !           596: 
        !           597:     if (!req->data_is_ptr) {
        !           598:         if (req->dir == IOREQ_READ) {
        !           599:             for (i = 0; i < req->count; i++) {
        !           600:                 cpu_physical_memory_read(req->addr + (sign * i * req->size),
        !           601:                         (uint8_t *) &req->data, req->size);
        !           602:             }
        !           603:         } else if (req->dir == IOREQ_WRITE) {
        !           604:             for (i = 0; i < req->count; i++) {
        !           605:                 cpu_physical_memory_write(req->addr + (sign * i * req->size),
        !           606:                         (uint8_t *) &req->data, req->size);
        !           607:             }
        !           608:         }
        !           609:     } else {
        !           610:         target_ulong tmp;
        !           611: 
        !           612:         if (req->dir == IOREQ_READ) {
        !           613:             for (i = 0; i < req->count; i++) {
        !           614:                 cpu_physical_memory_read(req->addr + (sign * i * req->size),
        !           615:                         (uint8_t*) &tmp, req->size);
        !           616:                 cpu_physical_memory_write(req->data + (sign * i * req->size),
        !           617:                         (uint8_t*) &tmp, req->size);
        !           618:             }
        !           619:         } else if (req->dir == IOREQ_WRITE) {
        !           620:             for (i = 0; i < req->count; i++) {
        !           621:                 cpu_physical_memory_read(req->data + (sign * i * req->size),
        !           622:                         (uint8_t*) &tmp, req->size);
        !           623:                 cpu_physical_memory_write(req->addr + (sign * i * req->size),
        !           624:                         (uint8_t*) &tmp, req->size);
        !           625:             }
        !           626:         }
        !           627:     }
        !           628: }
        !           629: 
        !           630: static void handle_ioreq(ioreq_t *req)
        !           631: {
        !           632:     if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) &&
        !           633:             (req->size < sizeof (target_ulong))) {
        !           634:         req->data &= ((target_ulong) 1 << (8 * req->size)) - 1;
        !           635:     }
        !           636: 
        !           637:     switch (req->type) {
        !           638:         case IOREQ_TYPE_PIO:
        !           639:             cpu_ioreq_pio(req);
        !           640:             break;
        !           641:         case IOREQ_TYPE_COPY:
        !           642:             cpu_ioreq_move(req);
        !           643:             break;
        !           644:         case IOREQ_TYPE_TIMEOFFSET:
        !           645:             break;
        !           646:         case IOREQ_TYPE_INVALIDATE:
        !           647:             xen_invalidate_map_cache();
        !           648:             break;
        !           649:         default:
        !           650:             hw_error("Invalid ioreq type 0x%x\n", req->type);
        !           651:     }
        !           652: }
        !           653: 
        !           654: static void handle_buffered_iopage(XenIOState *state)
        !           655: {
        !           656:     buf_ioreq_t *buf_req = NULL;
        !           657:     ioreq_t req;
        !           658:     int qw;
        !           659: 
        !           660:     if (!state->buffered_io_page) {
        !           661:         return;
        !           662:     }
        !           663: 
        !           664:     while (state->buffered_io_page->read_pointer != state->buffered_io_page->write_pointer) {
        !           665:         buf_req = &state->buffered_io_page->buf_ioreq[
        !           666:             state->buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM];
        !           667:         req.size = 1UL << buf_req->size;
        !           668:         req.count = 1;
        !           669:         req.addr = buf_req->addr;
        !           670:         req.data = buf_req->data;
        !           671:         req.state = STATE_IOREQ_READY;
        !           672:         req.dir = buf_req->dir;
        !           673:         req.df = 1;
        !           674:         req.type = buf_req->type;
        !           675:         req.data_is_ptr = 0;
        !           676:         qw = (req.size == 8);
        !           677:         if (qw) {
        !           678:             buf_req = &state->buffered_io_page->buf_ioreq[
        !           679:                 (state->buffered_io_page->read_pointer + 1) % IOREQ_BUFFER_SLOT_NUM];
        !           680:             req.data |= ((uint64_t)buf_req->data) << 32;
        !           681:         }
        !           682: 
        !           683:         handle_ioreq(&req);
        !           684: 
        !           685:         xen_mb();
        !           686:         state->buffered_io_page->read_pointer += qw ? 2 : 1;
        !           687:     }
        !           688: }
        !           689: 
        !           690: static void handle_buffered_io(void *opaque)
        !           691: {
        !           692:     XenIOState *state = opaque;
        !           693: 
        !           694:     handle_buffered_iopage(state);
        !           695:     qemu_mod_timer(state->buffered_io_timer,
        !           696:                    BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
        !           697: }
        !           698: 
        !           699: static void cpu_handle_ioreq(void *opaque)
        !           700: {
        !           701:     XenIOState *state = opaque;
        !           702:     ioreq_t *req = cpu_get_ioreq(state);
        !           703: 
        !           704:     handle_buffered_iopage(state);
        !           705:     if (req) {
        !           706:         handle_ioreq(req);
        !           707: 
        !           708:         if (req->state != STATE_IOREQ_INPROCESS) {
        !           709:             fprintf(stderr, "Badness in I/O request ... not in service?!: "
        !           710:                     "%x, ptr: %x, port: %"PRIx64", "
        !           711:                     "data: %"PRIx64", count: %" FMT_ioreq_size ", size: %" FMT_ioreq_size "\n",
        !           712:                     req->state, req->data_is_ptr, req->addr,
        !           713:                     req->data, req->count, req->size);
        !           714:             destroy_hvm_domain();
        !           715:             return;
        !           716:         }
        !           717: 
        !           718:         xen_wmb(); /* Update ioreq contents /then/ update state. */
        !           719: 
        !           720:         /*
        !           721:          * We do this before we send the response so that the tools
        !           722:          * have the opportunity to pick up on the reset before the
        !           723:          * guest resumes and does a hlt with interrupts disabled which
        !           724:          * causes Xen to powerdown the domain.
        !           725:          */
        !           726:         if (vm_running) {
        !           727:             if (qemu_shutdown_requested_get()) {
        !           728:                 destroy_hvm_domain();
        !           729:             }
        !           730:             if (qemu_reset_requested_get()) {
        !           731:                 qemu_system_reset(VMRESET_REPORT);
        !           732:             }
        !           733:         }
        !           734: 
        !           735:         req->state = STATE_IORESP_READY;
        !           736:         xc_evtchn_notify(state->xce_handle, state->ioreq_local_port[state->send_vcpu]);
        !           737:     }
        !           738: }
        !           739: 
        !           740: static int store_dev_info(int domid, CharDriverState *cs, const char *string)
        !           741: {
        !           742:     struct xs_handle *xs = NULL;
        !           743:     char *path = NULL;
        !           744:     char *newpath = NULL;
        !           745:     char *pts = NULL;
        !           746:     int ret = -1;
        !           747: 
        !           748:     /* Only continue if we're talking to a pty. */
        !           749:     if (strncmp(cs->filename, "pty:", 4)) {
        !           750:         return 0;
        !           751:     }
        !           752:     pts = cs->filename + 4;
        !           753: 
        !           754:     /* We now have everything we need to set the xenstore entry. */
        !           755:     xs = xs_open(0);
        !           756:     if (xs == NULL) {
        !           757:         fprintf(stderr, "Could not contact XenStore\n");
        !           758:         goto out;
        !           759:     }
        !           760: 
        !           761:     path = xs_get_domain_path(xs, domid);
        !           762:     if (path == NULL) {
        !           763:         fprintf(stderr, "xs_get_domain_path() error\n");
        !           764:         goto out;
        !           765:     }
        !           766:     newpath = realloc(path, (strlen(path) + strlen(string) +
        !           767:                 strlen("/tty") + 1));
        !           768:     if (newpath == NULL) {
        !           769:         fprintf(stderr, "realloc error\n");
        !           770:         goto out;
        !           771:     }
        !           772:     path = newpath;
        !           773: 
        !           774:     strcat(path, string);
        !           775:     strcat(path, "/tty");
        !           776:     if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) {
        !           777:         fprintf(stderr, "xs_write for '%s' fail", string);
        !           778:         goto out;
        !           779:     }
        !           780:     ret = 0;
        !           781: 
        !           782: out:
        !           783:     free(path);
        !           784:     xs_close(xs);
        !           785: 
        !           786:     return ret;
        !           787: }
        !           788: 
        !           789: void xenstore_store_pv_console_info(int i, CharDriverState *chr)
        !           790: {
        !           791:     if (i == 0) {
        !           792:         store_dev_info(xen_domid, chr, "/console");
        !           793:     } else {
        !           794:         char buf[32];
        !           795:         snprintf(buf, sizeof(buf), "/device/console/%d", i);
        !           796:         store_dev_info(xen_domid, chr, buf);
        !           797:     }
        !           798: }
        !           799: 
        !           800: static void xenstore_record_dm_state(XenIOState *s, const char *state)
        !           801: {
        !           802:     char path[50];
        !           803: 
        !           804:     snprintf(path, sizeof (path), "/local/domain/0/device-model/%u/state", xen_domid);
        !           805:     if (!xs_write(s->xenstore, XBT_NULL, path, state, strlen(state))) {
        !           806:         fprintf(stderr, "error recording dm state\n");
        !           807:         exit(1);
        !           808:     }
        !           809: }
        !           810: 
        !           811: static void xen_main_loop_prepare(XenIOState *state)
        !           812: {
        !           813:     int evtchn_fd = -1;
        !           814: 
        !           815:     if (state->xce_handle != XC_HANDLER_INITIAL_VALUE) {
        !           816:         evtchn_fd = xc_evtchn_fd(state->xce_handle);
        !           817:     }
        !           818: 
        !           819:     state->buffered_io_timer = qemu_new_timer_ms(rt_clock, handle_buffered_io,
        !           820:                                                  state);
        !           821:     qemu_mod_timer(state->buffered_io_timer, qemu_get_clock_ms(rt_clock));
        !           822: 
        !           823:     if (evtchn_fd != -1) {
        !           824:         qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state);
        !           825:     }
        !           826: 
        !           827:     /* record state running */
        !           828:     xenstore_record_dm_state(state, "running");
        !           829: }
        !           830: 
        !           831: 
        !           832: /* Initialise Xen */
        !           833: 
        !           834: static void xen_vm_change_state_handler(void *opaque, int running, int reason)
        !           835: {
        !           836:     XenIOState *state = opaque;
        !           837:     if (running) {
        !           838:         xen_main_loop_prepare(state);
        !           839:     }
        !           840: }
        !           841: 
        !           842: static void xen_exit_notifier(Notifier *n, void *data)
        !           843: {
        !           844:     XenIOState *state = container_of(n, XenIOState, exit);
        !           845: 
        !           846:     xc_evtchn_close(state->xce_handle);
        !           847:     xs_daemon_close(state->xenstore);
        !           848: }
        !           849: 
        !           850: int xen_init(void)
        !           851: {
        !           852:     xen_xc = xen_xc_interface_open(0, 0, 0);
        !           853:     if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
        !           854:         xen_be_printf(NULL, 0, "can't open xen interface\n");
        !           855:         return -1;
        !           856:     }
        !           857: 
        !           858:     return 0;
        !           859: }
        !           860: 
        !           861: int xen_hvm_init(void)
        !           862: {
        !           863:     int i, rc;
        !           864:     unsigned long ioreq_pfn;
        !           865:     XenIOState *state;
        !           866: 
        !           867:     state = qemu_mallocz(sizeof (XenIOState));
        !           868: 
        !           869:     state->xce_handle = xen_xc_evtchn_open(NULL, 0);
        !           870:     if (state->xce_handle == XC_HANDLER_INITIAL_VALUE) {
        !           871:         perror("xen: event channel open");
        !           872:         return -errno;
        !           873:     }
        !           874: 
        !           875:     state->xenstore = xs_daemon_open();
        !           876:     if (state->xenstore == NULL) {
        !           877:         perror("xen: xenstore open");
        !           878:         return -errno;
        !           879:     }
        !           880: 
        !           881:     state->exit.notify = xen_exit_notifier;
        !           882:     qemu_add_exit_notifier(&state->exit);
        !           883: 
        !           884:     xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
        !           885:     DPRINTF("shared page at pfn %lx\n", ioreq_pfn);
        !           886:     state->shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
        !           887:                                               PROT_READ|PROT_WRITE, ioreq_pfn);
        !           888:     if (state->shared_page == NULL) {
        !           889:         hw_error("map shared IO page returned error %d handle=" XC_INTERFACE_FMT,
        !           890:                  errno, xen_xc);
        !           891:     }
        !           892: 
        !           893:     xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn);
        !           894:     DPRINTF("buffered io page at pfn %lx\n", ioreq_pfn);
        !           895:     state->buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
        !           896:                                                    PROT_READ|PROT_WRITE, ioreq_pfn);
        !           897:     if (state->buffered_io_page == NULL) {
        !           898:         hw_error("map buffered IO page returned error %d", errno);
        !           899:     }
        !           900: 
        !           901:     state->ioreq_local_port = qemu_mallocz(smp_cpus * sizeof (evtchn_port_t));
        !           902: 
        !           903:     /* FIXME: how about if we overflow the page here? */
        !           904:     for (i = 0; i < smp_cpus; i++) {
        !           905:         rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid,
        !           906:                                         xen_vcpu_eport(state->shared_page, i));
        !           907:         if (rc == -1) {
        !           908:             fprintf(stderr, "bind interdomain ioctl error %d\n", errno);
        !           909:             return -1;
        !           910:         }
        !           911:         state->ioreq_local_port[i] = rc;
        !           912:     }
        !           913: 
        !           914:     /* Init RAM management */
        !           915:     xen_map_cache_init();
        !           916:     xen_ram_init(ram_size);
        !           917: 
        !           918:     qemu_add_vm_change_state_handler(xen_vm_change_state_handler, state);
        !           919: 
        !           920:     state->client = xen_cpu_phys_memory_client;
        !           921:     QLIST_INIT(&state->physmap);
        !           922:     cpu_register_phys_memory_client(&state->client);
        !           923:     state->log_for_dirtybit = NULL;
        !           924: 
        !           925:     /* Initialize backend core & drivers */
        !           926:     if (xen_be_init() != 0) {
        !           927:         fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
        !           928:         exit(1);
        !           929:     }
        !           930:     xen_be_register("console", &xen_console_ops);
        !           931:     xen_be_register("vkbd", &xen_kbdmouse_ops);
        !           932:     xen_be_register("qdisk", &xen_blkdev_ops);
        !           933: 
        !           934:     return 0;
        !           935: }
        !           936: 
        !           937: void destroy_hvm_domain(void)
        !           938: {
        !           939:     XenXC xc_handle;
        !           940:     int sts;
        !           941: 
        !           942:     xc_handle = xen_xc_interface_open(0, 0, 0);
        !           943:     if (xc_handle == XC_HANDLER_INITIAL_VALUE) {
        !           944:         fprintf(stderr, "Cannot acquire xenctrl handle\n");
        !           945:     } else {
        !           946:         sts = xc_domain_shutdown(xc_handle, xen_domid, SHUTDOWN_poweroff);
        !           947:         if (sts != 0) {
        !           948:             fprintf(stderr, "? xc_domain_shutdown failed to issue poweroff, "
        !           949:                     "sts %d, %s\n", sts, strerror(errno));
        !           950:         } else {
        !           951:             fprintf(stderr, "Issued domain %d poweroff\n", xen_domid);
        !           952:         }
        !           953:         xc_interface_close(xc_handle);
        !           954:     }
        !           955: }

unix.superglobalmegacorp.com