This repository was archived by the owner on Dec 2, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrh_timing.rb
More file actions
142 lines (122 loc) · 3.73 KB
/
rh_timing.rb
File metadata and controls
142 lines (122 loc) · 3.73 KB
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/ruby
# -*- encoding: utf-8 -*-
$: << "ext/"
require "RHUtils"
module RHUtils
class Page
ROW_SHIFT = 17
def row
@p >> ROW_SHIFT
end
end
end
include RHUtils
class HammerResult < Struct.new("HammerInfo", :p, :page, :value, :n, :ticks, :pairs)
def inspect
"#<HammerResult p=0x%x value=%x n=#{self.n} ticks=#{self.ticks} pairs=#{pairs}>" % [self.p, self.value]
end
def offset; self.p - self.page.p; end
def ns; RHUtils.ticks_to_ns(self.ticks); end
def explain
addr = "pa 0x%x+%x value %x" % [self.page.p, self.offset, self.value]
timing = "hammer %d times %d ms (avg %d ns)" % [self.n, self.ns/1000000, self.ns/self.n]
pair = self.pairs.map {|x| "%x-%x" % [x[0].p, x[1].p]}.join(" ")
return [addr, timing, pair].join(", ")
end
end
$pages_per_row = 32
$result = {}
# test row [r] by hammering [ppage, qpage] (on row (r-1, r+1) and with row conflict)
# and update result hash
def hammer_row(r, ppage, qpage, ntime)
flag = false
$result[r] ||= {}
# fill row with 0xff (c-routine)
$pages[r-1].each {|pg| pg.fill(0x55)}
$pages[r].each {|pg| pg.fill(0xaa)}
$pages[r+1].each {|pg| pg.fill(0x55)}
# hammer virt addrs (c-routine)
ticks = hammer(ppage.v, qpage.v, ntime, $lat)
# parse result
$pages[r].each {|pg|
# with each bug offset i, update result hash
pg.check(0xaa).each {|i|
pa = pg.p+i
info = $result[r][pa] || HammerResult.new(
p = pa,
page = pg,
value = pg[i],
n = ntime,
ticks = ticks,
pairs = []
)
info.pairs << [ppage, qpage]; info.pairs.uniq! # hammer page object
if ntime <= info.n
info.n, info.ticks = ntime, ticks
flag = true
end
$result[r][pa] = info
}
}
return flag
end
# select hammer pages:
# p: on row (r-1), every 8kB
# q: on row (r+1), every 8kB, row conflict with p
# hammer them with $ntime_max times to get initial result
def test_row_first(r)
flag = false
$pages[r-1].select{|p| (p.p >> PAGE_SHIFT).even? }.each {|p|
$pages[r+1].select {|q| (q.p >> PAGE_SHIFT).even? and conflict?(p.v, q.v)
}.each {|q|
flag |= hammer_row(r, p, q, $ntime_max)
}
}
return flag
end
# test smallest loop time to invoke bit flip
def test_hammer_time(r)
flag = true
ntime = $ntime_max - 100000
pair = $result[r].values[0].pairs[0] # just pick one pair ????
while (ntime > 0 and flag)
# puts ntime
hammer_row(r, pair[0], pair[1], ntime)
ntime -= 100000
end
end
# -- 1. allocate memory
mb = 2048
$lat = (ARGV[0] || 0).to_i
$ntime_max = (ARGV[1] || 1024000).to_i
$start_row = (ARGV[2] || 0).to_i
puts "- allocate #{mb} MB memory..."
$pages = allocate_mb(mb).group_by(&:row)
# -- 2. release unused rows
puts "- release rows that we don't hold (<32 pages)"
$pages.keys.select {|k| $pages[k].size < $pages_per_row}.each {|k|
$pages[k].each &:release
$pages.delete(k)
}
# -- 3. select test rows
test_rows = $pages.keys.select {|k| $pages.has_key?(k-1) and $pages.has_key?(k+1) and k>=$start_row}
# -- 4. start testing
begin
puts "- start testing"
test_rows.each {|r|
puts "- Row #{r} -"
if test_row_first(r)
# if found bug, test min time to invoke it
test_hammer_time(r)
$result[r].each_value {|v|
puts v.explain
puts "-----------"
}
end
}
rescue Interrupt
puts "", "Interrupt"
end
# -- 5. cleanup
puts "cleanup..."
$pages.values.flatten.each &:release