2012-08-09 28 views
13

Tôi có một chương trình đơn giản cố gắng truy cập vào bộ nhớ vật lý trong không gian người dùng, nơi hạt nhân lưu trữ trang cấu trúc đầu tiên. Trên một máy 64 bit địa chỉ này là:Làm thế nào để truy cập mmaped/dev/mem mà không làm đứt hạt nhân Linux?

  • kernel địa chỉ ảo: ffffea0000000000
  • địa chỉ vật lý: 0000620000000000

Tôi cố gắng để truy cập vào địa chỉ vật lý này thông qua mmap trong không gian sử dụng. Nhưng đoạn mã sau bị treo hạt nhân.

int *addr; 
if ((fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0) { 
    printf("Error opening file. \n"); 
    close(fd); 
    return (-1); 
} 
/* mmap. address of first struct page for 64 bit architectures 
* is 0x0000620000000000. 
*/ 
addr = (int *)mmap(0, num*STRUCT_PAGE_SIZE, PROT_READ, MAP_PRIVATE, 
      fd, 0x0000620000000000); 
printf("addr: %p \n",addr); 
printf("addr: %d \n",*addr); /* CRASH. */ 
+1

Giá trị mmap() trả về trong addr là gì? – BjoernD

+1

@BjoernD: Tôi đã thử ở trên trên một x86 32-bit (thay thế bù đắp mmap là 0x01000000); addr = 0xffffffff. Và vâng, nó đổ vỡ tất nhiên về sự dereference. Giải pháp là gì? – kaiwan

+3

0xffffffff == -1 -> mmap() trả về lỗi. Theo trang người đàn ông, lý do cho lỗi được đưa ra trong biến 'errno'. Vì vậy, bạn có thể muốn kiểm tra tat. – BjoernD

Trả lời

18

Tôi nghĩ rằng tôi đã tìm thấy vấn đề - nó liên quan đến bảo vệ bản đồ bộ nhớ/dev/mem trên x86.

Pl tham khảo bài viết LWN này: "x86: giới thiệu những hạn chế/dev/mem với một tùy chọn cấu hình" http://lwn.net/Articles/267427/

CONFIG_NONPROMISC_DEVMEM

Bây giờ (i thử nghiệm này trên một hạt nhân gần đây 3.2.21) , tùy chọn cấu hình dường như được gọi là CONFIG_STRICT_DEVMEM.

tôi đã thay đổi cấu hình của tôi kernel:

$ grep DEVMEM .config 
# CONFIG_STRICT_DEVMEM is not set 
$ 

Khi PRG trên được chạy với hạt nhân trước đó, với CONFIG_STRICT_DEVMEM SET: show dmesg:

[29537.565599] Program a.out tried to access /dev/mem between 1000000->1001000. 
[29537.565663] a.out[13575]: segfault at ffffffff ip 080485bd sp bfb8d640 error 4 in a.out[8048000+1000] 

Điều này là do các bảo vệ hạt nhân ..

Khi hạt nhân được xây dựng lại (với CONFIG_STRICT_DEVMEM unset) và PRG trên đã chạy:

# ./a.out 
mmap failed: Invalid argument 
# 

Điều này là do các thông số 'bù đắp' là> 1 MB (không hợp lệ trên x86) (nó là 16MB).

Sau khi thực hiện mmap bù đắp được trong vòng 1 MB:

# ./a.out 
addr: 0xb7758000 
*addr: 138293760 
# 

Nó hoạt động! Xem bài viết LWN ở trên để biết chi tiết.

Trên kiến ​​trúc x86 có hỗ trợ PAT (Bảng thuộc tính trang), hạt nhân vẫn ngăn ánh xạ vùng DRAM. Lý do cho điều này như được đề cập trong số kernel source là:

This check is nedded to avoid cache aliasing when PAT is enabled 

Séc này sẽ gây ra lỗi tương tự như đã đề cập ở trên. Ví dụ:

Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

Hạn chế này có thể bị xóa bằng cách tắt PAT. PAT có thể được vô hiệu hóa bằng cách thêm đối số "nopat" vào dòng lệnh hạt nhân tại thời điểm khởi động.

+0

Xin chào Kaiwan, Cảm ơn để chỉ ra biến cấu hình thú vị. 'CONFIG_STRICT_DEVMEM chưa được đặt' trong trường hợp của tôi. Kernel (3.4.6 & 3.1.0). Sau khi thực hiện thay đổi bù đắp, chương trình hoạt động. Nhưng tôi đã quan tâm để truy cập vào địa chỉ đó vì nó giữ trang cấu trúc đầu tiên. điều này có thể không? – Vinay

+0

Ngoài ra tôi đặt bù đắp thành 0x0000000000000000 và tôi nhận được địa chỉ trả lại hợp lệ. Nhưng nếu tôi đặt bù đắp cho một số địa chỉ ngẫu nhiên nói 0x00000000000000ff, tôi không lấy lại một địa chỉ hợp lệ. Tôi có phải đặt địa chỉ trên ranh giới trang không? – Vinay

+1

ARM yêu cầu sử dụng ranh giới trang cho mmap(). Từ một thử nghiệm nhỏ trên IA32 nó có vẻ là trường hợp đó là tốt ... (& bạn đã thử trên x86_64 tôi đoán). Ngoài ra, hãy viết nhận xét của bạn về việc truy cập trang cấu trúc đầu tiên, với CONFIG_STRICT_DEVMEM Tắt, tôi nghĩ nó sẽ hoạt động (trên một biên giới trang) .. không chắc chắn về điều này .. – kaiwan

3

Trên kiến ​​trúc x86 có hỗ trợ PAT (Bảng thuộc tính trang), hạt nhân có thể ngăn ánh xạ vùng DRAM (ngay cả khi được biên dịch mà không cần thiết lập CONFIG_NONPROMISC_DEVMEM).

Lý do cho điều này như đã đề cập trong kernel source là:

This check is nedded to avoid cache aliasing when PAT is enabled 

kiểm tra này sẽ gây ra một lỗi tương tự xuất hiện trong dmesg như ai đề cập đến trong câu trả lời của chữ Kaiwan trên trên. Ví dụ:

Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

Hạn chế này có thể bị xóa bằng cách tắt PAT.

PAT có thể được tắt bằng cách thêm đối số nopat vào dòng lệnh hạt nhân tại thời điểm khởi động.

+0

Câu trả lời này (đúng!) Dường như đã được sao chép vào câu trả lời ở trên bởi một người dùng ẩn danh 8 phút sau khi bạn trả lời. Nếu bạn muốn xóa, hãy cho tôi biết và tôi sẽ chỉnh sửa nó, vì tôi cho rằng nó không công bằng nếu được thực hiện mà không có sự đồng ý của bạn. –

+0

Đó là tôi. Tôi là người đã thêm nó vào câu trả lời trước đó và sau đó thêm nó như là một câu trả lời riêng biệt bởi vì (rõ ràng) Tôi không biết làm thế nào để sử dụng công cụ: D. –

+0

OK! Hãy cho tôi biết nếu bạn muốn nó bị xóa khỏi câu trả lời ở trên. Chúc mừng. –

Các vấn đề liên quan