Linux 在Ubuntu 10.04(64位机器)上访问物理内存时,电脑完全冻结

Linux 在Ubuntu 10.04(64位机器)上访问物理内存时,电脑完全冻结,linux,memory,linux-kernel,ubuntu-10.04,Linux,Memory,Linux Kernel,Ubuntu 10.04,我正在尝试使用这个使用mmap()的程序访问电脑的物理内存- #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #定义致命do{fprintf(stderr,“第%d行错误,文件%s(%d)[%s]\n”\ __行_uu,_u文件_uu,errno,strerror(errno));退出(1);}while(0) #定义地图尺寸4096UL #定义映射掩码(映射大小-1) int main(int argc,字符**argv){ int-fd; void*m

我正在尝试使用这个使用mmap()的程序访问电脑的物理内存-

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义致命do{fprintf(stderr,“第%d行错误,文件%s(%d)[%s]\n”\
__行_uu,_u文件_uu,errno,strerror(errno));退出(1);}while(0)
#定义地图尺寸4096UL
#定义映射掩码(映射大小-1)
int main(int argc,字符**argv){
int-fd;
void*map\u base,*virt\u addr;
无符号长读结果,writeval;
偏离目标;
int access_type='w';
如果(argc<2){
fprintf(stderr,“\n用法:\t%s{address}[类型[数据]]\n”
“\t地址:要执行操作的内存地址\n”
\t类型:访问操作类型:[b]yte,[h]alfword,[w]ord\n
“\t数据:要写入的数据\n\n”,
argv[0]);
出口(1);
}
target=strtoul(argv[1],0,0);
如果(argc>2)
访问类型=tolower(argv[2][0]);
如果((fd=open(“/dev/mem”,O|RDWR | O|u SYNC))==-1)致命;
printf(“/dev/mem已打开。\n”);
fflush(stdout);
/*映射一页*/
map_base=mmap(0,map_大小,PROT_读写,map_共享,fd,目标&~map_掩码);
如果(map_base==(void*)-1)致命;
printf(“在地址%p处映射的内存。\n”,映射库);
fflush(stdout);
virt_addr=map_base+(目标和映射掩码);
交换机(接入型){
案例“b”:
read_result=*((无符号字符*)virt_addr);
打破
案例“h”:
读取结果=*((无符号短*)虚拟地址);
打破
案例“w”:
读取结果=*((无符号长*)虚拟地址);
打破
违约:
fprintf(stderr,“非法数据类型“%c”。\n”,访问类型);
出口(2);
}
printf(“地址0x%X(%p):0x%X\n处的值”,目标,病毒地址,读取结果);
fflush(stdout);
如果(argc>3){
writeval=strtoul(argv[3],0,0);
交换机(接入型){
案例“b”:
*((无符号字符*)virt_addr)=writeval;
read_result=*((无符号字符*)virt_addr);
打破
案例“h”:
*((无符号短*)virt_addr)=writeval;
读取结果=*((无符号短*)虚拟地址);
打破
案例“w”:
*((无符号长*)virt_addr)=writeval;
读取结果=*((无符号长*)虚拟地址);
打破
}
printf(“写入0x%X;回读0x%X\n”,writeval,read\u结果);
fflush(stdout);
}
如果(munmap(map\u base,map\u SIZE)=-1)致命;
关闭(fd);
返回0;
}
当我以sudo./a.out 0xfdff8000的形式运行这个程序时,我的系统只是挂起。鼠标,键盘,显示一切冻结!重启是唯一的选择。我在/proc/iomem中检查了0xfdff8000。它对应于ICH高清音频。我不知道这意味着什么。
此外,kmsg、dmesg和/var/log/messages没有抛出任何提示

您正在读取芯片组IO内存中某个位置的单词。我不能确切地告诉你为什么这会冻结你的系统,但是在不知道地址上有什么硬件寄存器,或者不知道有问题的硬件的正确编程方式的情况下偷看和戳IO内存很可能会冻结你的系统。

你正在读芯片组IO内存中某个地方的一个单词。我无法确切地告诉您为什么会冻结您的系统,但是在不知道地址上有什么硬件寄存器或对所讨论的硬件进行正确编程的情况下偷看和戳IO内存很可能会冻结您的系统。

