Anthony PERARD | 3285cf4 | 2010-08-19 12:27:56 +0100 | [diff] [blame] | 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 | |
Anthony PERARD | 4144530 | 2010-07-16 14:55:39 +0100 | [diff] [blame] | 9 | #include "hw/pci.h" |
Anthony PERARD | 3285cf4 | 2010-08-19 12:27:56 +0100 | [diff] [blame] | 10 | #include "hw/xen_common.h" |
| 11 | #include "hw/xen_backend.h" |
| 12 | |
Jun Nakajima | 432d268 | 2010-08-31 16:41:25 +0100 | [diff] [blame] | 13 | #include "xen-mapcache.h" |
| 14 | #include "trace.h" |
| 15 | |
Anthony PERARD | 4144530 | 2010-07-16 14:55:39 +0100 | [diff] [blame] | 16 | /* Xen specific function for piix pci */ |
| 17 | |
| 18 | int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) |
| 19 | { |
| 20 | return irq_num + ((pci_dev->devfn >> 3) << 2); |
| 21 | } |
| 22 | |
| 23 | void xen_piix3_set_irq(void *opaque, int irq_num, int level) |
| 24 | { |
| 25 | xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2, |
| 26 | irq_num & 3, level); |
| 27 | } |
| 28 | |
| 29 | void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) |
| 30 | { |
| 31 | int i; |
| 32 | |
| 33 | /* Scan for updates to PCI link routes (0x60-0x63). */ |
| 34 | for (i = 0; i < len; i++) { |
| 35 | uint8_t v = (val >> (8 * i)) & 0xff; |
| 36 | if (v & 0x80) { |
| 37 | v = 0; |
| 38 | } |
| 39 | v &= 0xf; |
| 40 | if (((address + i) >= 0x60) && ((address + i) <= 0x63)) { |
| 41 | xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v); |
| 42 | } |
| 43 | } |
| 44 | } |
| 45 | |
Anthony PERARD | 9c11a8a | 2010-06-30 17:50:10 +0100 | [diff] [blame] | 46 | /* Xen Interrupt Controller */ |
| 47 | |
| 48 | static void xen_set_irq(void *opaque, int irq, int level) |
| 49 | { |
| 50 | xc_hvm_set_isa_irq_level(xen_xc, xen_domid, irq, level); |
| 51 | } |
| 52 | |
| 53 | qemu_irq *xen_interrupt_controller_init(void) |
| 54 | { |
| 55 | return qemu_allocate_irqs(xen_set_irq, NULL, 16); |
| 56 | } |
| 57 | |
Jun Nakajima | 432d268 | 2010-08-31 16:41:25 +0100 | [diff] [blame] | 58 | /* Memory Ops */ |
| 59 | |
| 60 | static void xen_ram_init(ram_addr_t ram_size) |
| 61 | { |
| 62 | RAMBlock *new_block; |
| 63 | ram_addr_t below_4g_mem_size, above_4g_mem_size = 0; |
| 64 | |
| 65 | new_block = qemu_mallocz(sizeof (*new_block)); |
| 66 | pstrcpy(new_block->idstr, sizeof (new_block->idstr), "xen.ram"); |
| 67 | new_block->host = NULL; |
| 68 | new_block->offset = 0; |
| 69 | new_block->length = ram_size; |
| 70 | |
| 71 | QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next); |
| 72 | |
| 73 | ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty, |
| 74 | new_block->length >> TARGET_PAGE_BITS); |
| 75 | memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS), |
| 76 | 0xff, new_block->length >> TARGET_PAGE_BITS); |
| 77 | |
| 78 | if (ram_size >= 0xe0000000 ) { |
| 79 | above_4g_mem_size = ram_size - 0xe0000000; |
| 80 | below_4g_mem_size = 0xe0000000; |
| 81 | } else { |
| 82 | below_4g_mem_size = ram_size; |
| 83 | } |
| 84 | |
| 85 | cpu_register_physical_memory(0, below_4g_mem_size, new_block->offset); |
| 86 | #if TARGET_PHYS_ADDR_BITS > 32 |
| 87 | if (above_4g_mem_size > 0) { |
| 88 | cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size, |
| 89 | new_block->offset + below_4g_mem_size); |
| 90 | } |
| 91 | #endif |
| 92 | } |
| 93 | |
| 94 | void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size) |
| 95 | { |
| 96 | unsigned long nr_pfn; |
| 97 | xen_pfn_t *pfn_list; |
| 98 | int i; |
| 99 | |
| 100 | trace_xen_ram_alloc(ram_addr, size); |
| 101 | |
| 102 | nr_pfn = size >> TARGET_PAGE_BITS; |
| 103 | pfn_list = qemu_malloc(sizeof (*pfn_list) * nr_pfn); |
| 104 | |
| 105 | for (i = 0; i < nr_pfn; i++) { |
| 106 | pfn_list[i] = (ram_addr >> TARGET_PAGE_BITS) + i; |
| 107 | } |
| 108 | |
| 109 | if (xc_domain_populate_physmap_exact(xen_xc, xen_domid, nr_pfn, 0, 0, pfn_list)) { |
| 110 | hw_error("xen: failed to populate ram at %lx", ram_addr); |
| 111 | } |
| 112 | |
| 113 | qemu_free(pfn_list); |
| 114 | } |
| 115 | |
| 116 | |
Anthony PERARD | 29d3ccd | 2010-06-30 12:58:34 +0100 | [diff] [blame] | 117 | /* VCPU Operations, MMIO, IO ring ... */ |
| 118 | |
| 119 | static void xen_reset_vcpu(void *opaque) |
| 120 | { |
| 121 | CPUState *env = opaque; |
| 122 | |
| 123 | env->halted = 1; |
| 124 | } |
| 125 | |
| 126 | void xen_vcpu_init(void) |
| 127 | { |
| 128 | CPUState *first_cpu; |
| 129 | |
| 130 | if ((first_cpu = qemu_get_cpu(0))) { |
| 131 | qemu_register_reset(xen_reset_vcpu, first_cpu); |
| 132 | xen_reset_vcpu(first_cpu); |
| 133 | } |
| 134 | } |
| 135 | |
Anthony PERARD | 3285cf4 | 2010-08-19 12:27:56 +0100 | [diff] [blame] | 136 | /* Initialise Xen */ |
| 137 | |
| 138 | int xen_init(void) |
| 139 | { |
| 140 | xen_xc = xen_xc_interface_open(0, 0, 0); |
| 141 | if (xen_xc == XC_HANDLER_INITIAL_VALUE) { |
| 142 | xen_be_printf(NULL, 0, "can't open xen interface\n"); |
| 143 | return -1; |
| 144 | } |
| 145 | |
| 146 | return 0; |
| 147 | } |
Anthony PERARD | 29d3ccd | 2010-06-30 12:58:34 +0100 | [diff] [blame] | 148 | |
| 149 | int xen_hvm_init(void) |
| 150 | { |
Jun Nakajima | 432d268 | 2010-08-31 16:41:25 +0100 | [diff] [blame] | 151 | /* Init RAM management */ |
| 152 | qemu_map_cache_init(); |
| 153 | xen_ram_init(ram_size); |
| 154 | |
Anthony PERARD | 29d3ccd | 2010-06-30 12:58:34 +0100 | [diff] [blame] | 155 | return 0; |
| 156 | } |