int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot) { int error = 0; pgd_t * dir; unsigned long beg = from; unsigned long end = from + size; struct mm_struct *mm = vma->vm_mm; int space = GET_IOSPACE(pfn); unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT; /* See comment in mm/memory.c remap_pfn_range */ vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; vma->vm_pgoff = (offset >> PAGE_SHIFT) | ((unsigned long)space << 28UL); offset -= from; dir = pgd_offset(mm, from); flush_cache_range(vma, beg, end); while (from < end) { pmd_t *pmd = pmd_alloc(mm, dir, from); error = -ENOMEM; if (!pmd) break; error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space); if (error) break; from = (from + PGDIR_SIZE) & PGDIR_MASK; dir++; } flush_tlb_range(vma, beg, end); return error; }
int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot) { int error = 0; pgd_t * dir; unsigned long beg = from; unsigned long end = from + size; struct mm_struct *mm = vma->vm_mm; int space = GET_IOSPACE(pfn); unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT; prot = __pgprot(pg_iobits); offset -= from; dir = pgd_offset(mm, from); flush_cache_range(vma, beg, end); spin_lock(&mm->page_table_lock); while (from < end) { pud_t *pud = pud_alloc(current->mm, dir, from); error = -ENOMEM; if (!pud) break; error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space); if (error) break; from = (from + PGDIR_SIZE) & PGDIR_MASK; dir++; } flush_tlb_range(vma, beg, end); spin_unlock(&mm->page_table_lock); return error; }
int get_phy_addr(ull *out_phy_addr, ull pid, ull virt_addr) { int pagemap_fd; char pagemap_path[256]; ull pagesize; ull pagesizemask; ull index; ull offset; ull seek_result; if (pid > 0) { sprintf(pagemap_path, "/proc/%llu/pagemap", pid); } else { // pid == 0 sprintf(pagemap_path, "/proc/self/pagemap"); } pagemap_fd = open(pagemap_path, O_RDONLY); if (pagemap_fd == -1) { fprintf(stderr, "failed to open %s\n", pagemap_path); return -1; } pagesize = (ull)memtester_pagesize(); pagesizemask = ~(pagesize - 1); index = (((virt_addr & pagesizemask) / pagesize) * sizeof(ull)); offset = (virt_addr & (~pagesizemask)); seek_result = (ull)lseek64(pagemap_fd, (off64_t)index, SEEK_SET); if (seek_result != index) { fprintf(stderr, "failed to seek\n"); close(pagemap_fd); return -2; } if (read(pagemap_fd, (void *)out_phy_addr, (size_t)sizeof(ull)) != sizeof(ull)) { fprintf(stderr, "failed to read\n"); close(pagemap_fd); return -3; } close(pagemap_fd); if (IS_PRESENT(*out_phy_addr)) { *out_phy_addr = GET_PFN(*out_phy_addr); *out_phy_addr = *out_phy_addr * pagesize; *out_phy_addr = *out_phy_addr + offset; return 0; } else { fprintf(stderr, "invalide pfn\n"); return -4; } }
int read_pagemap(char * path_buf, unsigned long virt_addr){ printf("Big endian? %d\n", is_bigendian()); f = fopen(path_buf, "rb"); if(!f){ printf("Error! Cannot open %s\n", path_buf); return -1; } //Shifting by virt-addr-offset number of bytes //and multiplying by the size of an address (the size of an entry in pagemap file) file_offset = virt_addr / getpagesize() * PAGEMAP_ENTRY; printf("Vaddr: 0x%lx, Page_size: %d, Entry_size: %d\n", virt_addr, getpagesize(), PAGEMAP_ENTRY); printf("Reading %s at 0x%llx\n", path_buf, (unsigned long long) file_offset); status = fseek(f, file_offset, SEEK_SET); if(status){ perror("Failed to do fseek!"); return -1; } errno = 0; read_val = 0; unsigned char c_buf[PAGEMAP_ENTRY]; for(i=0; i < PAGEMAP_ENTRY; i++){ c = getc(f); if(c==EOF){ printf("\nReached end of the file\n"); return 0; } if(is_bigendian()) c_buf[i] = c; else c_buf[PAGEMAP_ENTRY - i - 1] = c; printf("[%d]0x%x ", i, c); } for(i=0; i < PAGEMAP_ENTRY; i++){ //printf("%d ",c_buf[i]); read_val = (read_val << 8) + c_buf[i]; } printf("\n"); printf("Result: 0x%llx\n", (unsigned long long) read_val); //if(GET_BIT(read_val, 63)) if(GET_BIT(read_val, 63)) printf("PFN: 0x%llx\n",(unsigned long long) GET_PFN(read_val)); else printf("Page not present\n"); if(GET_BIT(read_val, 62)) printf("Page swapped\n"); fclose(f); return 0; }
unsigned long long read_pagemap(void* virt_addr){ int i, c, status; uint64_t read_val, file_offset; if(!f){ f = fopen("/proc/self/pagemap","rb"); } if(!f){ printf("Pagemap Read Error! Cannot open\n"); return 0; } //Shifting by virt-addr-offset number of bytes //and multiplying by the size of an address (the size of an entry in pagemap file) file_offset = ((unsigned long long)virt_addr) / getpagesize() * PAGEMAP_ENTRY; status = fseek(f, file_offset, SEEK_SET); if(status){ perror("Failed to do fseek!"); return 0; } errno = 0; read_val = 0; unsigned char c_buf[PAGEMAP_ENTRY]; for(i=0; i < PAGEMAP_ENTRY; i++){ c = getc(f); if(c==EOF){ return 0; } c_buf[PAGEMAP_ENTRY - i - 1] = c; } for(i=0; i < PAGEMAP_ENTRY; i++){ read_val = (read_val << 8) + c_buf[i]; } if(GET_BIT(read_val, 63)) return (unsigned long long) GET_PFN(read_val); else return 0; fseek(f,0,SEEK_SET); return 0; }