Skip to content

Commit ba321d2

Browse files
committed
naive /dev/mem mmap() experiment
1 parent f4a76b4 commit ba321d2

File tree

4 files changed

+177
-0
lines changed

4 files changed

+177
-0
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*~
2+
*.o
3+
*.ko
4+
*.cmd
5+
*.order
6+
*.mod.c
7+
*.symvers
8+
.tmp_versions

hello.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <linux/init.h> // Macros used to mark up functions e.g., __init __exit
1313
#include <linux/module.h> // Core header for loading LKMs into the kernel
1414
#include <linux/kernel.h> // Contains types, macros, functions for the kernel
15+
#include <linux/page-flags.h>
16+
#include <asm/cacheflush.h>
1517

1618
MODULE_LICENSE("GPL"); ///< The license type -- this affects runtime behavior
1719
MODULE_AUTHOR("Derek Molloy"); ///< The author -- visible when you use modinfo
@@ -22,6 +24,63 @@ static char *name = "world"; ///< An example LKM argument -- default valu
2224
module_param(name, charp, S_IRUGO); ///< Param desc. charp = char ptr, S_IRUGO can be read/not changed
2325
MODULE_PARM_DESC(name, "The name to display in /var/log/kern.log"); ///< parameter description
2426

27+
#if 0
28+
// x86 only ?
29+
#define alloc_gatt_pages(order) \
30+
((char *)__get_free_pages(GFP_KERNEL, (order)))
31+
#define free_gatt_pages(table, order) \
32+
free_pages((unsigned long)(table), (order))
33+
#endif
34+
35+
// use vmalloc()
36+
37+
static int page_order = 10; // we allocate (1<<page_order) pages
38+
static char *table = 0;
39+
40+
static void
41+
hello_alloc_pages(void)
42+
{
43+
struct page *page;
44+
char *table_end;
45+
46+
table = (char*) __get_free_pages(GFP_KERNEL, page_order);
47+
if (!table) { printk(KERN_WARNING "Could not allocate pages\n"); return; }
48+
49+
printk(KERN_WARNING "sizeof(phys_addr_t): %i\n", sizeof(phys_addr_t));
50+
if (sizeof(phys_addr_t) == 8)
51+
printk(KERN_WARNING "Allocated %li bytes (%i pages) at 0x%llx\n",
52+
(1 << page_order) * PAGE_SIZE, 1 << page_order, virt_to_phys(table));
53+
54+
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
55+
56+
for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
57+
SetPageReserved(page);
58+
59+
*((int*)table) = 0xdeadbeaf;
60+
61+
if (set_memory_uc((unsigned long)table, 1 << page_order))
62+
printk(KERN_WARNING "Could not set pages to UC!\n");
63+
else
64+
printk(KERN_WARNING "Success !\n");
65+
}
66+
67+
static void
68+
hello_free_pages(void)
69+
{
70+
char *table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
71+
struct page *page;
72+
73+
printk(KERN_WARNING "Freeing pages\n");
74+
75+
set_memory_wb((unsigned long)table, 1 << page_order);
76+
77+
for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
78+
ClearPageReserved(page);
79+
80+
free_pages((unsigned long)(table), (page_order));
81+
}
82+
83+
2584
/** @brief The LKM initialization function
2685
* The static keyword restricts the visibility of the function to within this C file. The __init
2786
* macro means that for a built-in driver (not a LKM) the function is only used at initialization
@@ -30,6 +89,7 @@ MODULE_PARM_DESC(name, "The name to display in /var/log/kern.log"); ///< parame
3089
*/
3190
static int __init helloBBB_init(void){
3291
printk(KERN_INFO "EBB: Hello %s from the BBB LKM!\n", name);
92+
hello_alloc_pages();
3393
return 0;
3494
}
3595

