/
reg32.go
143 lines (110 loc) · 3.41 KB
/
reg32.go
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
142
143
// https://github.com/f-secure-foundry/tamago
//
// Copyright (c) F-Secure Corporation
// https://foundry.f-secure.com
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.
// Package reg provides primitives for retrieving and modifying hardware
// registers.
//
// This package is only meant to be used with `GOOS=tamago GOARCH=arm` as
// supported by the TamaGo framework for bare metal Go on ARM SoCs, see
// https://github.com/f-secure-foundry/tamago.
package reg
import (
"runtime"
"sync/atomic"
"time"
"unsafe"
)
func Get(addr uint32, pos int, mask int) uint32 {
reg := (*uint32)(unsafe.Pointer(uintptr(addr)))
r := atomic.LoadUint32(reg)
return uint32((int(r) >> pos) & mask)
}
func Set(addr uint32, pos int) {
reg := (*uint32)(unsafe.Pointer(uintptr(addr)))
r := atomic.LoadUint32(reg)
r |= (1 << pos)
atomic.StoreUint32(reg, r)
}
func Clear(addr uint32, pos int) {
reg := (*uint32)(unsafe.Pointer(uintptr(addr)))
r := atomic.LoadUint32(reg)
r &= ^(1 << pos)
atomic.StoreUint32(reg, r)
}
func SetN(addr uint32, pos int, mask int, val uint32) {
reg := (*uint32)(unsafe.Pointer(uintptr(addr)))
r := atomic.LoadUint32(reg)
r = (r & (^(uint32(mask) << pos))) | (val << pos)
atomic.StoreUint32(reg, r)
}
func ClearN(addr uint32, pos int, mask int) {
reg := (*uint32)(unsafe.Pointer(uintptr(addr)))
r := atomic.LoadUint32(reg)
r &= ^(uint32(mask) << pos)
atomic.StoreUint32(reg, r)
}
// defined in reg32.s
func Move(dst uint32, src uint32)
func Read(addr uint32) uint32 {
reg := (*uint32)(unsafe.Pointer(uintptr(addr)))
return atomic.LoadUint32(reg)
}
func Write(addr uint32, val uint32) {
reg := (*uint32)(unsafe.Pointer(uintptr(addr)))
atomic.StoreUint32(reg, val)
}
func WriteBack(addr uint32) {
reg := (*uint32)(unsafe.Pointer(uintptr(addr)))
r := atomic.LoadUint32(reg)
r |= r
atomic.StoreUint32(reg, r)
}
func Or(addr uint32, val uint32) {
reg := (*uint32)(unsafe.Pointer(uintptr(addr)))
r := atomic.LoadUint32(reg)
r |= val
atomic.StoreUint32(reg, r)
}
// Wait waits for a specific register bit to match a value. This function
// cannot be used before runtime initialization with `GOOS=tamago`.
func Wait(addr uint32, pos int, mask int, val uint32) {
for Get(addr, pos, mask) != val {
// tamago is single-threaded, give other goroutines a chance
runtime.Gosched()
}
}
// WaitFor waits, until a timeout expires, for a specific register bit to match
// a value. The return boolean indicates whether the wait condition was checked
// (true) or if it timed out (false). This function cannot be used before
// runtime initialization.
func WaitFor(timeout time.Duration, addr uint32, pos int, mask int, val uint32) bool {
start := time.Now()
for Get(addr, pos, mask) != val {
// tamago is single-threaded, give other goroutines a chance
runtime.Gosched()
if time.Since(start) >= timeout {
return false
}
}
return true
}
// WaitSignal waits, until a channel is closed, for a specific register bit to
// match a value. The return boolean indicates whether the wait condition was
// checked (true) or cancelled (false). This function cannot be used before
// runtime initialization.
func WaitSignal(done chan bool, addr uint32, pos int, mask int, val uint32) bool {
for Get(addr, pos, mask) != val {
// tamago is single-threaded, give other goroutines a chance
runtime.Gosched()
select {
case <-done:
return false
default:
}
}
return true
}