aboutsummaryrefslogtreecommitdiffstats
path: root/mmu.c
blob: ababef5cb6ff08be7db48fd4ea07dc41163518f0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<#include "wccmalloc.h"

// This must be redefined for each new benchmark
#define HEAP_SIZE 30000

char susan_simulated_heap[HEAP_SIZE];
unsigned int susan_freeHeapPos;

void* susan_wccmalloc( unsigned int numberOfBytes )
{
  // Get a 4-byte adress for alignment purposes
  unsigned int offset = ( (unsigned long)susan_simulated_heap + susan_freeHeapPos ) % 4;
  if ( offset ) {
    susan_freeHeapPos += 4 - offset;
  }
  void* currentPos = (void*)&susan_simulated_heap[susan_freeHeapPos];
  susan_freeHeapPos += numberOfBytes;
  return currentPos;
}
void susan_wccfreeall( void ) 
{
  susan_freeHeapPos = 0;
}

void* susan_wccmemcpy(void* dstpp, const void* srcpp, unsigned int len)
{
  unsigned long int dstp = (long int) dstpp;
  unsigned long int srcp = (long int) srcpp;

  _Pragma("loopbound min 76 max 76")
  while (len > 0) {
    char __x = ((char *) srcp)[0];
    srcp += 1;
    len -= 1;
    ((char *) dstp)[0] = __x;
    dstp += 1;
  }

  return dstpp;
}

void susan_wccmemset( void *p, int value, unsigned int num )
{
  unsigned long i;
  char *char_ptr = (char*)p;

  _Pragma( "loopbound min 7220 max 28880" )
  for ( i = 0; i < num; ++i ) {
    *char_ptr++ = (unsigned char)value;
  }
}
s="hl ppc">#include <linux/err.h> // ERR_PTR() etc. #include <linux/iommu.h> // iommu_get_domain_for_dev() and iommu_iova_to_phys() #include <linux/kernel.h> // Kernel types #include "nvdebug.h" /* Set logging level for MMU operations g_verbose >= 1: Log a single message describing the MMU operation g_verbose >= 2: Log every PDE and PTE traversed */ int g_verbose = 0; #define printk_debug if (g_verbose >= 2) printk #define printk_info if (g_verbose >= 1) printk /* Convert a page directory (PD) pointer and aperture to be kernel-accessible I/O MMU handling inspired by amdgpu_iomem_read() in amdgpu_ttm.c of the AMDGPU driver. @param addr Pointer from page directory entry (PDE) @param pd_ap PD-type aperture (target address space) for `addr` @return A dereferencable kernel address, or an ERR_PTR-wrapped error */ static void __iomem *pd_deref(struct nvdebug_state *g, uintptr_t addr, enum PD_TARGET pd_ap) { struct iommu_domain *dom; phys_addr_t phys; // Validate arguments if (unlikely(!IS_PD_TARGET(pd_ap) || pd_ap == PD_AND_TARGET_INVALID || !addr)) return ERR_PTR(-EINVAL); // VID_MEM accesses are the simple common-case if (pd_ap == PD_AND_TARGET_VID_MEM) { // Using BAR2 requires a page-table traversal. As this function is part // of the page-table traversal process, it must instead use PRAMIN. int off = addr_to_pramin_mut(g, addr, TARGET_VID_MEM); if (off < 0) return ERR_PTR(off); return g->regs + NV_PRAMIN + off; } /* SYS_MEM accesses are rare. Only nvgpu (Jetson driver), nouveau, and this * driver are known to create page directory entries in SYS_MEM. * * On systems using an I/O MMU, or some other I/O virtual address space, * these are **not** physical addresses, and must first be translated * through the I/O MMU before use. * Example default meaning of a SYS_MEM address for a few CPUs: * - Jetson Xavier : physical address * - AMD 3950X : I/O MMU address * - Phenom II x4 : physical address */ // Check for, and translate through, the I/O MMU (if any) if ((dom = iommu_get_domain_for_dev(g->dev))) { phys = iommu_iova_to_phys(dom, addr); printk_debug(KERN_DEBUG "[nvdebug] I/O MMU translated SYS_MEM I/O VA %#lx to physical address %#llx.\n", addr, phys); } else phys = addr; if (!phys) return 0; return phys_to_virt(phys); } // Internal helper for search_page_directory(). uint64_t search_page_directory_subtree(struct nvdebug_state *g, uintptr_t pde_addr, enum PD_TARGET pde_target, uint64_t addr_to_find, enum INST_TARGET addr_to_find_aperture, uint32_t level) { uint64_t res, i; void __iomem *pde_kern; page_dir_entry_t entry; if (level > sizeof(NV_MMU_PT_V2_SZ)) return 0; // Hack to workaround PDE0 being double-size and strangely formatted if (NV_MMU_PT_V2_ENTRY_SZ[level] == 16) pde_addr += 8; // Translate a VID_MEM/SYS_MEM-space address to something kernel-accessible pde_kern = pd_deref(g, pde_addr, pde_target); if (IS_ERR_OR_NULL(pde_kern)) { printk(KERN_ERR "[nvdebug] %s: Unable to resolve %#lx in GPU %s to a kernel-accessible address. Error %ld.\n", __func__, pde_addr, pd_target_to_text(pde_target), PTR_ERR(pde_kern)); return 0; }