diff options
author | cl349@labyrinth.cl.cam.ac.uk <cl349@labyrinth.cl.cam.ac.uk> | 2004-09-06 19:07:17 +0000 |
---|---|---|
committer | cl349@labyrinth.cl.cam.ac.uk <cl349@labyrinth.cl.cam.ac.uk> | 2004-09-06 19:07:17 +0000 |
commit | 31ae3c19a87731b8cc5831a800025ccb9594a85c (patch) | |
tree | 3b6d8c6d0dcae42bd59acbc196527c6880ceff7d /netbsd-2.0-xen-sparse | |
parent | 3ebb973d5045b339b449ecd3cd06cde2b00cafee (diff) | |
download | xen-31ae3c19a87731b8cc5831a800025ccb9594a85c.tar.gz xen-31ae3c19a87731b8cc5831a800025ccb9594a85c.tar.bz2 xen-31ae3c19a87731b8cc5831a800025ccb9594a85c.zip |
bitkeeper revision 1.1159.72.3 (413cb565kAu26gtMpvumani1Zx6Vjw)
Add new files in NetBSD for Xen2.0.
Diffstat (limited to 'netbsd-2.0-xen-sparse')
-rw-r--r-- | netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h | 138 | ||||
-rw-r--r-- | netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h | 53 | ||||
-rw-r--r-- | netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c | 573 | ||||
-rw-r--r-- | netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c | 347 |
4 files changed, 1111 insertions, 0 deletions
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h b/netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h new file mode 100644 index 0000000000..6d6bfe172f --- /dev/null +++ b/netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h @@ -0,0 +1,138 @@ +/****************************************************************************** + * ctrl_if.h + * + * Management functions for special interface to the domain controller. + * + * Copyright (c) 2004, K A Fraser + */ + +#ifndef __ASM_XEN__CTRL_IF_H__ +#define __ASM_XEN__CTRL_IF_H__ + +typedef control_msg_t ctrl_msg_t; + +/* + * Callback function type. Called for asynchronous processing of received + * request messages, and responses to previously-transmitted request messages. + * The parameters are (@msg, @id). + * @msg: Original request/response message (not a copy). The message can be + * modified in-place by the handler (e.g., a response callback can + * turn a request message into a response message in place). The message + * is no longer accessible after the callback handler returns -- if the + * message is required to persist for longer then it must be copied. + * @id: (Response callbacks only) The 'id' that was specified when the + * original request message was queued for transmission. + */ +typedef void (*ctrl_msg_handler_t)(ctrl_msg_t *, unsigned long); + +/* + * Send @msg to the domain controller. Execute @hnd when a response is + * received, passing the response message and the specified @id. This + * operation will not block: it will return -EAGAIN if there is no space. + * Notes: + * 1. The @msg is copied if it is transmitted and so can be freed after this + * function returns. + * 2. If @hnd is NULL then no callback is executed. + */ +int +ctrl_if_send_message_noblock( + ctrl_msg_t *msg, + ctrl_msg_handler_t hnd, + unsigned long id); + +/* + * Send @msg to the domain controller. Execute @hnd when a response is + * received, passing the response message and the specified @id. This + * operation will block until the message is sent, or a signal is received + * for the calling process (unless @wait_state is TASK_UNINTERRUPTIBLE). + * Notes: + * 1. The @msg is copied if it is transmitted and so can be freed after this + * function returns. + * 2. If @hnd is NULL then no callback is executed. + */ +int +ctrl_if_send_message_block( + ctrl_msg_t *msg, + ctrl_msg_handler_t hnd, + unsigned long id, + long wait_state); + +/* + * Send @msg to the domain controller. Block until the response is received, + * and then copy it into the provided buffer, @rmsg. + */ +int +ctrl_if_send_message_and_get_response( + ctrl_msg_t *msg, + ctrl_msg_t *rmsg, + long wait_state); + +#ifdef notyet +/* + * Request a callback when there is /possibly/ space to immediately send a + * message to the domain controller. This function returns 0 if there is + * already space to trasnmit a message --- in this case the callback task /may/ + * still be executed. If this function returns 1 then the callback /will/ be + * executed when space becomes available. + */ +int +ctrl_if_enqueue_space_callback( + struct tq_struct *task); +#endif + +/* + * Send a response (@msg) to a message from the domain controller. This will + * never block. + * Notes: + * 1. The @msg is copied and so can be freed after this function returns. + * 2. The @msg may be the original request message, modified in-place. + */ +void +ctrl_if_send_response( + ctrl_msg_t *msg); + +/* + * Register a receiver for typed messages from the domain controller. The + * handler (@hnd) is called for every received message of specified @type. + * Returns TRUE (non-zero) if the handler was successfully registered. + * If CALLBACK_IN_BLOCKING CONTEXT is specified in @flags then callbacks will + * occur in a context in which it is safe to yield (i.e., process context). + */ +#define CALLBACK_IN_BLOCKING_CONTEXT 1 +int ctrl_if_register_receiver( + uint8_t type, + ctrl_msg_handler_t hnd, + unsigned int flags); + +/* + * Unregister a receiver for typed messages from the domain controller. The + * handler (@hnd) will not be executed after this function returns. + */ +void +ctrl_if_unregister_receiver( + uint8_t type, ctrl_msg_handler_t hnd); + +/* Suspend/resume notifications. */ +void ctrl_if_suspend(void); +void ctrl_if_resume(void); + +/* Start-of-day setup. */ +void ctrl_if_init(void); + +/* + * Returns TRUE if there are no outstanding message requests at the domain + * controller. This can be used to ensure that messages have really flushed + * through when it is not possible to use the response-callback interface. + * WARNING: If other subsystems are using the control interface then this + * function might never return TRUE! + */ +int ctrl_if_transmitter_empty(void); /* !! DANGEROUS FUNCTION !! */ + +/* + * Manually discard response messages from the domain controller. + * WARNING: This is usually done automatically -- this function should only + * be called when normal interrupt mechanisms are disabled! + */ +void ctrl_if_discard_responses(void); /* !! DANGEROUS FUNCTION !! */ + +#endif /* __ASM_XEN__CONTROL_IF_H__ */ diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h b/netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h new file mode 100644 index 0000000000..5dd98ef250 --- /dev/null +++ b/netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h @@ -0,0 +1,53 @@ +/* $NetBSD$ */ + +/* + * + * Copyright (c) 2004 Christian Limpach. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian Limpach. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _XEN_EVENTS_H_ +#define _XEN_EVENTS_H_ + +#define NR_IRQS 32 + +extern int evtchn_to_irq[]; + +/* typedef unsigned int (*ev_handler_t)(int, struct pt_regs *); */ +typedef int (*ev_handler_t)(void *); + +void events_default_setup(void); +void init_events(void); +unsigned int do_event(int, struct trapframe *); +int event_set_handler(int, ev_handler_t, void *, int); + +int bind_virq_to_irq(int); +void unbind_virq_from_irq(int); +int bind_evtchn_to_irq(int); + +#endif /* _XEN_EVENTS_H_ */ diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c new file mode 100644 index 0000000000..39b4febdd3 --- /dev/null +++ b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c @@ -0,0 +1,573 @@ +/****************************************************************************** + * ctrl_if.c + * + * Management functions for special interface to the domain controller. + * + * Copyright (c) 2004, K A Fraser + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/kthread.h> + +#include <machine/xen.h> +#include <machine/hypervisor.h> +#include <machine/ctrl_if.h> +#include <machine/evtchn.h> + +#if 0 +#define DPRINTK(_f, _a...) printf("(file=%s, line=%d) " _f, \ + __FILE__ , __LINE__ , ## _a ) +#else +#define DPRINTK(_f, _a...) ((void)0) +#endif + +/* + * Only used by initial domain which must create its own control-interface + * event channel. This value is picked up by the user-space domain controller + * via an ioctl. + */ +int initdom_ctrlif_domcontroller_port = -1; + +static int ctrl_if_evtchn; +static int ctrl_if_irq; +static struct simplelock ctrl_if_lock; + +static CONTROL_RING_IDX ctrl_if_tx_resp_cons; +static CONTROL_RING_IDX ctrl_if_rx_req_cons; + +/* Incoming message requests. */ + /* Primary message type -> message handler. */ +static ctrl_msg_handler_t ctrl_if_rxmsg_handler[256]; + /* Primary message type -> callback in process context? */ +static unsigned long ctrl_if_rxmsg_blocking_context[256/sizeof(unsigned long)]; +#if 0 + /* Is it late enough during bootstrap to use schedule_task()? */ +static int safe_to_schedule_task; +#endif + /* Queue up messages to be handled in process context. */ +static ctrl_msg_t ctrl_if_rxmsg_deferred[CONTROL_RING_SIZE]; +static CONTROL_RING_IDX ctrl_if_rxmsg_deferred_prod; +static CONTROL_RING_IDX ctrl_if_rxmsg_deferred_cons; + +/* Incoming message responses: message identifier -> message handler/id. */ +static struct { + ctrl_msg_handler_t fn; + unsigned long id; +} ctrl_if_txmsg_id_mapping[CONTROL_RING_SIZE]; + +/* For received messages that must be deferred to process context. */ +static void __ctrl_if_rxmsg_deferred(void *unused); + +#ifdef notyet +/* Deferred callbacks for people waiting for space in the transmit ring. */ +static int DECLARE_TASK_QUEUE(ctrl_if_tx_tq); +#endif + +static void *ctrl_if_softintr = NULL; + +static int ctrl_if_tx_wait; +static void __ctrl_if_tx_tasklet(unsigned long data); + +static void __ctrl_if_rx_tasklet(unsigned long data); + +static void ctrl_if_kthread(void *); + +#define get_ctrl_if() ((control_if_t *)((char *)HYPERVISOR_shared_info + 2048)) +#define TX_FULL(_c) \ + (((_c)->tx_req_prod - ctrl_if_tx_resp_cons) == CONTROL_RING_SIZE) + +static void ctrl_if_notify_controller(void) +{ + hypervisor_notify_via_evtchn(ctrl_if_evtchn); +} + +static void ctrl_if_rxmsg_default_handler(ctrl_msg_t *msg, unsigned long id) +{ + msg->length = 0; + ctrl_if_send_response(msg); +} + +static void __ctrl_if_tx_tasklet(unsigned long data) +{ + control_if_t *ctrl_if = get_ctrl_if(); + ctrl_msg_t *msg; + int was_full = TX_FULL(ctrl_if); + CONTROL_RING_IDX rp; + + rp = ctrl_if->tx_resp_prod; + __insn_barrier(); /* Ensure we see all requests up to 'rp'. */ + + while ( ctrl_if_tx_resp_cons != rp ) + { + msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if_tx_resp_cons)]; + + DPRINTK("Rx-Rsp %u/%u :: %d/%d\n", + ctrl_if_tx_resp_cons, + ctrl_if->tx_resp_prod, + msg->type, msg->subtype); + + /* Execute the callback handler, if one was specified. */ + if ( msg->id != 0xFF ) + { + (*ctrl_if_txmsg_id_mapping[msg->id].fn)( + msg, ctrl_if_txmsg_id_mapping[msg->id].id); + __insn_barrier(); /* Execute, /then/ free. */ + ctrl_if_txmsg_id_mapping[msg->id].fn = NULL; + } + + /* + * Step over the message in the ring /after/ finishing reading it. As + * soon as the index is updated then the message may get blown away. + */ + __insn_barrier(); + ctrl_if_tx_resp_cons++; + } + + if ( was_full && !TX_FULL(ctrl_if) ) + { + wakeup(&ctrl_if_tx_wait); +#ifdef notyet + run_task_queue(&ctrl_if_tx_tq); +#endif + } +} + +static void __ctrl_if_rxmsg_deferred(void *unused) +{ + ctrl_msg_t *msg; + CONTROL_RING_IDX dp; + + dp = ctrl_if_rxmsg_deferred_prod; + __insn_barrier(); /* Ensure we see all deferred requests up to 'dp'. */ + + while ( ctrl_if_rxmsg_deferred_cons != dp ) + { + msg = &ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX( + ctrl_if_rxmsg_deferred_cons++)]; + (*ctrl_if_rxmsg_handler[msg->type])(msg, 0); + } +} + +static void __ctrl_if_rx_tasklet(unsigned long data) +{ + control_if_t *ctrl_if = get_ctrl_if(); + ctrl_msg_t msg, *pmsg; + CONTROL_RING_IDX rp, dp; + + dp = ctrl_if_rxmsg_deferred_prod; + rp = ctrl_if->rx_req_prod; + __insn_barrier(); /* Ensure we see all requests up to 'rp'. */ + + while ( ctrl_if_rx_req_cons != rp ) + { + pmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if_rx_req_cons++)]; + memcpy(&msg, pmsg, offsetof(ctrl_msg_t, msg)); + + DPRINTK("Rx-Req %u/%u :: %d/%d\n", + ctrl_if_rx_req_cons-1, + ctrl_if->rx_req_prod, + msg.type, msg.subtype); + + if ( msg.length != 0 ) + memcpy(msg.msg, pmsg->msg, msg.length); + + if ( x86_atomic_test_bit( + (unsigned long *)&ctrl_if_rxmsg_blocking_context, + msg.type) ) + memcpy(&ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX(dp++)], + &msg, offsetof(ctrl_msg_t, msg) + msg.length); + else + (*ctrl_if_rxmsg_handler[msg.type])(&msg, 0); + } + + if ( dp != ctrl_if_rxmsg_deferred_prod ) + { + __insn_barrier(); + ctrl_if_rxmsg_deferred_prod = dp; +#if 0 + wakeup(&ctrl_if_kthread); +#else + if (ctrl_if_softintr) + softintr_schedule(ctrl_if_softintr); +#endif + } +} + +static int ctrl_if_interrupt(void *arg) +{ + control_if_t *ctrl_if = get_ctrl_if(); + + if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod || + ctrl_if_rx_req_cons != ctrl_if->rx_req_prod ) { +#if 0 + wakeup(&ctrl_if_kthread); +#else + if (ctrl_if_softintr) + softintr_schedule(ctrl_if_softintr); +#endif + } + + return 0; +} + +int +ctrl_if_send_message_noblock( + ctrl_msg_t *msg, + ctrl_msg_handler_t hnd, + unsigned long id) +{ + control_if_t *ctrl_if = get_ctrl_if(); + unsigned long flags; + int i; + + save_and_cli(flags); + simple_lock(&ctrl_if_lock); + + if ( TX_FULL(ctrl_if) ) + { + simple_unlock(&ctrl_if_lock); + restore_flags(flags); + return -EAGAIN; + } + + msg->id = 0xFF; + if ( hnd != NULL ) + { + for ( i = 0; ctrl_if_txmsg_id_mapping[i].fn != NULL; i++ ) + continue; + ctrl_if_txmsg_id_mapping[i].fn = hnd; + ctrl_if_txmsg_id_mapping[i].id = id; + msg->id = i; + } + + DPRINTK("Tx-Req %u/%u :: %d/%d\n", + ctrl_if->tx_req_prod, + ctrl_if_tx_resp_cons, + msg->type, msg->subtype); + + memcpy(&ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if->tx_req_prod)], + msg, sizeof(*msg)); + __insn_barrier(); /* Write the message before letting the controller peek at it. */ + ctrl_if->tx_req_prod++; + + simple_unlock(&ctrl_if_lock); + restore_flags(flags); + + ctrl_if_notify_controller(); + + return 0; +} + +int +ctrl_if_send_message_block( + ctrl_msg_t *msg, + ctrl_msg_handler_t hnd, + unsigned long id, + long wait_state) +{ + int rc; + + while ((rc = ctrl_if_send_message_noblock(msg, hnd, id)) == EAGAIN) { + /* XXXcl possible race -> add a lock and ltsleep */ + rc = tsleep((caddr_t) &ctrl_if_tx_wait, PUSER | PCATCH, + "ctrl_if", 0); + if (rc) + break; + } + + return rc; +} + +/* Allow a reponse-callback handler to find context of a blocked requester. */ +struct rsp_wait { + ctrl_msg_t *msg; /* Buffer for the response message. */ + struct task_struct *task; /* The task that is blocked on the response. */ + int done; /* Indicate to 'task' that response is rcv'ed. */ +}; + +static void __ctrl_if_get_response(ctrl_msg_t *msg, unsigned long id) +{ + struct rsp_wait *wait = (struct rsp_wait *)id; + + memcpy(wait->msg, msg, sizeof(*msg)); + __insn_barrier(); + wait->done = 1; + + wakeup(wait); +} + +int +ctrl_if_send_message_and_get_response( + ctrl_msg_t *msg, + ctrl_msg_t *rmsg, + long wait_state) +{ + struct rsp_wait wait; + int rc; + + wait.msg = rmsg; + wait.done = 0; + + if ( (rc = ctrl_if_send_message_block(msg, __ctrl_if_get_response, + (unsigned long)&wait, + wait_state)) != 0 ) + return rc; + + for ( ; ; ) + { + if ( wait.done ) + break; + tsleep((caddr_t)&wait, PUSER | PCATCH, "ctrl_if", 0); + } + + return 0; +} + +#ifdef notyet +int +ctrl_if_enqueue_space_callback( + struct tq_struct *task) +{ + control_if_t *ctrl_if = get_ctrl_if(); + + /* Fast path. */ + if ( !TX_FULL(ctrl_if) ) + return 0; + + (void)queue_task(task, &ctrl_if_tx_tq); + + /* + * We may race execution of the task queue, so return re-checked status. If + * the task is not executed despite the ring being non-full then we will + * certainly return 'not full'. + */ + __insn_barrier(); + return TX_FULL(ctrl_if); +} +#endif + +void +ctrl_if_send_response( + ctrl_msg_t *msg) +{ + control_if_t *ctrl_if = get_ctrl_if(); + unsigned long flags; + ctrl_msg_t *dmsg; + + /* + * NB. The response may the original request message, modified in-place. + * In this situation we may have src==dst, so no copying is required. + */ + save_and_cli(flags); + simple_lock(&ctrl_if_lock); + + DPRINTK("Tx-Rsp %u :: %d/%d\n", + ctrl_if->rx_resp_prod, + msg->type, msg->subtype); + + dmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if->rx_resp_prod)]; + if ( dmsg != msg ) + memcpy(dmsg, msg, sizeof(*msg)); + + __insn_barrier(); /* Write the message before letting the controller peek at it. */ + ctrl_if->rx_resp_prod++; + + simple_unlock(&ctrl_if_lock); + restore_flags(flags); + + ctrl_if_notify_controller(); +} + +int +ctrl_if_register_receiver( + uint8_t type, + ctrl_msg_handler_t hnd, + unsigned int flags) +{ + unsigned long _flags; + int inuse; + + save_and_cli(_flags); + simple_lock(&ctrl_if_lock); + + inuse = (ctrl_if_rxmsg_handler[type] != ctrl_if_rxmsg_default_handler); + + if ( inuse ) + { + printf("Receiver %p already established for control " + "messages of type %d.\n", ctrl_if_rxmsg_handler[type], type); + } + else + { + ctrl_if_rxmsg_handler[type] = hnd; + x86_atomic_clear_bit((unsigned long *)&ctrl_if_rxmsg_blocking_context, type); + if ( flags == CALLBACK_IN_BLOCKING_CONTEXT ) + { + x86_atomic_set_bit((unsigned long *)&ctrl_if_rxmsg_blocking_context, type); +#if 0 + if ( !safe_to_schedule_task ) + BUG(); +#endif + } + } + + simple_unlock(&ctrl_if_lock); + restore_flags(_flags); + + return !inuse; +} + +void +ctrl_if_unregister_receiver( + uint8_t type, + ctrl_msg_handler_t hnd) +{ + unsigned long flags; + + save_and_cli(flags); + simple_lock(&ctrl_if_lock); + + if ( ctrl_if_rxmsg_handler[type] != hnd ) + printf("Receiver %p is not registered for control " + "messages of type %d.\n", hnd, type); + else + ctrl_if_rxmsg_handler[type] = ctrl_if_rxmsg_default_handler; + + simple_unlock(&ctrl_if_lock); + restore_flags(flags); + + /* Ensure that @hnd will not be executed after this function returns. */ +#if 0 + wakeup(&ctrl_if_kthread); +#else + if (ctrl_if_softintr) + softintr_schedule(ctrl_if_softintr); +#endif +} + +static void +ctrl_if_kthread(void *arg) +{ + control_if_t *ctrl_if = get_ctrl_if(); + + // printf("ctrl_if_kthread starting\n"); + for (;;) { + if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod ) + __ctrl_if_tx_tasklet(0); + + if ( ctrl_if_rx_req_cons != ctrl_if->rx_req_prod ) + __ctrl_if_rx_tasklet(0); + + if ( ctrl_if_rxmsg_deferred_cons != + ctrl_if_rxmsg_deferred_prod ) + __ctrl_if_rxmsg_deferred(NULL); + + if (arg) { + // printf("ctrl_if_kthread one-shot done\n"); + return; + } + + tsleep((caddr_t)&ctrl_if_kthread, PUSER | PCATCH, + "ctrl_if", 0); + } +} + +static void +ctrl_if_create_kthread(void *arg) +{ + + printf("ctrl_if_kthread creating\n"); + if (kthread_create1(ctrl_if_kthread, arg, NULL, "ctrl_if")) + printf("ctrl_if_kthread create failed\n"); + softintr_schedule(ctrl_if_softintr); +} + +#ifdef notyet +void ctrl_if_suspend(void) +{ + free_irq(ctrl_if_irq, NULL); + unbind_evtchn_from_irq(ctrl_if_evtchn); +} +#endif + +void ctrl_if_resume(void) +{ + control_if_t *ctrl_if = get_ctrl_if(); + + if ( xen_start_info.flags & SIF_INITDOMAIN ) + { + /* + * The initial domain must create its own domain-controller link. + * The controller is probably not running at this point, but will + * pick up its end of the event channel from + */ + evtchn_op_t op; + op.cmd = EVTCHNOP_bind_interdomain; + op.u.bind_interdomain.dom1 = DOMID_SELF; + op.u.bind_interdomain.dom2 = DOMID_SELF; + if ( HYPERVISOR_event_channel_op(&op) != 0 ) + panic("EVTCHNOP_bind_interdomain"); + xen_start_info.domain_controller_evtchn = op.u.bind_interdomain.port1; + initdom_ctrlif_domcontroller_port = op.u.bind_interdomain.port2; + } + + /* Sync up with shared indexes. */ + ctrl_if_tx_resp_cons = ctrl_if->tx_resp_prod; + ctrl_if_rx_req_cons = ctrl_if->rx_resp_prod; + + ctrl_if_evtchn = xen_start_info.domain_controller_evtchn; + ctrl_if_irq = bind_evtchn_to_irq(ctrl_if_evtchn); + + event_set_handler(ctrl_if_irq, &ctrl_if_interrupt, NULL, IPL_HIGH); + hypervisor_enable_irq(ctrl_if_irq); +} + +void ctrl_if_init(void) +{ + int i; + + for ( i = 0; i < 256; i++ ) + ctrl_if_rxmsg_handler[i] = ctrl_if_rxmsg_default_handler; + + simple_lock_init(&ctrl_if_lock); + + if (0) kthread_create(ctrl_if_create_kthread, NULL); + ctrl_if_softintr = + softintr_establish(IPL_SOFTNET, ctrl_if_kthread, (void *)1); + + ctrl_if_resume(); +} + + +#if 0 +/* This is called after it is safe to call schedule_task(). */ +static int __init ctrl_if_late_setup(void) +{ + safe_to_schedule_task = 1; + return 0; +} +__initcall(ctrl_if_late_setup); +#endif + + +/* + * !! The following are DANGEROUS FUNCTIONS !! + * Use with care [for example, see xencons_force_flush()]. + */ + +int ctrl_if_transmitter_empty(void) +{ + return (get_ctrl_if()->tx_req_prod == ctrl_if_tx_resp_cons); +} + +void ctrl_if_discard_responses(void) +{ + ctrl_if_tx_resp_cons = get_ctrl_if()->tx_resp_prod; +} + diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c new file mode 100644 index 0000000000..ca3f7c99f6 --- /dev/null +++ b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c @@ -0,0 +1,347 @@ +/* $NetBSD$ */ + +/* + * + * Copyright (c) 2004 Christian Limpach. + * Copyright (c) 2004, K A Fraser. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian Limpach. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/reboot.h> + +#include <uvm/uvm.h> + +#include <machine/intrdefs.h> + +#include <machine/xen.h> +#include <machine/hypervisor.h> +#include <machine/evtchn.h> +#include <machine/ctrl_if.h> +#include <machine/xenfunc.h> + +struct pic xenev_pic = { + .pic_dev = { + .dv_xname = "xen_fakepic", + }, + .pic_type = PIC_XEN, + .pic_lock = __SIMPLELOCK_UNLOCKED, +}; + +/* + * This lock protects updates to the following mapping and reference-count + * arrays. The lock does not need to be acquired to read the mapping tables. + */ +static struct simplelock irq_mapping_update_lock = SIMPLELOCK_INITIALIZER; + +/* IRQ <-> event-channel mappings. */ +int evtchn_to_irq[NR_EVENT_CHANNELS]; +int irq_to_evtchn[NR_IRQS]; + +/* IRQ <-> VIRQ mapping. */ +static int virq_to_irq[NR_VIRQS]; + +/* Reference counts for bindings to IRQs. */ +static int irq_bindcount[NR_IRQS]; + +#if 0 +static int xen_die_handler(void *); +#endif +static int xen_debug_handler(void *); +static int xen_misdirect_handler(void *); + +void +events_default_setup() +{ + int i; + + /* No VIRQ -> IRQ mappings. */ + for (i = 0; i < NR_VIRQS; i++) + virq_to_irq[i] = -1; + + /* No event-channel -> IRQ mappings. */ + for (i = 0; i < NR_EVENT_CHANNELS; i++) { + evtchn_to_irq[i] = -1; + hypervisor_mask_event(i); /* No event channels are 'live' right now. */ + } + + /* No IRQ -> event-channel mappings. */ + for (i = 0; i < NR_IRQS; i++) + irq_to_evtchn[i] = -1; +} + +void +init_events() +{ + int irq; + + irq = bind_virq_to_irq(VIRQ_DEBUG); + event_set_handler(irq, &xen_debug_handler, NULL, IPL_DEBUG); + hypervisor_enable_irq(irq); + + irq = bind_virq_to_irq(VIRQ_MISDIRECT); + event_set_handler(irq, &xen_misdirect_handler, NULL, IPL_DIE); + hypervisor_enable_irq(irq); + + /* This needs to be done early, but after the IRQ subsystem is + * alive. */ + ctrl_if_init(); + + enable_intr(); /* at long last... */ +} + +unsigned int +do_event(int irq, struct trapframe *regs) +{ + struct cpu_info *ci; + + if (irq >= NR_IRQS) { +#ifdef DIAGNOSTIC + printf("event irq number %d > NR_IRQS\n", irq); +#endif + return ENOENT; + } + + if (0 && irq == 4) { + ci = &cpu_info_primary; + printf("do_event %d/%d called, ilevel %d\n", irq, + irq_to_evtchn[irq], ci->ci_ilevel); + } + + ci = &cpu_info_primary; + + hypervisor_acknowledge_irq(irq); + if (ci->ci_isources[irq] == NULL) { + return 0; + } + __asm__ __volatile__ ( + " movl $1f,%%esi ;" + " jmp *%%eax ;" + "1: " + : : "a" (ci->ci_isources[irq]->is_recurse), + "b" (ci->ci_ilevel) + : "esi", "ecx", "edx", "memory"); + + if (0 && irq == 4) + printf("do_event %d done, ipending %08x\n", irq, + ci->ci_ipending); + + return 0; +} + +static int +find_unbound_irq(void) +{ + int irq; + + for (irq = 0; irq < NR_IRQS; irq++) + if (irq_bindcount[irq] == 0) + break; + + if (irq == NR_IRQS) + panic("No available IRQ to bind to: increase NR_IRQS!\n"); + + return irq; +} + +int +bind_virq_to_irq(int virq) +{ + evtchn_op_t op; + int evtchn, irq; + + simple_lock(&irq_mapping_update_lock); + + irq = virq_to_irq[virq]; + if (irq == -1) { + op.cmd = EVTCHNOP_bind_virq; + op.u.bind_virq.virq = virq; + if (HYPERVISOR_event_channel_op(&op) != 0) + panic("Failed to bind virtual IRQ %d\n", virq); + evtchn = op.u.bind_virq.port; + + irq = find_unbound_irq(); + evtchn_to_irq[evtchn] = irq; + irq_to_evtchn[irq] = evtchn; + + virq_to_irq[virq] = irq; + } + + irq_bindcount[irq]++; + + simple_unlock(&irq_mapping_update_lock); + + return irq; +} + +void +unbind_virq_from_irq(int virq) +{ + evtchn_op_t op; + int irq = virq_to_irq[virq]; + int evtchn = irq_to_evtchn[irq]; + + simple_lock(&irq_mapping_update_lock); + + irq_bindcount[irq]--; + if (irq_bindcount[irq] == 0) { + op.cmd = EVTCHNOP_close; + op.u.close.dom = DOMID_SELF; + op.u.close.port = evtchn; + if (HYPERVISOR_event_channel_op(&op) != 0) + panic("Failed to unbind virtual IRQ %d\n", virq); + + evtchn_to_irq[evtchn] = -1; + irq_to_evtchn[irq] = -1; + virq_to_irq[virq] = -1; + } + + simple_unlock(&irq_mapping_update_lock); +} + +int bind_evtchn_to_irq(int evtchn) +{ + int irq; + + simple_lock(&irq_mapping_update_lock); + + irq = evtchn_to_irq[evtchn]; + if (irq == -1) { + irq = find_unbound_irq(); + evtchn_to_irq[evtchn] = irq; + irq_to_evtchn[irq] = evtchn; + } + + irq_bindcount[irq]++; + + simple_unlock(&irq_mapping_update_lock); + + return irq; +} + +int +event_set_handler(int irq, ev_handler_t handler, void *arg, int level) +{ + struct intrsource *isp; + struct intrhand *ih; + struct cpu_info *ci; + + if (irq >= NR_IRQS) { +#ifdef DIAGNOSTIC + printf("irq number %d > NR_IRQS\n", irq); +#endif + return ENOENT; + } + +#if 0 + printf("event_set_handler irq %d/%d handler %p level %d\n", irq, + irq_to_evtchn[irq], handler, level); +#endif + /* XXXcl handle already bound irq */ + + MALLOC(isp, struct intrsource *, sizeof (struct intrsource), M_DEVBUF, + M_WAITOK|M_ZERO); + if (isp == NULL) + panic("can't allocate fixed interrupt source"); + MALLOC(ih, struct intrhand *, sizeof (struct intrhand), M_DEVBUF, + M_WAITOK|M_ZERO); + if (ih == NULL) + panic("can't allocate fixed interrupt source"); + + ci = &cpu_info_primary; + + isp->is_recurse = xenev_stubs[irq].ist_recurse; + isp->is_resume = xenev_stubs[irq].ist_resume; + ih->ih_level = level; + ih->ih_fun = handler; + ih->ih_arg = arg; + ih->ih_next = NULL; + isp->is_handlers = ih; + isp->is_pic = &xenev_pic; + ci->ci_isources[irq] = isp; + evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL, + ci->ci_dev->dv_xname, "xenev"); + + intr_calculatemasks(ci); + + return 0; +} + +void hypervisor_enable_irq(unsigned int irq) +{ + + hypervisor_unmask_event(irq_to_evtchn[irq]); +} + +void hypervisor_disable_irq(unsigned int irq) +{ + + hypervisor_mask_event(irq_to_evtchn[irq]); +} + +void hypervisor_acknowledge_irq(unsigned int irq) +{ + + hypervisor_mask_event(irq_to_evtchn[irq]); + hypervisor_clear_event(irq_to_evtchn[irq]); +} + +#if 0 +static int +xen_die_handler(void *arg) +{ + printf("hypervisor: DIE event received...\n"); + cpu_reboot(0, NULL); + /* NOTREACHED */ + return 0; +} +#endif + +static int +xen_debug_handler(void *arg) +{ + printf("debug event\n"); + return 0; +} + +static int +xen_misdirect_handler(void *arg) +{ +#if 0 + char *msg = "misdirect\n"; + (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg); +#endif + return 0; +} |