github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/boot/kexec/memory_linux_test.go (about) 1 // Copyright 2018-2019 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 kexec 6 7 import ( 8 "bytes" 9 "fmt" 10 "io/ioutil" 11 "os" 12 "path" 13 "reflect" 14 "testing" 15 ) 16 17 func TestParseMemoryMap(t *testing.T) { 18 root, err := ioutil.TempDir("", "memmap") 19 if err != nil { 20 t.Fatalf("Cannot create test dir: %v", err) 21 } 22 defer os.RemoveAll(root) 23 24 create := func(dir string, start, end uintptr, typ RangeType) error { 25 p := path.Join(root, dir) 26 if err := os.Mkdir(p, 0755); err != nil { 27 return err 28 } 29 if err := ioutil.WriteFile(path.Join(p, "start"), []byte(fmt.Sprintf("%#x\n", start)), 0655); err != nil { 30 return err 31 } 32 if err := ioutil.WriteFile(path.Join(p, "end"), []byte(fmt.Sprintf("%#x\n", end)), 0655); err != nil { 33 return err 34 } 35 return ioutil.WriteFile(path.Join(p, "type"), append([]byte(typ), '\n'), 0655) 36 } 37 38 if err := create("0", 0, 49, RangeRAM); err != nil { 39 t.Fatal(err) 40 } 41 if err := create("1", 100, 149, RangeACPI); err != nil { 42 t.Fatal(err) 43 } 44 if err := create("2", 200, 249, RangeNVS); err != nil { 45 t.Fatal(err) 46 } 47 if err := create("3", 300, 349, RangeReserved); err != nil { 48 t.Fatal(err) 49 } 50 51 want := MemoryMap{ 52 {Range: Range{Start: 0, Size: 50}, Type: RangeRAM}, 53 {Range: Range{Start: 100, Size: 50}, Type: RangeACPI}, 54 {Range: Range{Start: 200, Size: 50}, Type: RangeNVS}, 55 {Range: Range{Start: 300, Size: 50}, Type: RangeReserved}, 56 } 57 58 phys, err := internalParseMemoryMap(root) 59 if err != nil { 60 t.Fatalf("ParseMemoryMap() error: %v", err) 61 } 62 if !reflect.DeepEqual(phys, want) { 63 t.Errorf("ParseMemoryMap() got %v, want %v", phys, want) 64 } 65 } 66 67 func TestAvailableRAM(t *testing.T) { 68 old := pageMask 69 defer func() { 70 pageMask = old 71 }() 72 // suppose we have 4K pages. 73 pageMask = 4095 74 75 var mem Memory 76 mem.Phys = MemoryMap{ 77 TypedRange{Range: Range{Start: 0, Size: 8192}, Type: RangeRAM}, 78 TypedRange{Range: Range{Start: 8192, Size: 8000}, Type: RangeRAM}, 79 TypedRange{Range: Range{Start: 20480, Size: 1000}, Type: RangeRAM}, 80 TypedRange{Range: Range{Start: 24576, Size: 1000}, Type: RangeRAM}, 81 TypedRange{Range: Range{Start: 28672, Size: 1000}, Type: RangeRAM}, 82 } 83 84 mem.Segments = []Segment{ 85 {Phys: Range{Start: 40, Size: 50}}, 86 {Phys: Range{Start: 8000, Size: 200}}, 87 {Phys: Range{Start: 18000, Size: 1000}}, 88 {Phys: Range{Start: 24600, Size: 1000}}, 89 {Phys: Range{Start: 28000, Size: 10000}}, 90 } 91 92 want := Ranges{ 93 Range{Start: 0, Size: 40}, 94 Range{Start: 4096, Size: 8000 - 4096}, 95 Range{Start: 12288, Size: 8192 + 8000 - 12288}, 96 Range{Start: 20480, Size: 1000}, 97 Range{Start: 24576, Size: 24}, 98 } 99 100 got := mem.AvailableRAM() 101 if !reflect.DeepEqual(got, want) { 102 t.Errorf("AvailableRAM() got %+v, want %+v", got, want) 103 } 104 } 105 106 func TestAlignPhys(t *testing.T) { 107 for _, test := range []struct { 108 name string 109 seg, want Segment 110 }{ 111 { 112 name: "aligned", 113 seg: Segment{ 114 Buf: Range{Start: 0x1000, Size: 0x1000}, 115 Phys: Range{Start: 0x2000, Size: 0x1000}, 116 }, 117 want: Segment{ 118 Buf: Range{Start: 0x1000, Size: 0x1000}, 119 Phys: Range{Start: 0x2000, Size: 0x1000}, 120 }, 121 }, 122 { 123 name: "unaligned", 124 seg: Segment{ 125 Buf: Range{Start: 0x1011, Size: 0x1022}, 126 Phys: Range{Start: 0x2011, Size: 0x1022}, 127 }, 128 want: Segment{ 129 Buf: Range{Start: 0x1000, Size: 0x1033}, 130 Phys: Range{Start: 0x2000, Size: 0x2000}, 131 }, 132 }, 133 { 134 name: "unaligned_size", 135 seg: Segment{ 136 Buf: Range{Start: 0x1000, Size: 0x1022}, 137 Phys: Range{Start: 0x2000, Size: 0x1022}, 138 }, 139 want: Segment{ 140 Buf: Range{Start: 0x1000, Size: 0x1022}, 141 Phys: Range{Start: 0x2000, Size: 0x2000}, 142 }, 143 }, 144 { 145 name: "empty_buf", 146 seg: Segment{ 147 Buf: Range{Start: 0x1011, Size: 0}, 148 Phys: Range{Start: 0x2011, Size: 0}, 149 }, 150 want: Segment{ 151 Buf: Range{Start: 0x1000, Size: 0}, 152 Phys: Range{Start: 0x2000, Size: 0x1000}, 153 }, 154 }, 155 } { 156 t.Run(test.name, func(t *testing.T) { 157 got := AlignPhys(test.seg) 158 if got != test.want { 159 t.Errorf("AlignPhys() got %v, want %v", got, test.want) 160 } 161 }) 162 } 163 } 164 165 func TestTryMerge(t *testing.T) { 166 for _, test := range []struct { 167 name string 168 phys Range 169 merged bool 170 want Range 171 }{ 172 { 173 name: "disjunct", 174 phys: Range{Start: 100, Size: 150}, 175 merged: false, 176 }, 177 { 178 name: "superset", 179 phys: Range{Start: 0, Size: 80}, 180 merged: true, 181 want: Range{Start: 0, Size: 100}, 182 }, 183 { 184 name: "superset", 185 phys: Range{Start: 10, Size: 80}, 186 merged: true, 187 want: Range{Start: 0, Size: 100}, 188 }, 189 { 190 name: "superset", 191 phys: Range{Start: 10, Size: 90}, 192 merged: true, 193 want: Range{Start: 0, Size: 100}, 194 }, 195 { 196 name: "superset", 197 phys: Range{Start: 0, Size: 100}, 198 merged: true, 199 want: Range{Start: 0, Size: 100}, 200 }, 201 { 202 name: "overlap", 203 phys: Range{Start: 0, Size: 150}, 204 merged: true, 205 want: Range{Start: 0, Size: 150}, 206 }, 207 { 208 name: "overlap", 209 phys: Range{Start: 50, Size: 100}, 210 merged: true, 211 want: Range{Start: 0, Size: 150}, 212 }, 213 { 214 name: "overlap", 215 phys: Range{Start: 99, Size: 51}, 216 merged: true, 217 want: Range{Start: 0, Size: 150}, 218 }, 219 } { 220 t.Run(test.name, func(t *testing.T) { 221 a := NewSegment([]byte("aaaa"), Range{Start: 0, Size: 100}) 222 b := NewSegment([]byte("bbbb"), test.phys) 223 224 merged := a.tryMerge(b) 225 if merged != test.merged { 226 t.Fatalf("tryMerge() got %v, want %v", merged, test.merged) 227 } 228 if !merged { 229 return 230 } 231 if a.Phys != test.want { 232 t.Fatalf("Wrong merge result: got %+v, want %+v", a.Phys, test.want) 233 } 234 235 got := a.Buf.toSlice() 236 want := []byte("aaaabbbb") 237 if !bytes.Equal(got, want) { 238 t.Errorf("Wrong buf: got %s, want %s", got, want) 239 } 240 }) 241 } 242 } 243 244 func TestDedup(t *testing.T) { 245 s := []Segment{ 246 NewSegment([]byte("test"), Range{Start: 0, Size: 100}), 247 NewSegment([]byte("test"), Range{Start: 100, Size: 100}), 248 NewSegment([]byte("test"), Range{Start: 200, Size: 100}), 249 NewSegment([]byte("test"), Range{Start: 250, Size: 50}), 250 NewSegment([]byte("test"), Range{Start: 300, Size: 100}), 251 NewSegment([]byte("test"), Range{Start: 350, Size: 100}), 252 } 253 want := []Range{ 254 {Start: 0, Size: 100}, 255 {Start: 100, Size: 100}, 256 {Start: 200, Size: 100}, 257 {Start: 300, Size: 150}, 258 } 259 260 got := Dedup(s) 261 for i := range got { 262 if got[i].Phys != want[i] { 263 t.Errorf("Dedup() got %v, want %v", got[i].Phys, want[i]) 264 } 265 } 266 } 267 268 func TestFindSpaceIn(t *testing.T) { 269 for i, tt := range []struct { 270 name string 271 rs Ranges 272 size uint 273 limit Range 274 want Range 275 err error 276 }{ 277 { 278 name: "no space above 0x1000", 279 rs: Ranges{ 280 Range{Start: 0x0, Size: 0x1000}, 281 }, 282 size: 0x10, 283 limit: RangeFromInterval(0x1000, MaxAddr), 284 err: ErrNotEnoughSpace{Size: 0x10}, 285 }, 286 { 287 name: "no space under 0x1000", 288 rs: Ranges{ 289 Range{Start: 0x1000, Size: 0x10}, 290 }, 291 size: 0x10, 292 limit: RangeFromInterval(0, 0x1000), 293 err: ErrNotEnoughSpace{Size: 0x10}, 294 }, 295 { 296 name: "disjunct space above 0x1000", 297 rs: Ranges{ 298 Range{Start: 0x0, Size: 0x1000}, 299 Range{Start: 0x1000, Size: 0x10}, 300 }, 301 size: 0x10, 302 limit: RangeFromInterval(0x1000, MaxAddr), 303 want: Range{Start: 0x1000, Size: 0x10}, 304 }, 305 { 306 name: "just enough space under 0x1000", 307 rs: Ranges{ 308 Range{Start: 0xFF, Size: 0xf}, 309 Range{Start: 0xFF0, Size: 0x10}, 310 Range{Start: 0x1000, Size: 0x10}, 311 }, 312 size: 0x10, 313 limit: RangeFromInterval(0, 0x1000), 314 want: Range{Start: 0xFF0, Size: 0x10}, 315 }, 316 { 317 name: "all spaces abvoe 0x1000 and under 0x2000 are too small", 318 rs: Ranges{ 319 Range{Start: 0x0, Size: 0x1000}, 320 Range{Start: 0x1000, Size: 0xf}, 321 Range{Start: 0x1010, Size: 0xf}, 322 Range{Start: 0x1f00, Size: 0xf}, 323 Range{Start: 0x2000, Size: 0x10}, 324 }, 325 size: 0x10, 326 limit: RangeFromInterval(0x1000, 0x2000), 327 err: ErrNotEnoughSpace{Size: 0x10}, 328 }, 329 { 330 name: "space is split across 0x1000, with enough space above", 331 rs: Ranges{ 332 Range{Start: 0x0, Size: 0x1010}, 333 }, 334 size: 0x10, 335 limit: RangeFromInterval(0x1000, MaxAddr), 336 want: Range{Start: 0x1000, Size: 0x10}, 337 }, 338 { 339 name: "space is split across 0x1000, with enough space under", 340 rs: Ranges{ 341 Range{Start: 0xFF0, Size: 0x20}, 342 }, 343 size: 0x10, 344 limit: RangeFromInterval(0, 0x1000), 345 want: Range{Start: 0xFF0, Size: 0x10}, 346 }, 347 { 348 name: "space is split across 0x1000 and 0x2000, but not enough space above or below", 349 rs: Ranges{ 350 Range{Start: 0xFF1, Size: 0xf + 0xf}, 351 Range{Start: 0x1FF1, Size: 0xf + 0xf}, 352 }, 353 size: 0x10, 354 limit: RangeFromInterval(0x1000, 0x2000), 355 err: ErrNotEnoughSpace{Size: 0x10}, 356 }, 357 { 358 name: "space is split across 0x1000, with enough space in the next one", 359 rs: Ranges{ 360 Range{Start: 0x0, Size: 0x100f}, 361 Range{Start: 0x1010, Size: 0x10}, 362 }, 363 size: 0x10, 364 limit: RangeFromInterval(0x1000, MaxAddr), 365 want: Range{Start: 0x1010, Size: 0x10}, 366 }, 367 { 368 name: "no ranges", 369 rs: Ranges{}, 370 size: 0x10, 371 limit: RangeFromInterval(0, MaxAddr), 372 err: ErrNotEnoughSpace{Size: 0x10}, 373 }, 374 { 375 name: "no ranges, zero size", 376 rs: Ranges{}, 377 size: 0, 378 limit: RangeFromInterval(0, MaxAddr), 379 err: ErrNotEnoughSpace{Size: 0}, 380 }, 381 } { 382 t.Run(fmt.Sprintf("test_%d_%s", i, tt.name), func(t *testing.T) { 383 got, err := tt.rs.FindSpaceIn(tt.size, tt.limit) 384 if !reflect.DeepEqual(got, tt.want) || err != tt.err { 385 t.Errorf("%s.FindSpaceIn(%#x, limit = %s) = (%#x, %v), want (%#x, %v)", tt.rs, tt.size, tt.limit, got, err, tt.want, tt.err) 386 } 387 }) 388 } 389 } 390 391 func TestIntersection(t *testing.T) { 392 for i, tt := range []struct { 393 r Range 394 r2 Range 395 wantOverlap bool 396 wantIntersect *Range 397 }{ 398 { 399 r: Range{Start: 0, Size: 50}, 400 r2: Range{Start: 49, Size: 1}, 401 wantOverlap: true, 402 wantIntersect: &Range{Start: 49, Size: 1}, 403 }, 404 { 405 r: Range{Start: 0, Size: 50}, 406 r2: Range{Start: 50, Size: 1}, 407 wantOverlap: false, 408 wantIntersect: nil, 409 }, 410 { 411 r: Range{Start: 49, Size: 1}, 412 r2: Range{Start: 0, Size: 50}, 413 wantOverlap: true, 414 wantIntersect: &Range{Start: 49, Size: 1}, 415 }, 416 { 417 r: Range{Start: 50, Size: 1}, 418 r2: Range{Start: 0, Size: 50}, 419 wantOverlap: false, 420 wantIntersect: nil, 421 }, 422 { 423 r: Range{Start: 0, Size: 50}, 424 r2: Range{Start: 10, Size: 1}, 425 wantOverlap: true, 426 wantIntersect: &Range{Start: 10, Size: 1}, 427 }, 428 { 429 r: Range{Start: 10, Size: 1}, 430 r2: Range{Start: 0, Size: 50}, 431 wantOverlap: true, 432 wantIntersect: &Range{Start: 10, Size: 1}, 433 }, 434 } { 435 t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { 436 if got := tt.r.Overlaps(tt.r2); got != tt.wantOverlap { 437 t.Errorf("%s.Overlaps(%s) = %v, want %v", tt.r, tt.r2, got, tt.wantOverlap) 438 } 439 if got := tt.r.Intersect(tt.r2); !reflect.DeepEqual(got, tt.wantIntersect) { 440 t.Errorf("%s.Intersect(%s) = %v, want %v", tt.r, tt.r2, got, tt.wantIntersect) 441 } 442 }) 443 } 444 } 445 446 func TestMinusRange(t *testing.T) { 447 for i, tt := range []struct { 448 r Range 449 r2 Range 450 want []Range 451 }{ 452 { 453 // r2 contained completely within r. 454 r: Range{Start: 0x100, Size: 0x200}, 455 r2: Range{Start: 0x150, Size: 0x50}, 456 want: []Range{ 457 {Start: 0x100, Size: 0x50}, 458 {Start: 0x1a0, Size: 0x160}, 459 }, 460 }, 461 { 462 // r contained completely within r2. 463 r: Range{Start: 0x100, Size: 0x50}, 464 r2: Range{Start: 0x90, Size: 0x100}, 465 want: nil, 466 }, 467 { 468 r: Range{Start: 0x100, Size: 0x50}, 469 r2: Range{Start: 0x100, Size: 0x100}, 470 want: nil, 471 }, 472 { 473 r: Range{Start: 0x100, Size: 0x50}, 474 r2: Range{Start: 0xf0, Size: 0x60}, 475 want: nil, 476 }, 477 { 478 // Overlaps to the right. 479 r: Range{Start: 0x100, Size: 0x100}, 480 r2: Range{Start: 0x150, Size: 0x100}, 481 want: []Range{ 482 {Start: 0x100, Size: 0x50}, 483 }, 484 }, 485 { 486 // Overlaps to the left. 487 r: Range{Start: 0x100, Size: 0x100}, 488 r2: Range{Start: 0x50, Size: 0x100}, 489 want: []Range{ 490 {Start: 0x150, Size: 0xb0}, 491 }, 492 }, 493 { 494 // Doesn't overlap at all. 495 r: Range{Start: 0x100, Size: 0x100}, 496 r2: Range{Start: 0x200, Size: 0x100}, 497 want: []Range{ 498 {Start: 0x100, Size: 0x100}, 499 }, 500 }, 501 } { 502 t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { 503 if got := tt.r.Minus(tt.r2); !reflect.DeepEqual(got, tt.want) { 504 t.Errorf("%s minus %s = %v, want %v", tt.r, tt.r2, got, tt.want) 505 } 506 }) 507 } 508 } 509 510 func TestContains(t *testing.T) { 511 for i, tt := range []struct { 512 r Range 513 p uintptr 514 want bool 515 }{ 516 { 517 r: Range{Start: 0, Size: 50}, 518 p: 50, 519 want: false, 520 }, 521 { 522 r: Range{Start: 0, Size: 50}, 523 p: 49, 524 want: true, 525 }, 526 { 527 r: Range{Start: 50, Size: 50}, 528 p: 49, 529 want: false, 530 }, 531 } { 532 t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { 533 if got := tt.r.Contains(tt.p); got != tt.want { 534 t.Errorf("%s.Contains(%#x) = %v, want %v", tt.r, tt.p, got, tt.want) 535 } 536 }) 537 } 538 } 539 540 func TestAdjacent(t *testing.T) { 541 for i, tt := range []struct { 542 r1 Range 543 r2 Range 544 want bool 545 }{ 546 { 547 r1: Range{Start: 0, Size: 50}, 548 r2: Range{Start: 50, Size: 50}, 549 want: true, 550 }, 551 { 552 r1: Range{Start: 0, Size: 40}, 553 r2: Range{Start: 41, Size: 50}, 554 want: false, 555 }, 556 { 557 r1: Range{Start: 10, Size: 40}, 558 r2: Range{Start: 0, Size: 10}, 559 want: true, 560 }, 561 { 562 r1: Range{Start: 10, Size: 39}, 563 r2: Range{Start: 40, Size: 50}, 564 want: false, 565 }, 566 } { 567 t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { 568 got1 := tt.r1.Adjacent(tt.r2) 569 got2 := tt.r2.Adjacent(tt.r1) 570 if got1 != tt.want { 571 t.Errorf("%s.Adjacent(%s) = %v, want %v", tt.r1, tt.r2, got1, tt.want) 572 } 573 if got2 != tt.want { 574 t.Errorf("%s.Adjacent(%s) = %v, want %v", tt.r2, tt.r1, got2, tt.want) 575 } 576 }) 577 } 578 } 579 580 func TestMemoryMapInsert(t *testing.T) { 581 for i, tt := range []struct { 582 m MemoryMap 583 r TypedRange 584 want MemoryMap 585 }{ 586 { 587 // r is entirely within m's one range. 588 m: MemoryMap{ 589 TypedRange{Range: Range{Start: 0, Size: 0x2000}, Type: RangeRAM}, 590 }, 591 r: TypedRange{Range: Range{Start: 0x100, Size: 0x100}, Type: RangeReserved}, 592 want: MemoryMap{ 593 TypedRange{Range: Range{Start: 0, Size: 0x100}, Type: RangeRAM}, 594 TypedRange{Range: Range{Start: 0x100, Size: 0x100}, Type: RangeReserved}, 595 TypedRange{Range: Range{Start: 0x200, Size: 0x2000 - 0x200}, Type: RangeRAM}, 596 }, 597 }, 598 { 599 // r sits across three RAM ranges. 600 m: MemoryMap{ 601 TypedRange{Range: Range{Start: 0, Size: 0x150}, Type: RangeRAM}, 602 TypedRange{Range: Range{Start: 0x150, Size: 0x50}, Type: RangeRAM}, 603 TypedRange{Range: Range{Start: 0x1a0, Size: 0x100}, Type: RangeRAM}, 604 }, 605 r: TypedRange{Range: Range{Start: 0x100, Size: 0x100}, Type: RangeReserved}, 606 want: MemoryMap{ 607 TypedRange{Range: Range{Start: 0, Size: 0x100}, Type: RangeRAM}, 608 TypedRange{Range: Range{Start: 0x100, Size: 0x100}, Type: RangeReserved}, 609 TypedRange{Range: Range{Start: 0x200, Size: 0xa0}, Type: RangeRAM}, 610 }, 611 }, 612 { 613 // r is a superset of the ranges in m. 614 m: MemoryMap{ 615 TypedRange{Range: Range{Start: 0x100, Size: 0x50}, Type: RangeRAM}, 616 }, 617 r: TypedRange{Range: Range{Start: 0x100, Size: 0x100}, Type: RangeReserved}, 618 want: MemoryMap{ 619 TypedRange{Range: Range{Start: 0x100, Size: 0x100}, Type: RangeReserved}, 620 }, 621 }, 622 { 623 // r is the first range in the map. 624 m: MemoryMap{}, 625 r: TypedRange{Range: Range{Start: 0x100, Size: 0x100}, Type: RangeReserved}, 626 want: MemoryMap{ 627 TypedRange{Range: Range{Start: 0x100, Size: 0x100}, Type: RangeReserved}, 628 }, 629 }, 630 } { 631 t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { 632 // Make a copy for the Errorf print. 633 m := tt.m 634 tt.m.Insert(tt.r) 635 636 if !reflect.DeepEqual(tt.m, tt.want) { 637 t.Errorf("\n%v.Insert(%s) =\n%v, want\n%v", m, tt.r, tt.m, tt.want) 638 } 639 }) 640 } 641 } 642 643 func TestSegmentsInsert(t *testing.T) { 644 for i, tt := range []struct { 645 segs Segments 646 s Segment 647 want Segments 648 }{ 649 { 650 segs: Segments{ 651 Segment{Phys: Range{Start: 0x2000, Size: 0x20}}, 652 Segment{Phys: Range{Start: 0x4000, Size: 0x20}}, 653 }, 654 s: Segment{Phys: Range{Start: 0x3000, Size: 0x20}}, 655 want: Segments{ 656 Segment{Phys: Range{Start: 0x2000, Size: 0x20}}, 657 Segment{Phys: Range{Start: 0x3000, Size: 0x20}}, 658 Segment{Phys: Range{Start: 0x4000, Size: 0x20}}, 659 }, 660 }, 661 { 662 segs: Segments{}, 663 s: Segment{Phys: Range{Start: 0x3000, Size: 0x20}}, 664 want: Segments{ 665 Segment{Phys: Range{Start: 0x3000, Size: 0x20}}, 666 }, 667 }, 668 } { 669 t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { 670 before := tt.segs 671 tt.segs.Insert(tt.s) 672 673 if !reflect.DeepEqual(tt.segs, tt.want) { 674 t.Errorf("\n%v.Insert(%v) = \n%v, want \n%v", before, tt.s, tt.segs, tt.want) 675 } 676 }) 677 } 678 }