2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
29 #include <ipxe/malloc.h>
31 #include <ipxe/cpuid.h>
34 #include <ipxe/xenver.h>
35 #include <ipxe/xenmem.h>
36 #include <ipxe/xenstore.h>
37 #include <ipxe/xenbus.h>
38 #include <ipxe/xengrant.h>
51 * @ret rc Return status code
53 static int hvm_cpuid_base ( struct hvm_device
*hvm
) {
58 } __attribute__ (( packed
)) signature
;
66 /* Scan for magic signature */
67 for ( base
= HVM_CPUID_MIN
; base
<= HVM_CPUID_MAX
;
68 base
+= HVM_CPUID_STEP
) {
69 cpuid ( base
, 0, &discard_eax
, &signature
.ebx
, &signature
.ecx
,
71 if ( memcmp ( &signature
, HVM_CPUID_MAGIC
,
72 sizeof ( signature
) ) == 0 ) {
73 hvm
->cpuid_base
= base
;
74 cpuid ( ( base
+ HVM_CPUID_VERSION
), 0, &version
,
75 &discard_ebx
, &discard_ecx
, &discard_edx
);
76 DBGC2 ( hvm
, "HVM using CPUID base %#08x (v%d.%d)\n",
77 base
, ( version
>> 16 ), ( version
& 0xffff ) );
82 DBGC ( hvm
, "HVM could not find hypervisor\n" );
87 * Map hypercall page(s)
90 * @ret rc Return status code
92 static int hvm_map_hypercall ( struct hvm_device
*hvm
) {
97 physaddr_t hypercall_phys
;
99 static xen_extraversion_t extraversion
;
103 /* Get number of hypercall pages and MSR to use */
104 cpuid ( ( hvm
->cpuid_base
+ HVM_CPUID_PAGES
), 0, &pages
, &msr
,
105 &discard_ecx
, &discard_edx
);
108 hvm
->hypercall_len
= ( pages
* PAGE_SIZE
);
109 hvm
->xen
.hypercall
= malloc_dma ( hvm
->hypercall_len
, PAGE_SIZE
);
110 if ( ! hvm
->xen
.hypercall
) {
111 DBGC ( hvm
, "HVM could not allocate %d hypercall page(s)\n",
115 hypercall_phys
= virt_to_phys ( hvm
->xen
.hypercall
);
116 DBGC2 ( hvm
, "HVM hypercall page(s) at [%#08lx,%#08lx) via MSR %#08x\n",
117 hypercall_phys
, ( hypercall_phys
+ hvm
->hypercall_len
), msr
);
120 wrmsr ( msr
, hypercall_phys
);
122 /* Check that hypercall mechanism is working */
123 version
= xenver_version ( &hvm
->xen
);
124 if ( ( xenrc
= xenver_extraversion ( &hvm
->xen
, &extraversion
) ) != 0){
125 rc
= -EXEN ( xenrc
);
126 DBGC ( hvm
, "HVM could not get extraversion: %s\n",
130 DBGC2 ( hvm
, "HVM found Xen version %d.%d%s\n",
131 ( version
>> 16 ), ( version
& 0xffff ) , extraversion
);
137 * Unmap hypercall page(s)
141 static void hvm_unmap_hypercall ( struct hvm_device
*hvm
) {
144 free_dma ( hvm
->xen
.hypercall
, hvm
->hypercall_len
);
148 * Allocate and map MMIO space
151 * @v space Source mapping space
152 * @v len Length (must be a multiple of PAGE_SIZE)
153 * @ret mmio MMIO space address, or NULL on error
155 static void * hvm_ioremap ( struct hvm_device
*hvm
, unsigned int space
,
157 struct xen_add_to_physmap add
;
158 struct xen_remove_from_physmap remove
;
159 unsigned int pages
= ( len
/ PAGE_SIZE
);
160 physaddr_t mmio_phys
;
167 assert ( ( len
% PAGE_SIZE
) == 0 );
169 /* Check for available space */
170 if ( ( hvm
->mmio_offset
+ len
) > hvm
->mmio_len
) {
171 DBGC ( hvm
, "HVM could not allocate %zd bytes of MMIO space "
172 "(%zd of %zd remaining)\n", len
,
173 ( hvm
->mmio_len
- hvm
->mmio_offset
), hvm
->mmio_len
);
178 mmio
= ioremap ( ( hvm
->mmio
+ hvm
->mmio_offset
), len
);
180 DBGC ( hvm
, "HVM could not map MMIO space [%08lx,%08lx)\n",
181 ( hvm
->mmio
+ hvm
->mmio_offset
),
182 ( hvm
->mmio
+ hvm
->mmio_offset
+ len
) );
185 mmio_phys
= virt_to_phys ( mmio
);
187 /* Add to physical address space */
188 for ( i
= 0 ; i
< pages
; i
++ ) {
189 add
.domid
= DOMID_SELF
;
192 add
.gpfn
= ( ( mmio_phys
/ PAGE_SIZE
) + i
);
193 if ( ( xenrc
= xenmem_add_to_physmap ( &hvm
->xen
, &add
) ) !=0){
194 rc
= -EXEN ( xenrc
);
195 DBGC ( hvm
, "HVM could not add space %d idx %d at "
196 "[%08lx,%08lx): %s\n", space
, i
,
197 ( mmio_phys
+ ( i
* PAGE_SIZE
) ),
198 ( mmio_phys
+ ( ( i
+ 1 ) * PAGE_SIZE
) ),
200 goto err_add_to_physmap
;
205 hvm
->mmio_offset
+= len
;
211 for ( i
-- ; ( signed int ) i
>= 0 ; i
-- ) {
212 remove
.domid
= DOMID_SELF
;
213 add
.gpfn
= ( ( mmio_phys
/ PAGE_SIZE
) + i
);
214 xenmem_remove_from_physmap ( &hvm
->xen
, &remove
);
226 * @v mmio MMIO space address
227 * @v len Length (must be a multiple of PAGE_SIZE)
229 static void hvm_iounmap ( struct hvm_device
*hvm
, void *mmio
, size_t len
) {
230 struct xen_remove_from_physmap remove
;
231 physaddr_t mmio_phys
= virt_to_phys ( mmio
);
232 unsigned int pages
= ( len
/ PAGE_SIZE
);
237 /* Unmap this space */
240 /* Remove from physical address space */
241 for ( i
= 0 ; i
< pages
; i
++ ) {
242 remove
.domid
= DOMID_SELF
;
243 remove
.gpfn
= ( ( mmio_phys
/ PAGE_SIZE
) + i
);
244 if ( ( xenrc
= xenmem_remove_from_physmap ( &hvm
->xen
,
246 rc
= -EXEN ( xenrc
);
247 DBGC ( hvm
, "HVM could not remove space [%08lx,%08lx): "
248 "%s\n", ( mmio_phys
+ ( i
* PAGE_SIZE
) ),
249 ( mmio_phys
+ ( ( i
+ 1 ) * PAGE_SIZE
) ),
251 /* Nothing we can do about this */
257 * Map shared info page
260 * @ret rc Return status code
262 static int hvm_map_shared_info ( struct hvm_device
*hvm
) {
263 physaddr_t shared_info_phys
;
266 /* Map shared info page */
267 hvm
->xen
.shared
= hvm_ioremap ( hvm
, XENMAPSPACE_shared_info
,
269 if ( ! hvm
->xen
.shared
) {
273 shared_info_phys
= virt_to_phys ( hvm
->xen
.shared
);
274 DBGC2 ( hvm
, "HVM shared info page at [%#08lx,%#08lx)\n",
275 shared_info_phys
, ( shared_info_phys
+ PAGE_SIZE
) );
278 DBGC2 ( hvm
, "HVM wallclock time is %d\n",
279 readl ( &hvm
->xen
.shared
->wc_sec
) );
283 hvm_iounmap ( hvm
, hvm
->xen
.shared
, PAGE_SIZE
);
289 * Unmap shared info page
293 static void hvm_unmap_shared_info ( struct hvm_device
*hvm
) {
295 /* Unmap shared info page */
296 hvm_iounmap ( hvm
, hvm
->xen
.shared
, PAGE_SIZE
);
303 * @ret rc Return status code
305 static int hvm_map_grant ( struct hvm_device
*hvm
) {
306 physaddr_t grant_phys
;
309 /* Initialise grant table */
310 if ( ( rc
= xengrant_init ( &hvm
->xen
) ) != 0 ) {
311 DBGC ( hvm
, "HVM could not initialise grant table: %s\n",
316 /* Map grant table */
317 hvm
->xen
.grant
.table
= hvm_ioremap ( hvm
, XENMAPSPACE_grant_table
,
318 hvm
->xen
.grant
.len
);
319 if ( ! hvm
->xen
.grant
.table
)
322 grant_phys
= virt_to_phys ( hvm
->xen
.grant
.table
);
323 DBGC2 ( hvm
, "HVM mapped grant table at [%08lx,%08lx)\n",
324 grant_phys
, ( grant_phys
+ hvm
->xen
.grant
.len
) );
333 static void hvm_unmap_grant ( struct hvm_device
*hvm
) {
335 /* Unmap grant table */
336 hvm_iounmap ( hvm
, hvm
->xen
.grant
.table
, hvm
->xen
.grant
.len
);
343 * @ret rc Return status code
345 static int hvm_map_xenstore ( struct hvm_device
*hvm
) {
346 uint64_t xenstore_evtchn
;
347 uint64_t xenstore_pfn
;
348 physaddr_t xenstore_phys
;
353 /* Get XenStore event channel */
354 if ( ( xenrc
= xen_hvm_get_param ( &hvm
->xen
, HVM_PARAM_STORE_EVTCHN
,
355 &xenstore_evtchn
) ) != 0 ) {
356 rc
= -EXEN ( xenrc
);
357 DBGC ( hvm
, "HVM could not get XenStore event channel: %s\n",
361 hvm
->xen
.store
.port
= xenstore_evtchn
;
363 /* Get XenStore PFN */
364 if ( ( xenrc
= xen_hvm_get_param ( &hvm
->xen
, HVM_PARAM_STORE_PFN
,
365 &xenstore_pfn
) ) != 0 ) {
366 rc
= -EXEN ( xenrc
);
367 DBGC ( hvm
, "HVM could not get XenStore PFN: %s\n",
371 xenstore_phys
= ( xenstore_pfn
* PAGE_SIZE
);
374 hvm
->xen
.store
.intf
= ioremap ( xenstore_phys
, PAGE_SIZE
);
375 if ( ! hvm
->xen
.store
.intf
) {
376 DBGC ( hvm
, "HVM could not map XenStore at [%08lx,%08lx)\n",
377 xenstore_phys
, ( xenstore_phys
+ PAGE_SIZE
) );
380 DBGC2 ( hvm
, "HVM mapped XenStore at [%08lx,%08lx) with event port "
381 "%d\n", xenstore_phys
, ( xenstore_phys
+ PAGE_SIZE
),
382 hvm
->xen
.store
.port
);
384 /* Check that XenStore is working */
385 if ( ( rc
= xenstore_read ( &hvm
->xen
, &name
, "name", NULL
) ) != 0 ) {
386 DBGC ( hvm
, "HVM could not read domain name: %s\n",
390 DBGC2 ( hvm
, "HVM running in domain \"%s\"\n", name
);
401 static void hvm_unmap_xenstore ( struct hvm_device
*hvm
) {
404 iounmap ( hvm
->xen
.store
.intf
);
411 * @ret rc Return status code
413 static int hvm_probe ( struct pci_device
*pci
) {
414 struct hvm_device
*hvm
;
417 /* Allocate and initialise structure */
418 hvm
= zalloc ( sizeof ( *hvm
) );
423 hvm
->mmio
= pci_bar_start ( pci
, HVM_MMIO_BAR
);
424 hvm
->mmio_len
= pci_bar_size ( pci
, HVM_MMIO_BAR
);
425 DBGC2 ( hvm
, "HVM has MMIO space [%08lx,%08lx)\n",
426 hvm
->mmio
, ( hvm
->mmio
+ hvm
->mmio_len
) );
428 /* Fix up PCI device */
429 adjust_pci_device ( pci
);
431 /* Attach to hypervisor */
432 if ( ( rc
= hvm_cpuid_base ( hvm
) ) != 0 )
434 if ( ( rc
= hvm_map_hypercall ( hvm
) ) != 0 )
435 goto err_map_hypercall
;
436 if ( ( rc
= hvm_map_shared_info ( hvm
) ) != 0 )
437 goto err_map_shared_info
;
438 if ( ( rc
= hvm_map_grant ( hvm
) ) != 0 )
440 if ( ( rc
= hvm_map_xenstore ( hvm
) ) != 0 )
441 goto err_map_xenstore
;
443 /* Probe Xen devices */
444 if ( ( rc
= xenbus_probe ( &hvm
->xen
, &pci
->dev
) ) != 0 ) {
445 DBGC ( hvm
, "HVM could not probe Xen bus: %s\n",
447 goto err_xenbus_probe
;
450 pci_set_drvdata ( pci
, hvm
);
453 xenbus_remove ( &hvm
->xen
, &pci
->dev
);
455 hvm_unmap_xenstore ( hvm
);
457 hvm_unmap_grant ( hvm
);
459 hvm_unmap_shared_info ( hvm
);
461 hvm_unmap_hypercall ( hvm
);
474 static void hvm_remove ( struct pci_device
*pci
) {
475 struct hvm_device
*hvm
= pci_get_drvdata ( pci
);
477 xenbus_remove ( &hvm
->xen
, &pci
->dev
);
478 hvm_unmap_xenstore ( hvm
);
479 hvm_unmap_grant ( hvm
);
480 hvm_unmap_shared_info ( hvm
);
481 hvm_unmap_hypercall ( hvm
);
485 /** PCI device IDs */
486 static struct pci_device_id hvm_ids
[] = {
487 PCI_ROM ( 0x5853, 0x0001, "hvm", "hvm", 0 ),
488 PCI_ROM ( 0x5853, 0x0002, "hvm2", "hvm2", 0 ),
492 struct pci_driver hvm_driver __pci_driver
= {
494 .id_count
= ( sizeof ( hvm_ids
) / sizeof ( hvm_ids
[0] ) ),
496 .remove
= hvm_remove
,
499 /* Drag in objects via hvm_driver */
500 REQUIRING_SYMBOL ( hvm_driver
);
502 /* Drag in netfront driver */
503 //REQUIRE_OBJECT ( netfront );