您不应该直接访问物理内存。可能会发生的情况是,页面表条目是使用该地址设置的,该地址是指向设备的内存映射指针。未经允许读取将使系统崩溃,因为它将向操作系统发送一个它不期望的中断错误

请记住,物理地址和虚拟地址是完全不同的。程序读取的地址都是虚拟的,我认为获取物理地址(除非映射,否则无法访问)的唯一方法是进行线性地址转换,该转换依赖于硬件(例如x86内核函数convert_ip_to_linear)


可能的崩溃原因是不安全的访问,因为驱动程序通常运行比用户空间高一个环级别,而您试图从用户空间而不是驱动程序级别的空间读取环级别,这会导致访问冲突。

您不应该直接访问物理内存。可能会发生的情况是,页面表条目是使用该地址设置的,该地址是指向设备的内存映射指针。未经允许读取将使系统崩溃,因为它将向操作系统发送一个它不期望的中断错误

请记住,物理地址和虚拟地址是完全不同的。程序读取的地址都是虚拟的,我认为获取物理地址(除非映射,否则无法访问)的唯一方法是进行线性地址转换,该转换依赖于硬件(例如x86内核函数convert_ip_to_linear)


可能的崩溃原因是不安全的访问,因为驱动程序通常运行的环级别高于用户空间,而您试图从用户空间而不是驱动程序级别的空间读取环级别会导致访问冲突。

您是对的,Ronald,虽然我对到底出了什么问题不感兴趣,但我想从内核的角度了解,冻结的可能原因是什么?当这种冻结发生时,内核在哪里运行(代码),为什么内核不能优雅地处理这种情况?谢谢最有可能的情况是,您的系统实际上在硬件级别被冻结了——内核永远没有机会运行,因为当它访问伪物理时,CPU会立即挂起
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>

#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
  __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

int main(int argc, char **argv) {
    int fd;
    void *map_base, *virt_addr;
    unsigned long read_result, writeval;
    off_t target;
    int access_type = 'w';

    if(argc < 2) {
        fprintf(stderr, "\nUsage:\t%s { address } [ type [ data ] ]\n"
            "\taddress : memory address to act upon\n"
            "\ttype    : access operation type : [b]yte, [h]alfword, [w]ord\n"
            "\tdata    : data to be written\n\n",
            argv[0]);
        exit(1);
    }
    target = strtoul(argv[1], 0, 0);

    if(argc > 2)
        access_type = tolower(argv[2][0]);


    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    printf("/dev/mem opened.\n");
    fflush(stdout);

    /* Map one page */
    map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
    if(map_base == (void *) -1) FATAL;
    printf("Memory mapped at address %p.\n", map_base);
    fflush(stdout);

    virt_addr = map_base + (target & MAP_MASK);
    switch(access_type) {
        case 'b':
            read_result = *((unsigned char *) virt_addr);
            break;
        case 'h':
            read_result = *((unsigned short *) virt_addr);
            break;
        case 'w':
            read_result = *((unsigned long *) virt_addr);
            break;
        default:
            fprintf(stderr, "Illegal data type '%c'.\n", access_type);
            exit(2);
    }
    printf("Value at address 0x%X (%p): 0x%X\n", target, virt_addr, read_result);
    fflush(stdout);

    if(argc > 3) {
        writeval = strtoul(argv[3], 0, 0);
        switch(access_type) {
            case 'b':
                *((unsigned char *) virt_addr) = writeval;
                read_result = *((unsigned char *) virt_addr);
                break;
            case 'h':
                *((unsigned short *) virt_addr) = writeval;
                read_result = *((unsigned short *) virt_addr);
                break;
            case 'w':
                *((unsigned long *) virt_addr) = writeval;
                read_result = *((unsigned long *) virt_addr);
                break;
        }
        printf("Written 0x%X; readback 0x%X\n", writeval, read_result);
        fflush(stdout);
    }

    if(munmap(map_base, MAP_SIZE) == -1) FATAL;
    close(fd);
    return 0;
}