[PATCH] usbmon in 2.6.13: peeking into DMA areas
This code looks at urb->transfer_dma, maps the page and takes the data. I am looking for volunteers to contribute architectures other than i386 or to develop an architecure-neutral API for it (or point me that it was done already). Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
d0384200f6
Коммит
0256839619
|
@ -2,7 +2,7 @@
|
||||||
# Makefile for USB Core files and filesystem
|
# Makefile for USB Core files and filesystem
|
||||||
#
|
#
|
||||||
|
|
||||||
usbmon-objs := mon_main.o mon_stat.o mon_text.o
|
usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_dma.o
|
||||||
|
|
||||||
# This does not use CONFIG_USB_MON because we want this to use a tristate.
|
# This does not use CONFIG_USB_MON because we want this to use a tristate.
|
||||||
obj-$(CONFIG_USB) += usbmon.o
|
obj-$(CONFIG_USB) += usbmon.o
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* The USB Monitor, inspired by Dave Harding's USBMon.
|
||||||
|
*
|
||||||
|
* mon_dma.c: Library which snoops on DMA areas.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com)
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
#include <asm/page.h>
|
||||||
|
|
||||||
|
#include <linux/usb.h> /* Only needed for declarations in usb_mon.h */
|
||||||
|
#include "usb_mon.h"
|
||||||
|
|
||||||
|
#ifdef __i386__ /* CONFIG_ARCH_I386 does not exit */
|
||||||
|
#define MON_HAS_UNMAP 1
|
||||||
|
|
||||||
|
#define phys_to_page(phys) pfn_to_page((phys) >> PAGE_SHIFT)
|
||||||
|
|
||||||
|
char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
|
||||||
|
{
|
||||||
|
struct page *pg;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned char *map;
|
||||||
|
unsigned char *ptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On i386, a DMA handle is the "physical" address of a page.
|
||||||
|
* In other words, the bus address is equal to physical address.
|
||||||
|
* There is no IOMMU.
|
||||||
|
*/
|
||||||
|
pg = phys_to_page(dma_addr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are called from hardware IRQs in case of callbacks.
|
||||||
|
* But we can be called from softirq or process context in case
|
||||||
|
* of submissions. In such case, we need to protect KM_IRQ0.
|
||||||
|
*/
|
||||||
|
local_irq_save(flags);
|
||||||
|
map = kmap_atomic(pg, KM_IRQ0);
|
||||||
|
ptr = map + (dma_addr & (PAGE_SIZE-1));
|
||||||
|
memcpy(dst, ptr, len);
|
||||||
|
kunmap_atomic(map, KM_IRQ0);
|
||||||
|
local_irq_restore(flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* __i386__ */
|
||||||
|
|
||||||
|
#ifndef MON_HAS_UNMAP
|
||||||
|
char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
|
||||||
|
{
|
||||||
|
return 'D';
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -91,25 +91,11 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
|
||||||
int len, char ev_type)
|
int len, char ev_type)
|
||||||
{
|
{
|
||||||
int pipe = urb->pipe;
|
int pipe = urb->pipe;
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The check to see if it's safe to poke at data has an enormous
|
|
||||||
* number of corner cases, but it seems that the following is
|
|
||||||
* more or less safe.
|
|
||||||
*
|
|
||||||
* We do not even try to look transfer_buffer, because it can
|
|
||||||
* contain non-NULL garbage in case the upper level promised to
|
|
||||||
* set DMA for the HCD.
|
|
||||||
*/
|
|
||||||
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
|
||||||
return 'D';
|
|
||||||
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return 'L';
|
return 'L';
|
||||||
|
if (len >= DATA_MAX)
|
||||||
if ((data = urb->transfer_buffer) == NULL)
|
len = DATA_MAX;
|
||||||
return 'Z'; /* '0' would be not as pretty. */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bulk is easy to shortcut reliably.
|
* Bulk is easy to shortcut reliably.
|
||||||
|
@ -126,8 +112,21 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len >= DATA_MAX)
|
/*
|
||||||
len = DATA_MAX;
|
* The check to see if it's safe to poke at data has an enormous
|
||||||
|
* number of corner cases, but it seems that the following is
|
||||||
|
* more or less safe.
|
||||||
|
*
|
||||||
|
* We do not even try to look transfer_buffer, because it can
|
||||||
|
* contain non-NULL garbage in case the upper level promised to
|
||||||
|
* set DMA for the HCD.
|
||||||
|
*/
|
||||||
|
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
||||||
|
return mon_dmapeek(ep->data, urb->transfer_dma, len);
|
||||||
|
|
||||||
|
if (urb->transfer_buffer == NULL)
|
||||||
|
return 'Z'; /* '0' would be not as pretty. */
|
||||||
|
|
||||||
memcpy(ep->data, urb->transfer_buffer, len);
|
memcpy(ep->data, urb->transfer_buffer, len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,10 @@ struct mon_reader {
|
||||||
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
|
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
|
||||||
void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
|
void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
|
||||||
|
|
||||||
extern struct semaphore mon_lock;
|
extern struct semaphore mon_lock;
|
||||||
|
|
||||||
extern struct file_operations mon_fops_text;
|
extern struct file_operations mon_fops_text;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче