*/
#include <linux/list.h>
+#include <linux/rculist.h>
#include <linux/spinlock.h>
#include <linux/hash.h>
#include <linux/init.h>
#include <linux/percpu.h>
#include <linux/kdebug.h>
#include <linux/mutex.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
#include <asm/debugreg.h>
#include <linux/mmiotrace.h>
return NULL;
}
-static void set_page_present(unsigned long addr, bool present, int *pglevel)
+static void set_page_present(unsigned long addr, bool present,
+ unsigned int *pglevel)
{
pteval_t pteval;
pmdval_t pmdval;
- int level;
+ unsigned int level;
pmd_t *pmd;
pte_t *pte = lookup_address(addr, &level);
}
/** Mark the given page as not present. Access to it will trigger a fault. */
-static void arm_kmmio_fault_page(unsigned long page, int *page_level)
+static void arm_kmmio_fault_page(unsigned long page, unsigned int *pglevel)
{
- set_page_present(page & PAGE_MASK, false, page_level);
+ set_page_present(page & PAGE_MASK, false, pglevel);
}
/** Mark the given page as present. */
-static void disarm_kmmio_fault_page(unsigned long page, int *page_level)
+static void disarm_kmmio_fault_page(unsigned long page, unsigned int *pglevel)
{
- set_page_present(page & PAGE_MASK, true, page_level);
+ set_page_present(page & PAGE_MASK, true, pglevel);
}
/*
}
}
+/*
+ * With page-unaligned ioremaps, one or two armed pages may contain
+ * addresses from outside the intended mapping. Events for these addresses
+ * are currently silently dropped. The events may result only from programming
+ * mistakes by accessing addresses before the beginning or past the end of a
+ * mapping.
+ */
int register_kmmio_probe(struct kmmio_probe *p)
{
unsigned long flags;
int ret = 0;
unsigned long size = 0;
+ const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
spin_lock_irqsave(&kmmio_lock, flags);
if (get_kmmio_probe(p->addr)) {
}
kmmio_count++;
list_add_rcu(&p->list, &kmmio_probes);
- while (size < p->len) {
+ while (size < size_lim) {
if (add_kmmio_fault_page(p->addr + size))
pr_err("kmmio: Unable to set page fault.\n");
size += PAGE_SIZE;
{
unsigned long flags;
unsigned long size = 0;
+ const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
struct kmmio_fault_page *release_list = NULL;
struct kmmio_delayed_release *drelease;
spin_lock_irqsave(&kmmio_lock, flags);
- while (size < p->len) {
+ while (size < size_lim) {
release_kmmio_fault_page(p->addr + size, &release_list);
size += PAGE_SIZE;
}