github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/pkg/kexec/memory_linux.go (about) 1 // Copyright 2015-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 "debug/elf" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "log" 13 "os" 14 "path" 15 "path/filepath" 16 "reflect" 17 "sort" 18 "strconv" 19 "strings" 20 "unsafe" 21 ) 22 23 var pageMask = uint(os.Getpagesize() - 1) 24 25 // ErrNotEnoughSpace is returned by the FindSpace family of functions if no 26 // range is large enough to accommodate the request. 27 type ErrNotEnoughSpace struct { 28 Size uint 29 } 30 31 func (e ErrNotEnoughSpace) Error() string { 32 return fmt.Sprintf("not enough space to allocate %#x bytes", e.Size) 33 } 34 35 // Range represents a contiguous uintptr interval [Start, Start+Size). 36 type Range struct { 37 // Start is the inclusive start of the range. 38 Start uintptr 39 40 // Size is the number of elements in the range. 41 // 42 // Start+Size is the exclusive end of the range. 43 Size uint 44 } 45 46 // RangeFromInterval returns a Range representing [start, end). 47 func RangeFromInterval(start, end uintptr) Range { 48 return Range{ 49 Start: start, 50 Size: uint(end - start), 51 } 52 } 53 54 // String returns [Start, Start+Size) as a string. 55 func (r Range) String() string { 56 return fmt.Sprintf("[%#x, %#x)", r.Start, r.End()) 57 } 58 59 // End returns the uintptr *after* the end of the interval. 60 func (r Range) End() uintptr { 61 return r.Start + uintptr(r.Size) 62 } 63 64 // Adjacent returns true if r and r2 do not overlap, but are immediately next 65 // to each other. 66 func (r Range) Adjacent(r2 Range) bool { 67 return r2.End() == r.Start || r.End() == r2.Start 68 } 69 70 // Contains returns true iff p is in the interval described by r. 71 func (r Range) Contains(p uintptr) bool { 72 return r.Start <= p && p < r.End() 73 } 74 75 func min(a, b uintptr) uintptr { 76 if a < b { 77 return a 78 } 79 return b 80 } 81 82 func max(a, b uintptr) uintptr { 83 if a > b { 84 return a 85 } 86 return b 87 } 88 89 // Intersect returns the continuous range of points common to r and r2 if there 90 // is one. 91 func (r Range) Intersect(r2 Range) *Range { 92 if !r.Overlaps(r2) { 93 return nil 94 } 95 i := RangeFromInterval(max(r.Start, r2.Start), min(r.End(), r2.End())) 96 return &i 97 } 98 99 // Minus removes all points in r2 from r. 100 func (r Range) Minus(r2 Range) []Range { 101 var result []Range 102 if r.Contains(r2.Start) && r.Start != r2.Start { 103 result = append(result, Range{ 104 Start: r.Start, 105 Size: uint(r2.Start - r.Start), 106 }) 107 } 108 if r.Contains(r2.End()) && r.End() != r2.End() { 109 result = append(result, Range{ 110 Start: r2.End(), 111 Size: uint(r.End() - r2.End()), 112 }) 113 } 114 // Neither end was in r? 115 // 116 // Either r is a subset of r2 and r disappears completely, or they are 117 // completely disjunct. 118 if len(result) == 0 && r.Disjunct(r2) { 119 result = append(result, r) 120 } 121 return result 122 } 123 124 // Overlaps returns true if r and r2 overlap. 125 func (r Range) Overlaps(r2 Range) bool { 126 return r.Start < r2.End() && r2.Start < r.End() 127 } 128 129 // IsSupersetOf returns true if r2 in r. 130 func (r Range) IsSupersetOf(r2 Range) bool { 131 return r.Start <= r2.Start && r.End() >= r2.End() 132 } 133 134 // Disjunct returns true if r and r2 do not overlap. 135 func (r Range) Disjunct(r2 Range) bool { 136 return !r.Overlaps(r2) 137 } 138 139 func (r Range) toSlice() []byte { 140 var data []byte 141 142 sh := (*reflect.SliceHeader)(unsafe.Pointer(&data)) 143 sh.Data = r.Start 144 sh.Len = int(r.Size) 145 sh.Cap = int(r.Size) 146 147 return data 148 } 149 150 // Ranges is a list of non-overlapping ranges. 151 type Ranges []Range 152 153 // Minus removes all points in r from all ranges in rs. 154 func (rs Ranges) Minus(r Range) Ranges { 155 var ram Ranges 156 for _, oldRange := range rs { 157 ram = append(ram, oldRange.Minus(r)...) 158 } 159 return ram 160 } 161 162 // FindSpace finds a continguous piece of sz points within Ranges and returns 163 // the Range pointing to it. 164 func (rs Ranges) FindSpace(sz uint) (space Range, err error) { 165 return rs.FindSpaceAbove(sz, 0) 166 } 167 168 // MaxAddr is the highest address in a 64bit address space. 169 const MaxAddr = ^uintptr(0) 170 171 // FindSpaceAbove finds a continguous piece of sz points within Ranges and 172 // returns a space.Start >= minAddr. 173 func (rs Ranges) FindSpaceAbove(sz uint, minAddr uintptr) (space Range, err error) { 174 return rs.FindSpaceIn(sz, RangeFromInterval(minAddr, MaxAddr)) 175 } 176 177 // FindSpaceIn finds a continguous piece of sz points within Ranges and returns 178 // a Range where space.Start >= limit.Start, with space.End() < limit.End(). 179 func (rs Ranges) FindSpaceIn(sz uint, limit Range) (space Range, err error) { 180 for _, r := range rs { 181 if overlap := r.Intersect(limit); overlap != nil && overlap.Size >= sz { 182 return Range{Start: overlap.Start, Size: sz}, nil 183 } 184 } 185 return Range{}, ErrNotEnoughSpace{Size: sz} 186 } 187 188 // Sort sorts ranges by their start point. 189 func (rs Ranges) Sort() { 190 sort.Slice(rs, func(i, j int) bool { 191 return rs[i].Start < rs[j].Start 192 }) 193 } 194 195 // pool stores byte slices pointed by the pointers Segments.Buf to 196 // prevent underlying arrays to be collected by garbage collector. 197 var pool [][]byte 198 199 // Segment defines kernel memory layout. 200 type Segment struct { 201 // Buf is a buffer in user space. 202 Buf Range 203 204 // Phys is a physical address of kernel. 205 Phys Range 206 } 207 208 // NewSegment creates new Segment. 209 // Segments should be created using NewSegment method to prevent 210 // data pointed by Segment.Buf to be collected by garbage collector. 211 func NewSegment(buf []byte, phys Range) Segment { 212 pool = append(pool, buf) 213 return Segment{ 214 Buf: Range{ 215 Start: uintptr((unsafe.Pointer(&buf[0]))), 216 Size: uint(len(buf)), 217 }, 218 Phys: phys, 219 } 220 } 221 222 func (s Segment) String() string { 223 return fmt.Sprintf("(virt: %s, phys: %s)", s.Buf, s.Phys) 224 } 225 226 func (s *Segment) tryMerge(s2 Segment) (ok bool) { 227 if s.Phys.Disjunct(s2.Phys) { 228 return false 229 } 230 231 // Virtual memory ranges should never overlap, 232 // concatenate ranges. 233 a := s.Buf.toSlice() 234 b := s2.Buf.toSlice() 235 c := append(a, b...) 236 237 phys := s.Phys 238 // s1 and s2 overlap somewhat. 239 if !s.Phys.IsSupersetOf(s2.Phys) { 240 phys.Size = uint(s2.Phys.Start-s.Phys.Start) + s2.Phys.Size 241 } 242 243 *s = NewSegment(c, phys) 244 return true 245 } 246 247 func alignUp(p uint) uint { 248 return (p + pageMask) &^ pageMask 249 } 250 251 func alignUpPtr(p uintptr) uintptr { 252 return uintptr(alignUp(uint(p))) 253 } 254 255 // AlignPhys fixes s to the kexec_load preconditions. 256 // 257 // s's physical addresses must be multiples of the page size. 258 // 259 // E.g. if page size is 0x1000: 260 // Segment { 261 // Buf: {Start: 0x1011, Size: 0x1022} 262 // Phys: {Start: 0x2011, Size: 0x1022} 263 // } 264 // has to become 265 // Segment { 266 // Buf: {Start: 0x1000, Size: 0x1033} 267 // Phys: {Start: 0x2000, Size: 0x2000} 268 // } 269 func AlignPhys(s Segment) Segment { 270 orig := s.Phys.Start 271 // Find the page address of the starting point. 272 s.Phys.Start = s.Phys.Start &^ uintptr(pageMask) 273 274 diff := orig - s.Phys.Start 275 276 // Round up to page size. 277 s.Phys.Size = alignUp(s.Phys.Size + uint(diff)) 278 279 if s.Buf.Start < diff && diff > 0 { 280 panic("cannot have virtual memory address within first page") 281 } 282 s.Buf.Start -= diff 283 284 if s.Buf.Size > 0 { 285 s.Buf.Size += uint(diff) 286 } 287 return s 288 } 289 290 // Segments is a collection of segments. 291 type Segments []Segment 292 293 // PhysContains returns whether p exists in any of segs' physical memory 294 // ranges. 295 func (segs Segments) PhysContains(p uintptr) bool { 296 for _, s := range segs { 297 if s.Phys.Contains(p) { 298 return true 299 } 300 } 301 return false 302 } 303 304 // Insert inserts s assuming it does not overlap with an existing segment. 305 func (segs *Segments) Insert(s Segment) { 306 *segs = append(*segs, s) 307 segs.sort() 308 } 309 310 func (segs Segments) sort() { 311 sort.Slice(segs, func(i, j int) bool { 312 return segs[i].Phys.Start < segs[j].Phys.Start 313 }) 314 } 315 316 // Dedup deduplicates overlapping and merges adjacent segments in segs. 317 func Dedup(segs Segments) Segments { 318 var s Segments 319 sort.Slice(segs, func(i, j int) bool { 320 if segs[i].Phys.Start == segs[j].Phys.Start { 321 // let segs[i] be the superset of segs[j] 322 return segs[i].Phys.Size > segs[j].Phys.Size 323 } 324 return segs[i].Phys.Start < segs[j].Phys.Start 325 }) 326 327 for _, seg := range segs { 328 doIt := true 329 for i := range s { 330 if merged := s[i].tryMerge(seg); merged { 331 doIt = false 332 break 333 } 334 } 335 if doIt { 336 s = append(s, seg) 337 } 338 } 339 return s 340 } 341 342 // Memory provides routines to work with physical memory ranges. 343 type Memory struct { 344 // Phys defines the layout of physical memory. 345 // 346 // Phys is used to tell loaded operating systems what memory is usable 347 // as RAM, and what memory is reserved (for ACPI or other reasons). 348 Phys MemoryMap 349 350 // Segments are the segments used to load a new operating system. 351 // 352 // Each segment also contains a physical memory region it maps to. 353 Segments Segments 354 } 355 356 // LoadElfSegments loads loadable ELF segments. 357 func (m *Memory) LoadElfSegments(r io.ReaderAt) error { 358 f, err := elf.NewFile(r) 359 if err != nil { 360 return err 361 } 362 363 for _, p := range f.Progs { 364 if p.Type != elf.PT_LOAD { 365 continue 366 } 367 368 d := make([]byte, p.Filesz) 369 n, err := r.ReadAt(d, int64(p.Off)) 370 if err != nil { 371 return err 372 } 373 if n < len(d) { 374 return fmt.Errorf("not all data of the segment was read") 375 } 376 // TODO(hugelgupf): check if this is within availableRAM?? 377 s := NewSegment(d, Range{ 378 Start: uintptr(p.Paddr), 379 Size: uint(p.Memsz), 380 }) 381 m.Segments.Insert(s) 382 } 383 return nil 384 } 385 386 // ParseMemoryMap reads firmware provided memory map from /sys/firmware/memmap. 387 func (m *Memory) ParseMemoryMap() error { 388 p, err := ParseMemoryMap() 389 if err != nil { 390 return err 391 } 392 m.Phys = p 393 return nil 394 } 395 396 var memoryMapRoot = "/sys/firmware/memmap/" 397 398 // ParseMemoryMap reads firmware provided memory map from /sys/firmware/memmap. 399 func ParseMemoryMap() (MemoryMap, error) { 400 return internalParseMemoryMap(memoryMapRoot) 401 } 402 403 func internalParseMemoryMap(memoryMapDir string) (MemoryMap, error) { 404 type memRange struct { 405 // start and end addresses are inclusive 406 start, end uintptr 407 typ RangeType 408 } 409 410 ranges := make(map[string]memRange) 411 walker := func(name string, info os.FileInfo, err error) error { 412 if err != nil { 413 return err 414 } 415 if info.IsDir() { 416 return nil 417 } 418 419 const ( 420 // file names 421 start = "start" 422 end = "end" 423 typ = "type" 424 ) 425 426 base := path.Base(name) 427 if base != start && base != end && base != typ { 428 return fmt.Errorf("unexpected file %q", name) 429 } 430 dir := path.Dir(name) 431 432 b, err := ioutil.ReadFile(name) 433 if err != nil { 434 return fmt.Errorf("error reading file %q: %v", name, err) 435 } 436 437 data := strings.TrimSpace(string(b)) 438 r := ranges[dir] 439 if base == typ { 440 typ, ok := sysfsToRangeType[data] 441 if !ok { 442 log.Printf("Sysfs file %q contains unrecognized memory map type %q, defaulting to Reserved", name, data) 443 r.typ = RangeReserved 444 } else { 445 r.typ = typ 446 } 447 ranges[dir] = r 448 return nil 449 } 450 451 v, err := strconv.ParseUint(data, 0, 64) 452 if err != nil { 453 return err 454 } 455 switch base { 456 case start: 457 r.start = uintptr(v) 458 case end: 459 r.end = uintptr(v) 460 } 461 ranges[dir] = r 462 return nil 463 } 464 465 if err := filepath.Walk(memoryMapDir, walker); err != nil { 466 return nil, err 467 } 468 469 var phys []TypedRange 470 for _, r := range ranges { 471 // Range's end address is exclusive, while Linux's sysfs prints 472 // the end address inclusive. 473 // 474 // E.g. sysfs will contain 475 // 476 // start: 0x100, end: 0x1ff 477 // 478 // while we represent 479 // 480 // start: 0x100, size: 0x100. 481 phys = append(phys, TypedRange{ 482 Range: RangeFromInterval(r.start, r.end+1), 483 Type: r.typ, 484 }) 485 } 486 sort.Slice(phys, func(i, j int) bool { 487 return phys[i].Start < phys[j].Start 488 }) 489 return phys, nil 490 } 491 492 // M1 is 1 Megabyte in bits. 493 const M1 = 1 << 20 494 495 // FindSpace returns pointer to the physical memory, where array of size sz can 496 // be stored during next AddKexecSegment call. 497 func (m Memory) FindSpace(sz uint) (Range, error) { 498 // Allocate full pages. 499 sz = alignUp(sz) 500 501 // Don't use memory below 1M, just in case. 502 return m.AvailableRAM().FindSpaceAbove(sz, M1) 503 } 504 505 // ReservePhys reserves page-aligned sz bytes in the physical memmap within 506 // the given limit address range. 507 func (m *Memory) ReservePhys(sz uint, limit Range) (Range, error) { 508 sz = alignUp(sz) 509 510 r, err := m.AvailableRAM().FindSpaceIn(sz, limit) 511 if err != nil { 512 return Range{}, err 513 } 514 515 m.Phys.Insert(TypedRange{ 516 Range: r, 517 Type: RangeReserved, 518 }) 519 return r, nil 520 } 521 522 // AddPhysSegment reserves len(d) bytes in the physical memmap within limit and 523 // adds a kexec segment with d in that range. 524 func (m *Memory) AddPhysSegment(d []byte, limit Range) (Range, error) { 525 r, err := m.ReservePhys(uint(len(d)), limit) 526 if err != nil { 527 return Range{}, err 528 } 529 m.Segments.Insert(NewSegment(d, r)) 530 return r, nil 531 } 532 533 // AddKexecSegment adds d to a new kexec segment 534 func (m *Memory) AddKexecSegment(d []byte) (Range, error) { 535 r, err := m.FindSpace(uint(len(d))) 536 if err != nil { 537 return Range{}, err 538 } 539 m.Segments.Insert(NewSegment(d, r)) 540 return r, nil 541 } 542 543 // AvailableRAM returns page-aligned unused regions of RAM. 544 // 545 // AvailableRAM takes all RAM-marked pages in the memory map and subtracts the 546 // kexec segments already allocated. RAM segments begin at a page boundary. 547 // 548 // E.g if page size is 4K and RAM segments are 549 // [{start:0 size:8192} {start:8192 size:8000}] 550 // and kexec segments are 551 // [{start:40 size:50} {start:8000 size:2000}] 552 // result should be 553 // [{start:0 size:40} {start:4096 end:8000 - 4096}] 554 func (m Memory) AvailableRAM() Ranges { 555 ram := m.Phys.FilterByType(RangeRAM) 556 557 // Remove all points in Segments from available RAM. 558 for _, s := range m.Segments { 559 ram = ram.Minus(s.Phys) 560 } 561 562 // Only return Ranges starting at an aligned size. 563 var alignedRanges Ranges 564 for _, r := range ram { 565 alignedStart := alignUpPtr(r.Start) 566 if alignedStart < r.End() { 567 alignedRanges = append(alignedRanges, Range{ 568 Start: alignedStart, 569 Size: r.Size - uint(alignedStart-r.Start), 570 }) 571 } 572 } 573 return alignedRanges 574 } 575 576 // RangeType defines type of a TypedRange based on the Linux 577 // kernel string provided by firmware memory map. 578 type RangeType string 579 580 // These are the range types we know Linux uses. 581 const ( 582 RangeRAM RangeType = "System RAM" 583 RangeDefault RangeType = "Default" 584 RangeACPI RangeType = "ACPI Tables" 585 RangeNVS RangeType = "ACPI Non-volatile Storage" 586 RangeReserved RangeType = "Reserved" 587 ) 588 589 // String implements fmt.Stringer. 590 func (r RangeType) String() string { 591 return string(r) 592 } 593 594 var sysfsToRangeType = map[string]RangeType{ 595 "System RAM": RangeRAM, 596 "Default": RangeDefault, 597 "ACPI Tables": RangeACPI, 598 "ACPI Non-volatile Storage": RangeNVS, 599 "Reserved": RangeReserved, 600 "reserved": RangeReserved, 601 } 602 603 // TypedRange represents range of physical memory. 604 type TypedRange struct { 605 Range 606 Type RangeType 607 } 608 609 func (tr TypedRange) String() string { 610 return fmt.Sprintf("{addr: %s, type: %s}", tr.Range, tr.Type) 611 } 612 613 // MemoryMap defines the layout of physical memory. 614 // 615 // MemoryMap defines which ranges in memory are usable RAM and which are 616 // reserved for various reasons. 617 type MemoryMap []TypedRange 618 619 // FilterByType only returns ranges of the given typ. 620 func (m MemoryMap) FilterByType(typ RangeType) Ranges { 621 var rs Ranges 622 for _, tr := range m { 623 if tr.Type == typ { 624 rs = append(rs, tr.Range) 625 } 626 } 627 return rs 628 } 629 630 func (m MemoryMap) sort() { 631 sort.Slice(m, func(i, j int) bool { 632 return m[i].Start < m[j].Start 633 }) 634 } 635 636 // Insert a new TypedRange into the memory map, removing chunks of other ranges 637 // as necessary. 638 // 639 // Assumes that TypedRange is a valid range -- no checking. 640 func (m *MemoryMap) Insert(r TypedRange) { 641 var newMap MemoryMap 642 643 // Remove points in r from all existing physical ranges. 644 for _, q := range *m { 645 split := q.Range.Minus(r.Range) 646 for _, r2 := range split { 647 newMap = append(newMap, TypedRange{Range: r2, Type: q.Type}) 648 } 649 } 650 651 newMap = append(newMap, r) 652 newMap.sort() 653 *m = newMap 654 }