1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import struct
22
23 from rekall import addrspace
24 from rekall import config
25 from rekall.plugins.addrspaces import intel
26
27 -class MIPS32PagedMemory(intel.IA32PagedMemory):
28 '''
29 Address space to handle the MIPS Linux memory layout, which is:
30
31 0x0000 0000 - 0x7FFF FFFF kuseg: User mapped pages
32 0x8000 0000 - 0x9FFF FFFF k0seg: Kernel non paged memory, this maps to
33 address range 0x0000 0000 - 0x1FFF FFFF
34 0xA000 0000 - 0xBFFF FFFF k1seg: Kernel non paged, non cached memory,
35 this maps to address range
36 0x0000 0000 - 0x1FFF FFFF
37 0xC000 0000 - 0xFFFF FFFF k2seg: Kernel paged memory using init_mm.pgd
38
39 See page 8 on:
40 http://www.eecs.harvard.edu/~margo/cs161/notes/vm-mips.pdf
41
42 Derives from IA32PagedMemory as the only major difference is the special
43 layout as shown above and minor details like no large pages and a difference
44 in the PTE to PFN translation, which is taken care of by the
45 pte_paddr function.
46 '''
47
48
49 valid_mask = (1 << 32) - 1
50
52 '''
53 Convert a physical address to the actual physical memory location.
54 '''
55 if x < 0x80000000:
56 return x
57 elif x >= 0xA0000000:
58 return x - 0xA0000000
59 else:
60 return x - 0x80000000
61
62 - def page_size_flag(self, entry):
63 '''
64 MIPS32 doesn't have a page size flag, always return False
65 '''
66 return False
67
68 - def read_long_phys(self, addr):
69 '''
70 Returns an unsigned 32-bit integer from the address addr in
71 physical memory. If unable to read from that location, returns None.
72 '''
73 string = self.base.read(self._pa(addr), 4)
74 return struct.unpack('>I', string)[0]
75
76 - def vtop(self, vaddr):
77 '''
78 Translates virtual addresses into physical offsets.
79 The function should return either None (no valid mapping)
80 or the offset in physical memory where the address maps.
81 '''
82 if (vaddr >= 0x80000000) and (vaddr < 0xC0000000):
83 return self._pa(vaddr)
84
85 return super(MIPS32PagedMemory, self).vtop(vaddr)
86
87 - def pte_paddr(self, pte):
88 '''
89 Return the physical address for the given PTE.
90 This should return:
91 (pte >> pfn_shift) << page_shift
92
93 On MIPS pfn_shift is 11, while page_shift is 12
94 '''
95 return pte << 1
96
97 - def get_phys_addr(self, vaddr, pte_value):
98 '''
99 Return the offset in a 4KB memory page from the given virtual
100 address and Page Table Entry.
101
102 Bits 31:12 are from the PTE
103 Bits 11:0 are from the original linear address
104 '''
105 if pte_value & self.valid_mask:
106 return (self.pte_paddr(pte_value) & 0xfffff000) | (vaddr & 0xfff)
107
108 - def get_available_addresses(self, start=0):
109 """Enumerate all valid memory ranges.
110
111 Yields:
112 tuples of (starting virtual address, size) for valid the memory
113 ranges.
114 """
115
116
117 sym = self._pa(self.session.profile.get_constant('swapper_pg_dir'))
118 if self.dtb == sym:
119 num_pde = 1024
120 else:
121 num_pde = 512
122
123
124
125
126
127 for pde in range(0, num_pde):
128 vaddr = pde << 22
129 next_vaddr = (pde+1) << 22
130 if start > next_vaddr:
131 continue
132
133 if (vaddr >= 0x80000000) and (vaddr < 0xC0000000):
134 yield (vaddr, self._pa(vaddr), 1 << 22)
135 continue
136
137 pde_value = self.get_pde(vaddr)
138
139
140
141
142
143 pte_table_addr = ((pde_value & 0xfffff000) |
144 ((vaddr & 0x3ff000) >> 10))
145
146 data = self.base.read(self._pa(pte_table_addr), 4 * 0x400)
147 pte_table = struct.unpack(">" + "I" * 0x400, data)
148
149 tmp1 = vaddr
150 for i, pte_value in enumerate(pte_table):
151 vaddr = tmp1 | i << 12
152 next_vaddr = tmp1 | ((i+1) << 12)
153
154 if start > next_vaddr:
155 continue
156
157 if pte_value & self.valid_mask:
158 yield (vaddr,
159 self.get_phys_addr(vaddr, pte_value),
160 0x1000)
161