github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/exp/cbmem/cbmem_linux_test.go (about) 1 // Copyright 2021 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "encoding/hex" 10 "encoding/json" 11 "io" 12 "os" 13 "path/filepath" 14 "testing" 15 ) 16 17 func TestNotFound(t *testing.T) { 18 var err error 19 f, err := os.CreateTemp("", "cbmemNotFound") 20 if err != nil { 21 t.Fatal(err) 22 } 23 if _, err := f.Write(make([]byte, 0x100000)); err != nil { 24 t.Fatalf("Writing empty file: got %v, want nil", err) 25 } 26 var found bool 27 for _, addr := range []int64{0, 0xf0000} { 28 t.Logf("Check %#08x", addr) 29 if _, found, err = parseCBtable(f, addr, 0x10000); err == nil { 30 break 31 } 32 } 33 if err != nil { 34 t.Errorf("Scanning empty file: got %v, want nil", err) 35 } 36 if found { 37 t.Fatalf("Found a coreboot table in empty file: got nil, want err") 38 } 39 } 40 41 func genFile(f *os.File, p func(string, ...interface{}), s []seg) error { 42 // Extend the test file to the full 4G, to match hardware. 43 if _, err := f.WriteAt([]byte{1}[:], 0xffffffff); err != nil { 44 return err 45 } 46 for _, r := range s { 47 p("Write %d bytes at %#x", len(r.dat), r.off) 48 if _, err := f.WriteAt(r.dat, r.off); err != nil { 49 return err 50 } 51 } 52 return nil 53 } 54 55 func TestAPU2(t *testing.T) { 56 var err error 57 f, err := os.CreateTemp("", "cbmemAPU2") 58 if err != nil { 59 t.Fatal(err) 60 } 61 if err := genFile(f, t.Logf, apu2); err != nil { 62 t.Fatal(err) 63 } 64 var c *CBmem 65 var found bool 66 for _, addr := range []int64{0, 0xf0000} { 67 t.Logf("Check %#08x", addr) 68 if c, found, err = parseCBtable(f, addr, 0x10000); err == nil { 69 break 70 } 71 } 72 if !found { 73 t.Fatalf("Looking for coreboot table: got false, want true") 74 } 75 if err != nil { 76 t.Fatalf("Reading coreboot table: got %v, want nil", err) 77 } 78 b := &bytes.Buffer{} 79 DumpMem(f, c, false, b) 80 t.Logf("%s", b.String()) 81 o := b.String() 82 if o != apu2Mem { 83 t.Errorf("APU2 DumpMem: got \n%s\n, want \n%s\n", hex.Dump(b.Bytes()), hex.Dump([]byte(apu2Mem))) 84 } 85 b.Reset() 86 DumpMem(f, c, true, b) 87 t.Logf("2nd dump string is %s", b.String()) 88 if b.Len() == len(apu2Mem) { 89 t.Errorf("APU2 DumpMem: got %d bytes output, want more", b.Len()) 90 } 91 // See if JSON even works. TODO: compare output 92 j, err := json.MarshalIndent(c, "", "\t") 93 if err != nil { 94 t.Fatalf("json marshal: %v", err) 95 } 96 // You can use this to generate new test data. It's a timesaver. 97 if false { 98 os.WriteFile("json", j, 0o666) 99 } 100 if string(j) != apu2JSON { 101 t.Errorf("APU2 JSON: got %s, want %s", j, apu2JSON) 102 } 103 } 104 105 func TestAPU2CBMemWrap(t *testing.T) { 106 var err error 107 f, err := os.CreateTemp("", "cbmemWRAPAPU2") 108 if err != nil { 109 t.Fatal(err) 110 } 111 // Need to patch this a bit. First, add a patch so that the cursor has wrapped. 112 p := apu2 113 if true { 114 p = append(p, []seg{ 115 { 116 // The buffer size will be 4, and the cursor will be 2 -> wrap. 117 off: 0x77fdf000, dat: []byte{ 118 0x04 /*'ø'*/, 0x00 /*'ÿ'*/, 0x00 /*'\x01'*/, 0x00 /*'\x00'*/, 0x02 /*'\x02' */, 0x00 /*'\x00'*/, 0x00 /*'\x00'*/, 0x80, /*'\x80'*/ 119 }, 120 }, 121 }...) 122 } 123 if err := genFile(f, t.Logf, p); err != nil { 124 t.Fatal(err) 125 } 126 var c *CBmem 127 var found bool 128 if c, found, err = parseCBtable(f, 0, 0x10000); err != nil { 129 t.Fatalf("reading CB table: got %v, want nil", err) 130 } 131 if !found { 132 t.Fatalf("Looking for coreboot table: got false, want true") 133 } 134 want := "EnPC" 135 got := c.MemConsole.Data 136 if got != want { 137 t.Fatalf("Console data: got %q, want %q", got, want) 138 } 139 } 140 141 func TestAPU2CBBadCursor(t *testing.T) { 142 var err error 143 f, err := os.CreateTemp("", "cbmemWRAPAPU2") 144 if err != nil { 145 t.Fatal(err) 146 } 147 // Need to patch this a bit. First, add a patch so that the cursor has wrapped. 148 p := apu2 149 p = append(p, []seg{ 150 { 151 // The buffer size will be 4, and the cursor will be 2 -> wrap. 152 off: 0x77fdf000, dat: []byte{ 153 /*0x77fdf000*/ 0x04 /*'ø'*/, 0x00 /*'ÿ'*/, 0x00 /*'\x01'*/, 0x00 /*'\x00'*/, 0x0a /*'\x0a'*/, 0x00 /*'\x00'*/, 0x00 /*'\x00'*/, 0x80, /*'\x80'*/ 154 }, 155 }, 156 }...) 157 158 if err := genFile(f, t.Logf, p); err != nil { 159 t.Fatal(err) 160 } 161 var c *CBmem 162 var found bool 163 if c, found, err = parseCBtable(f, 0, 0x10000); err != nil { 164 t.Fatalf("reading CB table: got %v, want nil", err) 165 } 166 if !found { 167 t.Fatalf("Looking for coreboot table: got false, want true") 168 } 169 want := "PCEn" 170 got := c.MemConsole.Data 171 if got != want { 172 t.Fatalf("Console data: got %q, want %q", got, want) 173 } 174 } 175 176 func TestAPU2CBBadPtr(t *testing.T) { 177 var err error 178 f, err := os.CreateTemp("", "cbmemWRAPAPU2") 179 if err != nil { 180 t.Fatal(err) 181 } 182 // Need to patch this a bit. First, add a patch so that the cursor has wrapped. 183 p := apu2 184 p = append(p, []seg{ 185 { 186 off: 0x77fae170, dat: []byte{ 187 0xff, 0xff, 0xff, 0xff, 188 }, 189 }, 190 }...) 191 if err := genFile(f, t.Logf, p); err != nil { 192 t.Fatal(err) 193 } 194 if _, _, err = parseCBtable(f, 0, 0x10000); err == nil { 195 t.Fatalf("reading CB table: got nil, want err") 196 } 197 } 198 199 func TestIO(t *testing.T) { 200 var ( 201 b = [8]byte{1} 202 i uint64 203 ) 204 if err := readOneSize(bytes.NewReader(b[:1]), &i, 1, 23); err == nil { 205 t.Errorf("readOne on too small buffer: got nil, want err") 206 } 207 if err := readOneSize(bytes.NewReader(b[:]), &i, 0, 8); err != nil { 208 t.Fatalf("readOne: got %v, want nil", err) 209 } 210 if i != 1 { 211 t.Fatalf("readOne value: got %d, want 1", i) 212 } 213 } 214 215 func TestOffsetReader(t *testing.T) { 216 memFile, err := os.CreateTemp("", "cbmemAPU2") 217 if err != nil { 218 t.Fatal(err) 219 } 220 if err := genFile(memFile, t.Logf, apu2); err != nil { 221 t.Fatal(err) 222 } 223 o, err := newOffsetReader(memFile, 0x77fdf040, 1) 224 if err != nil { 225 t.Fatalf("newOffsetReader: got %v, want nil", err) 226 } 227 var b [9]byte 228 for _, i := range []int64{0x8000000000, -1, 0x77fdf03f} { 229 _, err := o.ReadAt(b[:], i) 230 if err == nil { 231 t.Errorf("Reading newOffsetReader at %#x: got nil, want err", i) 232 } 233 } 234 for _, i := range []int64{0x77fdf040} { 235 n, err := o.ReadAt(b[:], i) 236 if err != io.EOF { 237 t.Errorf("Reading newOffsetReader at %#x: got %v, want io.EOF", i, err) 238 } 239 if n != 1 { 240 t.Errorf("Reading newOffsetReader at %#x: got %d bytes, want nil", i, n) 241 } 242 } 243 244 // Now find the LBIO at 0x77fae000 245 if o, err = newOffsetReader(memFile, 0x77fae000, 8); err != nil { 246 t.Fatalf("newOffsetReader: got %v, want nil", err) 247 } 248 for _, i := range []int64{0x77fae000} { 249 _, err := o.ReadAt(b[:], i) 250 if err == nil { 251 t.Errorf("Reading newOffsetReader at %#x: got nil, want err", i) 252 } 253 if string(b[:4]) != "LBIO" { 254 t.Errorf("Reading newOffsetReader at %#x: got %q, want LBIO", 0x77fae000, string(b[:4])) 255 } 256 } 257 if err := memFile.Close(); err != nil { 258 t.Fatalf("Closing %s: got %v, want nil", memFile.Name(), err) 259 } 260 if _, err := newOffsetReader(memFile, 0x77fdf040, 1); err == nil { 261 t.Fatalf("newOffsetReader: got nil, want err") 262 } 263 } 264 265 func TestTimeStampsAPU2(t *testing.T) { 266 f, err := os.CreateTemp("", "cbmemAPU2") 267 if err != nil { 268 t.Fatal(err) 269 } 270 if err := genFile(f, t.Logf, apu2); err != nil { 271 t.Fatal(err) 272 } 273 var c *CBmem 274 var found bool 275 for _, addr := range []int64{0, 0xf0000} { 276 t.Logf("Check %#08x", addr) 277 if c, found, err = parseCBtable(f, addr, 0x10000); err == nil { 278 break 279 } 280 } 281 if !found { 282 t.Fatalf("Looking for coreboot table: got false, want true") 283 } 284 if err != nil { 285 t.Fatalf("Reading coreboot table: got %v, want nil", err) 286 } 287 if c.TimeStampsTable.Addr != 0 { 288 t.Fatalf("TimeStampsTable: got %#x, want 0", c.TimeStampsTable) 289 } 290 } 291 292 func TestCbmem(t *testing.T) { 293 for _, tt := range []struct { 294 name string 295 mem string 296 version bool 297 verbose bool 298 timestamps bool 299 dumpJSON bool 300 list bool 301 console bool 302 want string 303 }{ 304 { 305 name: "version true", 306 version: true, 307 want: "cbmem in Go, including JSON output\n", 308 }, 309 { 310 name: "verbose true", 311 verbose: true, 312 }, 313 { 314 name: "dumpJSON true", 315 dumpJSON: true, 316 want: "{\n\t\"Memory\": {\n\t\t\"Tag\": 1,\n\t\t\"Size\": 108,\n\t\t\"Maps\": [\n\t\t\t{\n\t\t\t\t\"Start\": 0,\n\t\t\t\t\"Size\": 4096,\n\t\t\t\t\"Mtype\": 16\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Start\": 4096,\n\t\t\t\t\"Size\": 651264,\n\t\t\t\t\"Mtype\": 1\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Start\": 786432,\n\t\t\t\t\"Size\": 2012143616,\n\t\t\t\t\"Mtype\": 1\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Start\": 2012930048,\n\t\t\t\t\"Size\": 335872,\n\t\t\t\t\"Mtype\": 16\n\t\t\t}\n\t\t]\n\t},\n\t\"MemConsole\": {\n\t\t\"Tag\": 23,\n\t\t\"Size\": 131064,\n\t\t\"Address\": 2013130752,\n\t\t\"CSize\": 0,\n\t\t\"Cursor\": 240,\n\t\t\"Data\": \"PCEngines apu2\\r\\ncoreboot build 20170228\\r\\n2032 MB DRAM\\r\\n\\r\\n\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\"\n\t},\n\t\"Consoles\": [\n\t\t\"\"\n\t],\n\t\"TimeStampsTable\": {\n\t\t\"Tag\": 0,\n\t\t\"Size\": 0,\n\t\t\"Addr\": 0\n\t},\n\t\"TimeStamps\": null,\n\t\"UART\": [\n\t\t{\n\t\t\t\"Tag\": 15,\n\t\t\t\"Size\": 20,\n\t\t\t\"Type\": 1,\n\t\t\t\"BaseAddr\": 1016,\n\t\t\t\"Baud\": 115200,\n\t\t\t\"RegWidth\": 16\n\t\t}\n\t],\n\t\"MainBoard\": {\n\t\t\"Tag\": 3,\n\t\t\"Size\": 40,\n\t\t\"Vendor\": \"PC Engines\",\n\t\t\"PartNumber\": \"PCEngines apu2\"\n\t},\n\t\"Hwrpb\": {\n\t\t\"Tag\": 0,\n\t\t\"Size\": 0,\n\t\t\"HwrPB\": 0\n\t},\n\t\"CBMemory\": null,\n\t\"BoardID\": {\n\t\t\"Tag\": 37,\n\t\t\"Size\": 16,\n\t\t\"BoardID\": 2012962816\n\t},\n\t\"StringVars\": {\n\t\t\"LB_TAG_BUILD\": \"Tue Feb 28 22:34:13 UTC 2017\",\n\t\t\"LB_TAG_COMPILE_BY\": \"root\",\n\t\t\"LB_TAG_COMPILE_DOMAIN\": \"\",\n\t\t\"LB_TAG_COMPILE_HOST\": \"3aa919ff57dc\",\n\t\t\"LB_TAG_COMPILE_TIME\": \"22:34:13\",\n\t\t\"LB_TAG_EXTRA_VERSION\": \"-4.0.7\",\n\t\t\"LB_TAG_VERSION\": \"8b10004\"\n\t},\n\t\"BootMediaParams\": {\n\t\t\"Tag\": 0,\n\t\t\"Size\": 0,\n\t\t\"FMAPOffset\": 0,\n\t\t\"CBFSOffset\": 0,\n\t\t\"CBFSSize\": 0,\n\t\t\"BootMediaSize\": 0\n\t},\n\t\"VersionTimeStamp\": 38,\n\t\"Unknown\": null,\n\t\"Ignored\": null\n}\n", 317 }, 318 { 319 name: "list true", 320 list: true, 321 }, 322 { 323 name: "console true", 324 console: true, 325 want: "PCEngines apu2\r\ncoreboot build 20170228\r\n2032 MB DRAM\r\n\r\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 326 }, 327 } { 328 t.Run(tt.name, func(t *testing.T) { 329 f, err := os.Create(filepath.Join(t.TempDir(), "cbmemAPU2")) 330 if err != nil { 331 t.Errorf("could not gen file: %v", err) 332 } 333 defer f.Close() 334 if err := genFile(f, t.Logf, apu2); err != nil { 335 t.Errorf("could not gen file: %v", err) 336 } 337 338 *mem = f.Name() 339 version = tt.version 340 verbose = tt.verbose 341 timestamps = tt.timestamps 342 dumpJSON = tt.dumpJSON 343 list = tt.list 344 console = tt.console 345 346 buf := &bytes.Buffer{} 347 348 got := cbMem(buf) 349 if got != nil { 350 if got.Error() != tt.want { 351 t.Errorf("cbmem() = %q, want: %q", got.Error(), tt.want) 352 } 353 } else { 354 if buf.String() != tt.want { 355 t.Errorf("cbmem() = %q, want: %q", buf.String(), tt.want) 356 } 357 } 358 }) 359 } 360 }