source: trunk/packages/xen-common/xen-common/xen/arch/x86/hvm/intercept.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 7.8 KB
Line 
1/*
2 * intercept.c: Handle performance critical I/O packets in hypervisor space
3 *
4 * Copyright (c) 2004, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 */
19
20#include <xen/config.h>
21#include <xen/types.h>
22#include <xen/sched.h>
23#include <asm/regs.h>
24#include <asm/hvm/hvm.h>
25#include <asm/hvm/support.h>
26#include <asm/hvm/domain.h>
27#include <xen/lib.h>
28#include <xen/sched.h>
29#include <asm/current.h>
30#include <io_ports.h>
31#include <xen/event.h>
32
33
34extern struct hvm_mmio_handler hpet_mmio_handler;
35extern struct hvm_mmio_handler vlapic_mmio_handler;
36extern struct hvm_mmio_handler vioapic_mmio_handler;
37
38#define HVM_MMIO_HANDLER_NR 3
39
40static struct hvm_mmio_handler *hvm_mmio_handlers[HVM_MMIO_HANDLER_NR] =
41{
42    &hpet_mmio_handler,
43    &vlapic_mmio_handler,
44    &vioapic_mmio_handler
45};
46
47struct hvm_buffered_io_range {
48    unsigned long start_addr;
49    unsigned long length;
50};
51
52#define HVM_BUFFERED_IO_RANGE_NR 1
53
54static struct hvm_buffered_io_range buffered_stdvga_range = {0xA0000, 0x20000};
55static struct hvm_buffered_io_range
56*hvm_buffered_io_ranges[HVM_BUFFERED_IO_RANGE_NR] =
57{
58    &buffered_stdvga_range
59};
60
61static inline void hvm_mmio_access(struct vcpu *v,
62                                   ioreq_t *p,
63                                   hvm_mmio_read_t read_handler,
64                                   hvm_mmio_write_t write_handler)
65{
66    unsigned int tmp1, tmp2;
67    unsigned long data;
68
69    switch ( p->type ) {
70    case IOREQ_TYPE_COPY:
71    {
72        if ( !p->data_is_ptr ) {
73            if ( p->dir == IOREQ_READ )
74                p->data = read_handler(v, p->addr, p->size);
75            else    /* p->dir == IOREQ_WRITE */
76                write_handler(v, p->addr, p->size, p->data);
77        } else {    /* p->data_is_ptr */
78            int i, sign = (p->df) ? -1 : 1;
79
80            if ( p->dir == IOREQ_READ ) {
81                for ( i = 0; i < p->count; i++ ) {
82                    data = read_handler(v,
83                        p->addr + (sign * i * p->size),
84                        p->size);
85                    (void)hvm_copy_to_guest_phys(
86                        p->data + (sign * i * p->size),
87                        &data,
88                        p->size);
89                }
90            } else {/* p->dir == IOREQ_WRITE */
91                for ( i = 0; i < p->count; i++ ) {
92                    (void)hvm_copy_from_guest_phys(
93                        &data,
94                        p->data + (sign * i * p->size),
95                        p->size);
96                    write_handler(v,
97                        p->addr + (sign * i * p->size),
98                        p->size, data);
99                }
100            }
101        }
102        break;
103    }
104
105    case IOREQ_TYPE_AND:
106        tmp1 = read_handler(v, p->addr, p->size);
107        if ( p->dir == IOREQ_WRITE ) {
108            tmp2 = tmp1 & (unsigned long) p->data;
109            write_handler(v, p->addr, p->size, tmp2);
110        }
111        p->data = tmp1;
112        break;
113
114    case IOREQ_TYPE_ADD:
115        tmp1 = read_handler(v, p->addr, p->size);
116        if (p->dir == IOREQ_WRITE) {
117            tmp2 = tmp1 + (unsigned long) p->data;
118            write_handler(v, p->addr, p->size, tmp2);
119        }
120        p->data = tmp1;
121        break;
122
123    case IOREQ_TYPE_OR:
124        tmp1 = read_handler(v, p->addr, p->size);
125        if ( p->dir == IOREQ_WRITE ) {
126            tmp2 = tmp1 | (unsigned long) p->data;
127            write_handler(v, p->addr, p->size, tmp2);
128        }
129        p->data = tmp1;
130        break;
131
132    case IOREQ_TYPE_XOR:
133        tmp1 = read_handler(v, p->addr, p->size);
134        if ( p->dir == IOREQ_WRITE ) {
135            tmp2 = tmp1 ^ (unsigned long) p->data;
136            write_handler(v, p->addr, p->size, tmp2);
137        }
138        p->data = tmp1;
139        break;
140
141    case IOREQ_TYPE_XCHG:
142        /*
143         * Note that we don't need to be atomic here since VCPU is accessing
144         * its own local APIC.
145         */
146        tmp1 = read_handler(v, p->addr, p->size);
147        write_handler(v, p->addr, p->size, (unsigned long) p->data);
148        p->data = tmp1;
149        break;
150
151    case IOREQ_TYPE_SUB:
152        tmp1 = read_handler(v, p->addr, p->size);
153        if ( p->dir == IOREQ_WRITE ) {
154            tmp2 = tmp1 - (unsigned long) p->data;
155            write_handler(v, p->addr, p->size, tmp2);
156        }
157        p->data = tmp1;
158        break;
159
160    default:
161        printk("hvm_mmio_access: error ioreq type %x\n", p->type);
162        domain_crash_synchronous();
163        break;
164    }
165}
166
167int hvm_buffered_io_send(ioreq_t *p)
168{
169    struct vcpu *v = current;
170    struct hvm_ioreq_page *iorp = &v->domain->arch.hvm_domain.buf_ioreq;
171    buffered_iopage_t *pg = iorp->va;
172
173    spin_lock(&iorp->lock);
174
175    if ( (pg->write_pointer - pg->read_pointer) == IOREQ_BUFFER_SLOT_NUM )
176    {
177        /* The queue is full: send the iopacket through the normal path. */
178        spin_unlock(&iorp->lock);
179        return 0;
180    }
181
182    memcpy(&pg->ioreq[pg->write_pointer % IOREQ_BUFFER_SLOT_NUM],
183           p, sizeof(ioreq_t));
184
185    /* Make the ioreq_t visible /before/ write_pointer. */
186    wmb();
187    pg->write_pointer++;
188
189    spin_unlock(&iorp->lock);
190
191    return 1;
192}
193
194int hvm_buffered_io_intercept(ioreq_t *p)
195{
196    int i;
197
198    /* ignore READ ioreq_t! */
199    if ( p->dir == IOREQ_READ )
200        return 0;
201
202    for ( i = 0; i < HVM_BUFFERED_IO_RANGE_NR; i++ ) {
203        if ( p->addr >= hvm_buffered_io_ranges[i]->start_addr &&
204             p->addr + p->size - 1 < hvm_buffered_io_ranges[i]->start_addr +
205                                     hvm_buffered_io_ranges[i]->length )
206            break;
207    }
208
209    if ( i == HVM_BUFFERED_IO_RANGE_NR )
210        return 0;
211
212    return hvm_buffered_io_send(p);
213}
214
215int hvm_mmio_intercept(ioreq_t *p)
216{
217    struct vcpu *v = current;
218    int i;
219
220    for ( i = 0; i < HVM_MMIO_HANDLER_NR; i++ )
221    {
222        if ( hvm_mmio_handlers[i]->check_handler(v, p->addr) )
223        {
224            hvm_mmio_access(v, p,
225                            hvm_mmio_handlers[i]->read_handler,
226                            hvm_mmio_handlers[i]->write_handler);
227            return 1;
228        }
229    }
230
231    return 0;
232}
233
234/*
235 * Check if the request is handled inside xen
236 * return value: 0 --not handled; 1 --handled
237 */
238int hvm_io_intercept(ioreq_t *p, int type)
239{
240    struct vcpu *v = current;
241    struct hvm_io_handler *handler =
242                           &(v->domain->arch.hvm_domain.io_handler);
243    int i;
244    unsigned long addr, size;
245
246    for (i = 0; i < handler->num_slot; i++) {
247        if( type != handler->hdl_list[i].type)
248            continue;
249        addr = handler->hdl_list[i].addr;
250        size = handler->hdl_list[i].size;
251        if (p->addr >= addr &&
252            p->addr <  addr + size)
253            return handler->hdl_list[i].action(p);
254    }
255    return 0;
256}
257
258int register_io_handler(
259    struct domain *d, unsigned long addr, unsigned long size,
260    intercept_action_t action, int type)
261{
262    struct hvm_io_handler *handler = &d->arch.hvm_domain.io_handler;
263    int num = handler->num_slot;
264
265    BUG_ON(num >= MAX_IO_HANDLER);
266
267    handler->hdl_list[num].addr = addr;
268    handler->hdl_list[num].size = size;
269    handler->hdl_list[num].action = action;
270    handler->hdl_list[num].type = type;
271    handler->num_slot++;
272
273    return 1;
274}
275/*
276 * Local variables:
277 * mode: C
278 * c-set-style: "BSD"
279 * c-basic-offset: 4
280 * tab-width: 4
281 * indent-tabs-mode: nil
282 * End:
283 */
Note: See TracBrowser for help on using the repository browser.