| Hollis Blanchard | bbf45ba | 2008-04-16 23:28:09 -0500 | [diff] [blame] | 1 | /* | 
|  | 2 | * This program is free software; you can redistribute it and/or modify | 
|  | 3 | * it under the terms of the GNU General Public License, version 2, as | 
|  | 4 | * published by the Free Software Foundation. | 
|  | 5 | * | 
|  | 6 | * This program is distributed in the hope that it will be useful, | 
|  | 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 9 | * GNU General Public License for more details. | 
|  | 10 | * | 
|  | 11 | * You should have received a copy of the GNU General Public License | 
|  | 12 | * along with this program; if not, write to the Free Software | 
|  | 13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
|  | 14 | * | 
|  | 15 | * Copyright IBM Corp. 2008 | 
|  | 16 | * | 
|  | 17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | 
|  | 18 | */ | 
|  | 19 |  | 
|  | 20 | #include <linux/errno.h> | 
|  | 21 | #include <linux/kvm_host.h> | 
|  | 22 | #include <linux/module.h> | 
|  | 23 | #include <asm/cacheflush.h> | 
|  | 24 | #include <asm/kvm_ppc.h> | 
|  | 25 |  | 
|  | 26 | unsigned long kvmppc_booke_handlers; | 
|  | 27 |  | 
|  | 28 | static int kvmppc_booke_init(void) | 
|  | 29 | { | 
|  | 30 | unsigned long ivor[16]; | 
|  | 31 | unsigned long max_ivor = 0; | 
|  | 32 | int i; | 
|  | 33 |  | 
|  | 34 | /* We install our own exception handlers by hijacking IVPR. IVPR must | 
|  | 35 | * be 16-bit aligned, so we need a 64KB allocation. */ | 
|  | 36 | kvmppc_booke_handlers = __get_free_pages(GFP_KERNEL | __GFP_ZERO, | 
|  | 37 | VCPU_SIZE_ORDER); | 
|  | 38 | if (!kvmppc_booke_handlers) | 
|  | 39 | return -ENOMEM; | 
|  | 40 |  | 
|  | 41 | /* XXX make sure our handlers are smaller than Linux's */ | 
|  | 42 |  | 
|  | 43 | /* Copy our interrupt handlers to match host IVORs. That way we don't | 
|  | 44 | * have to swap the IVORs on every guest/host transition. */ | 
|  | 45 | ivor[0] = mfspr(SPRN_IVOR0); | 
|  | 46 | ivor[1] = mfspr(SPRN_IVOR1); | 
|  | 47 | ivor[2] = mfspr(SPRN_IVOR2); | 
|  | 48 | ivor[3] = mfspr(SPRN_IVOR3); | 
|  | 49 | ivor[4] = mfspr(SPRN_IVOR4); | 
|  | 50 | ivor[5] = mfspr(SPRN_IVOR5); | 
|  | 51 | ivor[6] = mfspr(SPRN_IVOR6); | 
|  | 52 | ivor[7] = mfspr(SPRN_IVOR7); | 
|  | 53 | ivor[8] = mfspr(SPRN_IVOR8); | 
|  | 54 | ivor[9] = mfspr(SPRN_IVOR9); | 
|  | 55 | ivor[10] = mfspr(SPRN_IVOR10); | 
|  | 56 | ivor[11] = mfspr(SPRN_IVOR11); | 
|  | 57 | ivor[12] = mfspr(SPRN_IVOR12); | 
|  | 58 | ivor[13] = mfspr(SPRN_IVOR13); | 
|  | 59 | ivor[14] = mfspr(SPRN_IVOR14); | 
|  | 60 | ivor[15] = mfspr(SPRN_IVOR15); | 
|  | 61 |  | 
|  | 62 | for (i = 0; i < 16; i++) { | 
|  | 63 | if (ivor[i] > max_ivor) | 
|  | 64 | max_ivor = ivor[i]; | 
|  | 65 |  | 
|  | 66 | memcpy((void *)kvmppc_booke_handlers + ivor[i], | 
|  | 67 | kvmppc_handlers_start + i * kvmppc_handler_len, | 
|  | 68 | kvmppc_handler_len); | 
|  | 69 | } | 
|  | 70 | flush_icache_range(kvmppc_booke_handlers, | 
|  | 71 | kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); | 
|  | 72 |  | 
|  | 73 | return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE); | 
|  | 74 | } | 
|  | 75 |  | 
|  | 76 | static void __exit kvmppc_booke_exit(void) | 
|  | 77 | { | 
|  | 78 | free_pages(kvmppc_booke_handlers, VCPU_SIZE_ORDER); | 
|  | 79 | kvm_exit(); | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | module_init(kvmppc_booke_init) | 
|  | 83 | module_exit(kvmppc_booke_exit) |