diff options
Diffstat (limited to 'tools/debugger/pdb/linux-2.6-module/module.c')
-rw-r--r-- | tools/debugger/pdb/linux-2.6-module/module.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/tools/debugger/pdb/linux-2.6-module/module.c b/tools/debugger/pdb/linux-2.6-module/module.c new file mode 100644 index 0000000000..25273d321f --- /dev/null +++ b/tools/debugger/pdb/linux-2.6-module/module.c @@ -0,0 +1,226 @@ + +/* + * module.c + * + * Handles initial registration with pdb when the pdb module starts up + * and cleanup when the module goes away (sortof :) + * Also receives each request from pdb in domain 0 and dispatches to the + * appropriate debugger function. + */ + +#include <linux/module.h> +#include <linux/interrupt.h> + +#include <asm-xen/evtchn.h> +#include <asm-xen/ctrl_if.h> +#include <asm-xen/hypervisor.h> +#include <asm-xen/xen-public/io/domain_controller.h> +#include <asm-xen/xen-public/xen.h> + +#include <asm-xen/xen-public/io/ring.h> + +#include "pdb_module.h" + +#define PDB_RING_SIZE __RING_SIZE((pdb_sring_t *)0, PAGE_SIZE) + +static pdb_back_ring_t pdb_ring; +static unsigned int pdb_evtchn; +static unsigned int pdb_irq; + +/* + * send response to a pdb request + */ +static void +pdb_send_response (pdb_response_t *response) +{ + pdb_response_t *resp; + + resp = RING_GET_RESPONSE(&pdb_ring, pdb_ring.rsp_prod_pvt); + + memcpy(resp, response, sizeof(pdb_response_t)); + + wmb(); /* Ensure other side can see the response fields. */ + pdb_ring.rsp_prod_pvt++; + RING_PUSH_RESPONSES(&pdb_ring); + notify_via_evtchn(pdb_evtchn); + return; +} + +/* + * handle a debug command from the front end + */ +static void +pdb_process_request (pdb_request_t *request) +{ + pdb_response_t resp; + + switch (request->operation) + { + case PDB_OPCODE_ATTACH : + pdb_attach(request->process); + resp.status = PDB_RESPONSE_OKAY; + break; + case PDB_OPCODE_DETACH : + pdb_detach(request->process); + resp.status = PDB_RESPONSE_OKAY; + break; + case PDB_OPCODE_RD_REG : + pdb_read_register(request->process, &request->u.rd_reg, + (unsigned long *)&resp.value); + resp.status = PDB_RESPONSE_OKAY; + break; + case PDB_OPCODE_WR_REG : + pdb_write_register(request->process, &request->u.wr_reg); + resp.status = PDB_RESPONSE_OKAY; + break; + default: + printk("(pdb) unknown request operation %d\n", request->operation); + resp.status = PDB_RESPONSE_ERROR; + } + + resp.operation = request->operation; + + pdb_send_response (&resp); + return; +} + +/* + * receive a pdb request + */ +static irqreturn_t +pdb_interrupt (int irq, void *dev_id, struct pt_regs *ptregs) +{ + pdb_request_t *req; + RING_IDX i, rp; + + rp = pdb_ring.sring->req_prod; + rmb(); + + for ( i = pdb_ring.req_cons; + (i != rp) && !RING_REQUEST_CONS_OVERFLOW(&pdb_ring, i); + i++ ) + { + req = RING_GET_REQUEST(&pdb_ring, i); + pdb_process_request(req); + + } + pdb_ring.req_cons = i; + + return IRQ_HANDLED; +} + + +static void +pdb_send_connection_status(int status, memory_t ring) +{ + ctrl_msg_t cmsg = + { + .type = CMSG_DEBUG, + .subtype = CMSG_DEBUG_CONNECTION_STATUS, + .length = sizeof(pdb_connection_t), + }; + pdb_connection_t *conn = (pdb_connection_t *)cmsg.msg; + + conn->status = status; + conn->ring = ring; + conn->evtchn = 0; + + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); +} + + +/* + * this is called each time a message is received on the control channel + */ +static void +pdb_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) +{ +printk ("pdb ctrlif rx\n"); + + switch (msg->subtype) + { + case CMSG_DEBUG_CONNECTION_STATUS: + /* initialize event channel created by the pdb server */ + + pdb_evtchn = ((pdb_connection_p) msg->msg)->evtchn; + pdb_irq = bind_evtchn_to_irq(pdb_evtchn); + + if ( request_irq(pdb_irq, pdb_interrupt, + SA_SAMPLE_RANDOM, "pdb", NULL) ) + { + printk("(pdb) request irq failed: %d %d\n", pdb_evtchn, pdb_irq); + } + break; + + default: + printk ("(pdb) unknown xcs control message: %d\n", msg->subtype); + break; + } + + return; +} + +static int __init +pdb_initialize(void) +{ + pdb_sring_t *sring; + + printk("----\npdb initialize %s %s\n", __DATE__, __TIME__); + + /* + if ( xen_start_info.flags & SIF_INITDOMAIN ) + return 1; + */ + + (void)ctrl_if_register_receiver(CMSG_DEBUG, pdb_ctrlif_rx, + CALLBACK_IN_BLOCKING_CONTEXT); + + /* rings */ + sring = (pdb_sring_t *)__get_free_page(GFP_KERNEL); + SHARED_RING_INIT(sring); + BACK_RING_INIT(&pdb_ring, sring, PAGE_SIZE); + + /* notify pdb in dom 0 */ + pdb_send_connection_status(PDB_CONNECTION_STATUS_UP, + virt_to_machine(pdb_ring.sring) >> PAGE_SHIFT); + + return 0; +} + +static void __exit +pdb_terminate(void) +{ + printk("pdb cleanup\n"); + + (void)ctrl_if_unregister_receiver(CMSG_DEBUG, pdb_ctrlif_rx); + + if (pdb_irq) + { + free_irq(pdb_irq, NULL); + pdb_irq = 0; + } + + if (pdb_evtchn) + { + unbind_evtchn_from_irq(pdb_evtchn); + pdb_evtchn = 0; + } + + pdb_send_connection_status(PDB_CONNECTION_STATUS_DOWN, 0); +} + + +module_init(pdb_initialize); +module_exit(pdb_terminate); + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ + |