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) |