我正在尝试做一个简单的mmap驱动程序,涵盖了非常基础知识。更像一个简单的示例驱动程序。但我试图使用通过kzalloc分配的大块内存(102页四舍五入到100)。我不明白为什么我的mmap无法从用户空间访问页面。为什么我无法访问超过10-14页?我们的驱动程序是否必须手动处理页面错误?
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
//#include <asm-generic/io.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <asm/io.h>
//#define MEM_SIZE 409600
#define MEM_SIZE 4096
#define NPAGES 100
#ifndef VM_RESERVED
# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
#endif
static void *dmem;
static unsigned int *dmem_area;
static int in_use;
static int dmem_map(struct file *filp, struct vm_area_struct *vma)
{
long length = vma->vm_end - vma->vm_start;
if(length > NPAGES * PAGE_SIZE)
return -EIO;
printk("%s: mapping\n", __func__);
if(remap_pfn_range( vma,
vma->vm_start,
virt_to_phys((void *)dmem_area) >> PAGE_SHIFT,
length, vma->vm_page_prot) < 0)
{
printk("%s: Error remap failed\n", __func__);
return -EAGAIN;
}
printk("%s: mapping done\n", __func__);
return 0;
}
static int mmap_dev_open(struct inode *inod, struct file *file)
{
int i;
printk("%s: open\n", __func__);
if(in_use)
return -EBUSY;
in_use++;
dmem = kzalloc((size_t) ((NPAGES + 2) * PAGE_SIZE), GFP_KERNEL);
dmem_area = (int *)((((unsigned long)dmem) + PAGE_SIZE - 1) & PAGE_MASK);
printk("%s: PAGE_SIZE = %lu\n", __func__, PAGE_SIZE);
printk("%s: dmem = %lu\n", __func__, (unsigned long)(virt_to_page((unsigned long)dmem)));
for(i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
SetPageReserved(virt_to_page(((unsigned long)dmem_area) + i));
for(i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
printk("i= %d \t: Reserved: %lu dmem: 0x%x \n",
i,
(unsigned long)(virt_to_page(((unsigned long)dmem_area) + i)),
(unsigned int)((unsigned long) dmem_area));
printk("%s: Validating memory\n", __func__);
printk("%s: Count size = %lu\n", __func__, (NPAGES - 1)*PAGE_SIZE);
for(i=0;i < (NPAGES-1) * PAGE_SIZE; i++){
dmem_area[i] = i;
if ( (i%4096) == 0)
printk("%s: checking page : %d\n",__func__, i/4096);
}
printk("%s: Final value of i = %d\n", __func__, i);
dmem_area[0] = 0xFF00FF00;
return 0;
}
static int mmap_dev_release(struct inode *inod, struct file *file)
{
in_use = 0;
//free_page((unsigned long) dmem);
kfree(dmem);
return 0;
}
static const struct file_operations mmap_dev_fops = {
.owner = THIS_MODULE,
.open = mmap_dev_open,
.release = mmap_dev_release,
.mmap = dmem_map,
};
static struct miscdevice mmap_dev_device = \
{
.minor = MISC_DYNAMIC_MINOR,
.name = "mmap_dev",
.fops = &mmap_dev_fops,
.nodename = "mmap_dev",
.mode = 0666
};
module_driver(mmap_dev_device, misc_register, misc_deregister);
MODULE_DESCRIPTION("Platform device for mmap_dev_driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("MMAP:DRV");
MODULE_AUTHOR("Preetam S Reddy <preetam@mistralsolutions.com>");
以上是内核驱动程序。
以下文件在内核中注册设备。
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/module.h>
static struct platform_device mmap_pdev = {
.name = "mmap_dev",
};
int __init pmod_init(void)
{
platform_device_register(&mmap_pdev);
return 0;
}
void __exit pmod_exit(void)
{
platform_device_unregister(&mmap_pdev);
}
MODULE_DESCRIPTION("Platform device for mmap driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("MMAP:DRV");
MODULE_AUTHOR("Preetam S Reddy <preetam@mistralsolutions.com>");
以下代码适用于用户空间应用。
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#define NPAGES 100
int main(void)
{
int len = NPAGES * getpagesize();
unsigned int *mm_addr;
printf("page size = %d\n", getpagesize());
printf("length = %d", len);
int fd = open("/dev/mmap_dev", O_RDWR);
getc(stdin);
printf("Opening file...\n");
printf("mmap ...\n");
mm_addr = mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, fd, 0);
if(mm_addr == MAP_FAILED) {
printf("mmap failed\n");
perror("mmap");
exit(-1);
}
printf("mmap complete. \n");
getc(stdin);
printf("data @[0] : 0x%x\n", mm_addr[0]);
close(fd);
#if 1
printf("um-mmap ...\n");
munmap(mm_addr, len);
printf("umap... done\n");
#endif
return 0;
}
以下是内核输出的主要部分:
[ 7782.754615] map_dev_open: open
[ 7782.754703] map_dev_open: PAGE_SIZE = 4096
[ 7782.754706] map_dev_open: dmem = 18446719884479594496
[ 7782.754711] i= 0 : Reserved: 18446719884479594496 dmem: 0x62a00000
[ 7782.754714] i= 4096 : Reserved: 18446719884479594560 dmem: 0x62a00000
[ 7782.754716] i= 8192 : Reserved: 18446719884479594624 dmem: 0x62a00000
[ 7782.754719] i= 12288 : Reserved: 18446719884479594688 dmem: 0x62a00000
[ 7782.754722] i= 16384 : Reserved: 18446719884479594752 dmem: 0x62a00000
[ 7782.754725] i= 20480 : Reserved: 18446719884479594816 dmem: 0x62a00000
[ 7782.754728] i= 24576 : Reserved: 18446719884479594880 dmem: 0x62a00000
[ 7782.754731] i= 28672 : Reserved: 18446719884479594944 dmem: 0x62a00000
[ 7782.754734] i= 32768 : Reserved: 18446719884479595008 dmem: 0x62a00000
[ 7782.754736] i= 36864 : Reserved: 18446719884479595072 dmem: 0x62a00000
[ 7782.754739] i= 40960 : Reserved: 18446719884479595136 dmem: 0x62a00000
[ 7782.754742] i= 45056 : Reserved: 18446719884479595200 dmem: 0x62a00000
[ 7782.754745] i= 49152 : Reserved: 18446719884479595264 dmem: 0x62a00000
[ 7782.754748] i= 53248 : Reserved: 18446719884479595328 dmem: 0x62a00000
[ 7782.754751] i= 57344 : Reserved: 18446719884479595392 dmem: 0x62a00000
[ 7782.754753] i= 61440 : Reserved: 18446719884479595456 dmem: 0x62a00000
[ 7782.754756] i= 65536 : Reserved: 18446719884479595520 dmem: 0x62a00000
[ 7782.754759] i= 69632 : Reserved: 18446719884479595584 dmem: 0x62a00000
[ 7782.754762] i= 73728 : Reserved: 18446719884479595648 dmem: 0x62a00000
[ 7782.754765] i= 77824 : Reserved: 18446719884479595712 dmem: 0x62a00000
[ 7782.754768] i= 81920 : Reserved: 18446719884479595776 dmem: 0x62a00000
[ 7782.754770] i= 86016 : Reserved: 18446719884479595840 dmem: 0x62a00000
[ 7782.754773] i= 90112 : Reserved: 18446719884479595904 dmem: 0x62a00000
[ 7782.754776] i= 94208 : Reserved: 18446719884479595968 dmem: 0x62a00000
[ 7782.754779] i= 98304 : Reserved: 18446719884479596032 dmem: 0x62a00000
[ 7782.754782] i= 102400 : Reserved: 18446719884479596096 dmem: 0x62a00000
[ 7782.754784] i= 106496 : Reserved: 18446719884479596160 dmem: 0x62a00000
[ 7782.754787] i= 110592 : Reserved: 18446719884479596224 dmem: 0x62a00000
[ 7782.754790] i= 114688 : Reserved: 18446719884479596288 dmem: 0x62a00000
[ 7782.754793] i= 118784 : Reserved: 18446719884479596352 dmem: 0x62a00000
[ 7782.754796] i= 122880 : Reserved: 18446719884479596416 dmem: 0x62a00000
[ 7782.754798] i= 126976 : Reserved: 18446719884479596480 dmem: 0x62a00000
[ 7782.754801] i= 131072 : Reserved: 18446719884479596544 dmem: 0x62a00000
[ 7782.754804] i= 135168 : Reserved: 18446719884479596608 dmem: 0x62a00000
[ 7782.754807] i= 139264 : Reserved: 18446719884479596672 dmem: 0x62a00000
[ 7782.754810] i= 143360 : Reserved: 18446719884479596736 dmem: 0x62a00000
[ 7782.754812] i= 147456 : Reserved: 18446719884479596800 dmem: 0x62a00000
[ 7782.754815] i= 151552 : Reserved: 18446719884479596864 dmem: 0x62a00000
[ 7782.754818] i= 155648 : Reserved: 18446719884479596928 dmem: 0x62a00000
[ 7782.754821] i= 159744 : Reserved: 18446719884479596992 dmem: 0x62a00000
[ 7782.754824] i= 163840 : Reserved: 18446719884479597056 dmem: 0x62a00000
[ 7782.754826] i= 167936 : Reserved: 18446719884479597120 dmem: 0x62a00000
[ 7782.754829] i= 172032 : Reserved: 18446719884479597184 dmem: 0x62a00000
[ 7782.754832] i= 176128 : Reserved: 18446719884479597248 dmem: 0x62a00000
[ 7782.754835] i= 180224 : Reserved: 18446719884479597312 dmem: 0x62a00000
[ 7782.754837] i= 184320 : Reserved: 18446719884479597376 dmem: 0x62a00000
[ 7782.754840] i= 188416 : Reserved: 18446719884479597440 dmem: 0x62a00000
[ 7782.754843] i= 192512 : Reserved: 18446719884479597504 dmem: 0x62a00000
[ 7782.754846] i= 196608 : Reserved: 18446719884479597568 dmem: 0x62a00000
[ 7782.754849] i= 200704 : Reserved: 18446719884479597632 dmem: 0x62a00000
[ 7782.754851] i= 204800 : Reserved: 18446719884479597696 dmem: 0x62a00000
[ 7782.754854] i= 208896 : Reserved: 18446719884479597760 dmem: 0x62a00000
[ 7782.754857] i= 212992 : Reserved: 18446719884479597824 dmem: 0x62a00000
[ 7782.754860] i= 217088 : Reserved: 18446719884479597888 dmem: 0x62a00000
[ 7782.754863] i= 221184 : Reserved: 18446719884479597952 dmem: 0x62a00000
[ 7782.754865] i= 225280 : Reserved: 18446719884479598016 dmem: 0x62a00000
[ 7782.754868] i= 229376 : Reserved: 18446719884479598080 dmem: 0x62a00000
[ 7782.754871] i= 233472 : Reserved: 18446719884479598144 dmem: 0x62a00000
[ 7782.754874] i= 237568 : Reserved: 18446719884479598208 dmem: 0x62a00000
[ 7782.754877] i= 241664 : Reserved: 18446719884479598272 dmem: 0x62a00000
[ 7782.754879] i= 245760 : Reserved: 18446719884479598336 dmem: 0x62a00000
[ 7782.754882] i= 249856 : Reserved: 18446719884479598400 dmem: 0x62a00000
[ 7782.754885] i= 253952 : Reserved: 18446719884479598464 dmem: 0x62a00000
[ 7782.754888] i= 258048 : Reserved: 18446719884479598528 dmem: 0x62a00000
[ 7782.754891] i= 262144 : Reserved: 18446719884479598592 dmem: 0x62a00000
[ 7782.754893] i= 266240 : Reserved: 18446719884479598656 dmem: 0x62a00000
[ 7782.754896] i= 270336 : Reserved: 18446719884479598720 dmem: 0x62a00000
[ 7782.754899] i= 274432 : Reserved: 18446719884479598784 dmem: 0x62a00000
[ 7782.754902] i= 278528 : Reserved: 18446719884479598848 dmem: 0x62a00000
[ 7782.754905] i= 282624 : Reserved: 18446719884479598912 dmem: 0x62a00000
[ 7782.754908] i= 286720 : Reserved: 18446719884479598976 dmem: 0x62a00000
[ 7782.754910] i= 290816 : Reserved: 18446719884479599040 dmem: 0x62a00000
[ 7782.754913] i= 294912 : Reserved: 18446719884479599104 dmem: 0x62a00000
[ 7782.754916] i= 299008 : Reserved: 18446719884479599168 dmem: 0x62a00000
[ 7782.754919] i= 303104 : Reserved: 18446719884479599232 dmem: 0x62a00000
[ 7782.754922] i= 307200 : Reserved: 18446719884479599296 dmem: 0x62a00000
[ 7782.754924] i= 311296 : Reserved: 18446719884479599360 dmem: 0x62a00000
[ 7782.754927] i= 315392 : Reserved: 18446719884479599424 dmem: 0x62a00000
[ 7782.754930] i= 319488 : Reserved: 18446719884479599488 dmem: 0x62a00000
[ 7782.754933] i= 323584 : Reserved: 18446719884479599552 dmem: 0x62a00000
[ 7782.754936] i= 327680 : Reserved: 18446719884479599616 dmem: 0x62a00000
[ 7782.754938] i= 331776 : Reserved: 18446719884479599680 dmem: 0x62a00000
[ 7782.754941] i= 335872 : Reserved: 18446719884479599744 dmem: 0x62a00000
[ 7782.754944] i= 339968 : Reserved: 18446719884479599808 dmem: 0x62a00000
[ 7782.754947] i= 344064 : Reserved: 18446719884479599872 dmem: 0x62a00000
[ 7782.754950] i= 348160 : Reserved: 18446719884479599936 dmem: 0x62a00000
[ 7782.754952] i= 352256 : Reserved: 18446719884479600000 dmem: 0x62a00000
[ 7782.754955] i= 356352 : Reserved: 18446719884479600064 dmem: 0x62a00000
[ 7782.754958] i= 360448 : Reserved: 18446719884479600128 dmem: 0x62a00000
[ 7782.754961] i= 364544 : Reserved: 18446719884479600192 dmem: 0x62a00000
[ 7782.754963] i= 368640 : Reserved: 18446719884479600256 dmem: 0x62a00000
[ 7782.754966] i= 372736 : Reserved: 18446719884479600320 dmem: 0x62a00000
[ 7782.754969] i= 376832 : Reserved: 18446719884479600384 dmem: 0x62a00000
[ 7782.754972] i= 380928 : Reserved: 18446719884479600448 dmem: 0x62a00000
[ 7782.754975] i= 385024 : Reserved: 18446719884479600512 dmem: 0x62a00000
[ 7782.754977] i= 389120 : Reserved: 18446719884479600576 dmem: 0x62a00000
[ 7782.754980] i= 393216 : Reserved: 18446719884479600640 dmem: 0x62a00000
[ 7782.754983] i= 397312 : Reserved: 18446719884479600704 dmem: 0x62a00000
[ 7782.754986] i= 401408 : Reserved: 18446719884479600768 dmem: 0x62a00000
[ 7782.754989] i= 405504 : Reserved: 18446719884479600832 dmem: 0x62a00000
[ 8304.656599] systemd-hostnamed[6482]: Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!
[ 8407.896365] BUG: Bad page state: 40 messages suppressed
[ 8407.896373] BUG: Bad page state in process a.out pfn:62a00
[ 8407.896379] page:ffffea00018a8000 count:0 mapcount:0 mapping: (null) index:0x0
[ 8407.896381] page flags: 0x1ffff0000004400(reserved|head)
[ 8407.896388] Modules linked in: map_dev(OF) map_device(OF) rfcomm bnep binfmt_misc arc4 brcmsmac cordic brcmutil btusb intel_powerclamp b43 bluetooth coretemp kvm_intel kvm mac80211 i915 crct10dif_pclmul crc32_pclmul snd_hda_codec_hdmi cfg80211 snd_hda_codec_realtek uvcvideo snd_hda_intel ssb snd_hda_codec ghash_clmulni_intel drm_kms_helper snd_hwdep aesni_intel snd_pcm videobuf2_vmalloc snd_page_alloc aes_x86_64 drm acer_wmi videobuf2_memops lrw snd_seq_midi i2c_algo_bit gf128mul parport_pc glue_helper snd_seq_midi_event sparse_keymap ppdev videobuf2_core ablk_helper snd_rawmidi cryptd joydev videodev serio_raw lp bcma snd_seq wmi mei_me mei snd_seq_device snd_timer snd intel_ips soundcore mac_hid lpc_ich video parport psmouse tg3 ahci ptp libahci pps_core [last unloaded: map_dev]
[ 8407.896482] CPU: 1 PID: 6444 Comm: a.out Tainted: GF B O 3.13.0-27-generic #50-Ubuntu
[ 8407.896485] Hardware name: Acer TravelMate 4740 /TravelMate 4740 , BIOS V1.12 05/04/2010
答案 0 :(得分:0)
所以,我认为你担心的printk就是这个:
[ 7782.754711] i= 0 : Reserved: 18446719884479594496 dmem: 0x62a00000
[ 7782.754714] i= 4096 : Reserved: 18446719884479594560 dmem: 0x62a00000
来自这里:
for(i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
printk("i= %d \t: Reserved: %lu dmem: 0x%x \n",
i,
(unsigned long)(virt_to_page(((unsigned long)dmem_area) + i)),
(unsigned int)((unsigned long) dmem_area));
因为i
每次增加4096,但页面帧编号(来自virt_to_page
)不是。如果查看virt_to_page
的定义,您会看到它将虚拟地址参数转换为物理地址,然后将其右移PAGE_SHIFT
位。因此,您记录的PFN必须增加小于i
。
您系统上的PAGE_SHIFT
是什么?如果是6
,那么4096 >> 6 == 64
就会解释您的困惑。
现在,这是您在评论中提到的问题。你原来的问题是
我不明白为什么我的mmap无法从用户空间访问这些页面。为什么我无法访问超过10-14页?
但你还没有说出症状是什么。当您尝试访问第15页时,会发生什么?
好吧,在用户空间中,您将其作为int访问。因此,您将一次访问4个字节,因此您可以调整for循环。 您获得的地址也是页面帧编号。不是完整的字节地址。