mmap.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #define _XOPEN_SOURCE 700
  2. #include <assert.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <stdint.h> /* uintmax_t */
  7. #include <string.h>
  8. #include <sys/mman.h>
  9. #include <unistd.h> /* sysconf */
  10. #include "common.h" /* virt_to_phys_user */
  11. enum { BUFFER_SIZE = 4 };
  12. int main(int argc, char **argv)
  13. {
  14. int fd;
  15. long page_size;
  16. char *address1, *address2;
  17. char buf[BUFFER_SIZE];
  18. uintptr_t paddr;
  19. if (argc < 2) {
  20. printf("Usage: %s <mmap_file>\n", argv[0]);
  21. return EXIT_FAILURE;
  22. }
  23. page_size = sysconf(_SC_PAGE_SIZE);
  24. printf("open pathname = %s\n", argv[1]);
  25. fd = open(argv[1], O_RDWR | O_SYNC);
  26. if (fd < 0) {
  27. perror("open");
  28. assert(0);
  29. }
  30. printf("fd = %d\n", fd);
  31. /* mmap twice for double fun. */
  32. puts("mmap 1");
  33. address1 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  34. if (address1 == MAP_FAILED) {
  35. perror("mmap");
  36. assert(0);
  37. }
  38. puts("mmap 2");
  39. address2 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  40. if (address2 == MAP_FAILED) {
  41. perror("mmap");
  42. return EXIT_FAILURE;
  43. }
  44. assert(address1 != address2);
  45. /* Read and modify memory. */
  46. puts("access 1");
  47. assert(!strcmp(address1, "asdf"));
  48. /* vm_fault */
  49. puts("access 2");
  50. assert(!strcmp(address2, "asdf"));
  51. /* vm_fault */
  52. strcpy(address1, "qwer");
  53. /* Also modified. So both virtual addresses point to the same physical address. */
  54. assert(!strcmp(address2, "qwer"));
  55. /* Check that the physical addresses are the same.
  56. * They are, but TODO why virt_to_phys on kernel gives a different value? */
  57. assert(!virt_to_phys_user(&paddr, getpid(), (uintptr_t)address1));
  58. printf("paddr1 = 0x%jx\n", (uintmax_t)paddr);
  59. assert(!virt_to_phys_user(&paddr, getpid(), (uintptr_t)address2));
  60. printf("paddr2 = 0x%jx\n", (uintmax_t)paddr);
  61. /* Check that modifications made from userland are also visible from the kernel. */
  62. read(fd, buf, BUFFER_SIZE);
  63. assert(!memcmp(buf, "qwer", BUFFER_SIZE));
  64. /* Modify the data from the kernel, and check that the change is visible from userland. */
  65. write(fd, "zxcv", 4);
  66. assert(!strcmp(address1, "zxcv"));
  67. assert(!strcmp(address2, "zxcv"));
  68. /* Cleanup. */
  69. puts("munmap 1");
  70. if (munmap(address1, page_size)) {
  71. perror("munmap");
  72. assert(0);
  73. }
  74. puts("munmap 2");
  75. if (munmap(address2, page_size)) {
  76. perror("munmap");
  77. assert(0);
  78. }
  79. puts("close");
  80. close(fd);
  81. return EXIT_SUCCESS;
  82. }