5
5
"errors"
6
6
"fmt"
7
7
"machine"
8
- "runtime/interrupt"
9
8
"time"
10
9
)
11
10
@@ -17,14 +16,17 @@ var (
17
16
func (m * msc ) RegisterBlockDevice (dev machine.BlockDevice ) {
18
17
m .dev = dev
19
18
20
- m .blockRatio = 1
21
- m .blockSize = uint32 (m .dev .WriteBlockSize ())
22
- if m .blockSize < 512 {
23
- // If the block size is less than 512 bytes, we'll scale it up to 512 for compatibility
24
- m .blockRatio = 512 / m .blockSize
25
- m .blockSize = 512
19
+ if cap (m .blockCache ) != int (dev .WriteBlockSize ()) {
20
+ m .blockCache = make ([]byte , dev .WriteBlockSize ())
21
+ m .buf = make ([]byte , dev .WriteBlockSize ())
26
22
}
27
- m .blockCount = uint32 (m .dev .Size ()) / m .blockSize
23
+
24
+ m .blockSizeRaw = uint32 (m .dev .WriteBlockSize ())
25
+ m .blockCount = uint32 (m .dev .Size ()) / m .blockSizeUSB
26
+ // Read/write/erase operations must be aligned to the underlying hardware blocks. In order to align
27
+ // them we assume the provided block device is aligned to the end of the underlying hardware block
28
+ // device and offset all reads/writes by the remaining bytes that don't make up a full block.
29
+ m .blockOffset = uint32 (m .dev .Size ()) % m .blockSizeUSB
28
30
// FIXME: Figure out what to do if the emulated write block size is larger than the erase block size
29
31
30
32
// Set VPD UNMAP fields
@@ -33,7 +35,7 @@ func (m *msc) RegisterBlockDevice(dev machine.BlockDevice) {
33
35
// 0xb0 - 5.4.5 Block Limits VPD page (B0h)
34
36
if len (vpdPages [i ].Data ) >= 28 {
35
37
// Set the OPTIMAL UNMAP GRANULARITY (write blocks per erase block)
36
- granularity := uint32 (dev .EraseBlockSize ()) / m .blockSize
38
+ granularity := uint32 (dev .EraseBlockSize ()) / m .blockSizeUSB
37
39
binary .BigEndian .PutUint32 (vpdPages [i ].Data [24 :28 ], granularity )
38
40
}
39
41
if len (vpdPages [i ].Data ) >= 32 {
@@ -44,7 +46,7 @@ func (m *msc) RegisterBlockDevice(dev machine.BlockDevice) {
44
46
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
45
47
46
48
// We assume the block device is aligned to the end of the underlying block device
47
- blockOffset := uint32 (dev .EraseBlockSize ()) % m .blockSize
49
+ blockOffset := uint32 (dev .EraseBlockSize ()) % m .blockSizeUSB
48
50
binary .BigEndian .PutUint32 (vpdPages [i ].Data [28 :32 ], blockOffset )
49
51
}
50
52
break
@@ -56,7 +58,7 @@ var _ machine.BlockDevice = (*RecorderDisk)(nil)
56
58
57
59
// RecorderDisk is a block device that records actions taken on it
58
60
type RecorderDisk struct {
59
- data map [ int64 ][] byte
61
+ dev machine. BlockDevice
60
62
log []RecorderRecord
61
63
last time.Time
62
64
time time.Time
@@ -80,9 +82,9 @@ const (
80
82
)
81
83
82
84
// NewRecorderDisk creates a new RecorderDisk instance
83
- func NewRecorderDisk (count int ) * RecorderDisk {
85
+ func NewRecorderDisk (dev machine. BlockDevice , count int ) * RecorderDisk {
84
86
d := & RecorderDisk {
85
- data : make ( map [ int64 ][] byte ) ,
87
+ dev : dev ,
86
88
log : make ([]RecorderRecord , 0 , count ),
87
89
last : time .Now (),
88
90
}
@@ -91,95 +93,64 @@ func NewRecorderDisk(count int) *RecorderDisk {
91
93
OpCode : RecorderOpCodeRead ,
92
94
Offset : 0 ,
93
95
Length : 0 ,
94
- Data : make ([]byte , 0 , 64 ),
96
+ Data : make ([]byte , dev . WriteBlockSize () ),
95
97
Time : 0 ,
96
98
})
97
99
}
98
100
return d
99
101
}
100
102
101
103
func (d * RecorderDisk ) Size () int64 {
102
- return 4096 * int64 ( d . WriteBlockSize ()) // 2MB
104
+ return d . dev . Size ()
103
105
}
104
106
105
107
func (d * RecorderDisk ) WriteBlockSize () int64 {
106
- return 512 // 512 bytes
108
+ return d . dev . WriteBlockSize ()
107
109
}
108
110
109
111
func (d * RecorderDisk ) EraseBlockSize () int64 {
110
- return 2048 // 4 blocks of 512 bytes
112
+ return d . dev . EraseBlockSize ()
111
113
}
112
114
113
115
func (d * RecorderDisk ) EraseBlocks (startBlock , numBlocks int64 ) error {
114
116
d .Record (RecorderOpCodeEraseBlocks , startBlock , int (numBlocks ), []byte {})
115
- if interrupt .In () {
116
- // Flash erase commands are not allowed in interrupt context
117
- panic ("EraseBlocks attempted in interrupt context" )
118
- }
119
- return nil
117
+ return d .dev .EraseBlocks (startBlock , numBlocks )
120
118
}
121
119
122
120
func (d * RecorderDisk ) ReadAt (buffer []byte , offset int64 ) (int , error ) {
123
- d .Record (RecorderOpCodeRead , offset , len (buffer ), []byte {})
124
- sector := offset / d .WriteBlockSize ()
125
- if sector < 0 || offset + int64 (len (buffer )) > d .Size () {
126
- return 0 , fmt .Errorf ("read out of bounds: %d" , offset )
127
- }
128
-
129
- sectorCount := int64 (len (buffer )) / d .WriteBlockSize ()
130
- for i := int64 (0 ); i < sectorCount ; i ++ {
131
- if _ , ok := d .data [sector + i ]; ok {
132
- n := int (offset % d .WriteBlockSize ())
133
- copy (buffer , d .data [sector + i ][n :])
134
- }
135
- }
136
-
137
- return len (buffer ), nil
121
+ n , err := d .dev .ReadAt (buffer , offset )
122
+ d .Record (RecorderOpCodeRead , offset , n , buffer )
123
+ return n , err
138
124
}
139
125
140
126
func (d * RecorderDisk ) WriteAt (buffer []byte , offset int64 ) (int , error ) {
141
- if interrupt .In () {
142
- // Flash writes aren't possible in interrupt context
143
- panic ("WriteAt attempted in interrupt context" )
144
- }
145
- if offset < 0 || offset + int64 (len (buffer )) > d .Size () {
146
- return 0 , errWriteOutOfBounds
147
- }
148
-
149
- d .Record (RecorderOpCodeWrite , offset , len (buffer ), buffer )
150
-
151
- sector := offset / d .WriteBlockSize ()
152
- sectorCount := int64 (len (buffer )) / d .WriteBlockSize ()
153
- for i := int64 (0 ); i < sectorCount ; i ++ {
154
- _ , ok := d .data [sector + i ]
155
- if ! ok {
156
- d .data [sector + i ] = make ([]byte , d .WriteBlockSize ())
157
- }
158
- n := int (offset % d .WriteBlockSize ())
159
- copy (d .data [sector + i ][n :], buffer )
160
- }
161
- return len (buffer ), nil
127
+ n , err := d .dev .WriteAt (buffer , offset )
128
+ d .Record (RecorderOpCodeWrite , offset , n , buffer )
129
+ return n , err
162
130
}
163
131
164
132
func (d * RecorderDisk ) Record (opCode RecorderOpCode , offset int64 , length int , data []byte ) {
165
- n := len (d .log )
166
- if n == 0 {
167
- return
168
- } else if n == cap (d .log ) {
169
- for i := 0 ; i < n - 1 ; i ++ {
170
- d .log [i ] = d .log [i + 1 ]
171
- }
133
+ n := len (d .log ) - 1
134
+ // Shift the log entries up to make room for a new entry
135
+ for i := 0 ; i < n ; i ++ {
136
+ d .log [i ].OpCode = d .log [i + 1 ].OpCode
137
+ d .log [i ].Offset = d .log [i + 1 ].Offset
138
+ d .log [i ].Length = d .log [i + 1 ].Length
139
+ d .log [i ].Data = d .log [i ].Data [:len (d .log [i + 1 ].Data )]
140
+ copy (d .log [i ].Data , d .log [i + 1 ].Data )
141
+ d .log [i ].Time = d .log [i + 1 ].Time
142
+ d .log [i ].valid = d .log [i + 1 ].valid
172
143
}
173
144
174
145
// Append the new record
175
- d .log [n - 1 ].OpCode = opCode
176
- d .log [n - 1 ].Offset = offset
177
- d .log [n - 1 ].Length = length
178
- d .log [n - 1 ].Data = d .log [n - 1 ].Data [:len (data )]
179
- copy (d .log [n - 1 ].Data , data )
180
- d .log [n - 1 ].Time = time .Since (d .time ).Microseconds ()
146
+ d .log [n ].OpCode = opCode
147
+ d .log [n ].Offset = offset
148
+ d .log [n ].Length = length
149
+ d .log [n ].Data = d .log [n ].Data [:len (data )]
150
+ copy (d .log [n ].Data , data )
151
+ d .log [n ].Time = time .Since (d .time ).Microseconds ()
181
152
d .time = d .time .Add (time .Since (d .time ))
182
- d .log [n - 1 ].valid = true
153
+ d .log [n ].valid = true
183
154
}
184
155
185
156
func (d * RecorderDisk ) ClearLog () {
@@ -193,7 +164,7 @@ func (d *RecorderDisk) GetLog() []RecorderRecord {
193
164
return d .log
194
165
}
195
166
196
- func (r RecorderRecord ) String () (string , bool ) {
167
+ func (r * RecorderRecord ) String () (string , bool ) {
197
168
opCode := "Unknown"
198
169
switch r .OpCode {
199
170
case RecorderOpCodeRead :
@@ -203,5 +174,5 @@ func (r RecorderRecord) String() (string, bool) {
203
174
case RecorderOpCodeEraseBlocks :
204
175
opCode = "EraseBlocks"
205
176
}
206
- return fmt .Sprintf ("%s: %05d+%02d t:%d| % 0x" , opCode , r .Offset , r .Length , r .Time , r .Data ), r .valid
177
+ return fmt .Sprintf ("%s: %05d+%02d t:%d | % 0x" , opCode , r .Offset , r .Length , r .Time , r .Data ), r .valid
207
178
}
0 commit comments