@@ -38,6 +98,8 @@ static int __init helloBBB_init(void){
3898
* code is used for a built-in driver (not a LKM) that this function is not required.
3999
*/
40100
static void __exit helloBBB_exit(void){
101+
if (table)
102+
hello_free_pages();
41103
printk(KERN_INFO "EBB: Goodbye %s from the BBB LKM!\n", name);
42104
}
43105

test/Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
CC=gcc
3+
#CFLAGS=-Wall -ggdb3 -std=gnu99 -O3
4+
CFLAGS=-Wall -ggdb3 -std=gnu99
5+
6+
all: test
7+
8+
clean:
9+
-@ rm test *~ >/dev/null 2>&1
10+

test/test.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
#include <sys/types.h>
4+
#include <sys/stat.h>
5+
#include <fcntl.h>
6+
#include <sys/mman.h>
7+
#include <sys/time.h>
8+
#include <string.h>
9+
#include <assert.h>
10+
11+
12+
void usage(int ac, char **av)
13+
{
14+
printf("usage: %s cached addr\n", av[0]);
15+
printf(" %s uncached addr\n", av[0]);
16+
exit(1);
17+
}
18+
19+
void die(char *msg)
20+
{
21+
printf("%s\n", msg);
22+
exit(1);
23+
}
24+
25+
/* Returns the current time. */
26+
double time_now(void)
27+
{
28+
#if _POSIX_TIMERS > 0
29+
struct timespec now;
30+
clock_gettime(CLOCK_REALTIME, &now);
31+
return now.tv_sec + now.tv_nsec/1000000000.0;
32+
#else
33+
struct timeval now;
34+
gettimeofday(&now, NULL);
35+
return now.tv_sec + now.tv_usec/1000000.0;
36+
#endif
37+
}
38+
39+
void *get_uncached_mem(void *base_addr, int size)
40+
{
41+
int fd = open("/dev/mem", O_RDWR | O_SYNC, 0);
42+
if (fd == -1) die("couldn't open /dev/mem, are you root ?");
43+
44+
printf("mmap()'ing %p\n", base_addr);
45+
46+
void *map = mmap(0, size, PROT_READ /*| PROT_WRITE*/, MAP_FILE | MAP_SHARED, fd, (off_t)base_addr);
47+
if (map == MAP_FAILED)
48+
die("mmap failed. Note: we need a kernel without CONFIG_STRICT_DEVMEM.");
49+
return map;
50+
}
51+
52+
int main(int ac, char **av)
53+
{
54+
int size = 1024 * 4096; // FIXME
55+
56+
if (ac != 3)
57+
usage(ac, av);
58+
59+
int uncached_mem_test;
60+
if (!strcmp(av[1], "uncached")) uncached_mem_test = 1;
61+
else if (!strcmp(av[1], "cached")) uncached_mem_test = 0;
62+
else usage(ac, av);
63+
64+
void *base_addr = (void*)strtoul(av[2], NULL, 16);
65+
66+
void *map;
67+
if (uncached_mem_test)
68+
map = get_uncached_mem(base_addr, size);
69+
else
70+
map = malloc(size); /* test normal memory */
71+
72+
unsigned int *pt = ((unsigned int*)map);
73+
/* uncached mem should start with 0xdeadbeaf */
74+
printf("read %#0x\n", *pt);
75+
if (uncached_mem_test) assert(*pt == 0xdeadbeaf);
76+
//printf("sizeof(off_t): %i\n", sizeof(off_t));
77+
78+
/*********************************************************************/
79+
/* benchmark reads */
80+
81+
double time_start = time_now();
82+
83+
int tsize = size / sizeof(int);
84+
//int t[tsize];
85+
#define STEP 10
86+
unsigned int sum = 0;
87+
int reads = 0;
88+
for (int i = 0; i < tsize - STEP; i++)
89+
for (int j = 0; j < STEP; j++) {
90+
sum += pt[i+j];
91+
reads++;
92+
}
93+
94+
printf("%s mem test: %i reads in %.2fs (sum: %i)\n",
95+
(uncached_mem_test ? "uncached" : "cached"),
96+
reads, time_now() - time_start, sum);
97+
}

0 commit comments

Comments
 (0)