1/* SPDX-License-Identifier: GPL-2.0-only */ 2 3package main 4 5import "bufio" 6import "encoding/binary" 7import "encoding/csv" 8import "flag" 9import "fmt" 10import "io" 11import "log" 12import "os" 13import "path/filepath" 14import "sort" 15import "strconv" 16import "strings" 17 18// This program generates 32-bit PAE page tables based on a CSV input file. 19// By default each PDPTE entry is allocated a PD page such that it's easy 20// fault in new entries that are 2MiB aligned and size. 21 22var iomapFilePtr = flag.String("iomap_file", "", "CSV file detailing page table mapping") 23var ptCFilePtr = flag.String("pt_output_c_file", "", "File to write page tables to in C code") 24var ptBinFilePtr = flag.String("pt_output_bin_file", "", "File to write page tables to in binary") 25var pdptCFilePtr = flag.String("pdpt_output_c_file", "", "File to write PDPT to in C code") 26var pdptBinFilePtr = flag.String("pdpt_output_bin_file", "", "File to write PDPT to in binary") 27var pagesBaseAddress = flag.Uint64("metadata_base_address", BASE_ADDR, "Physical base address where metadata pages allocated from") 28 29var generatedCodeLicense string = 30`/* 31 * Copyright 2018 Generated Code 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. The name of the author may not be used to endorse or promote products 42 * derived from this software without specific prior written permission. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ` + "``" + `AS IS'' AND 45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * SUCH DAMAGE. 55 */ 56` 57 58const ( 59 PAT_UC = 0 60 PAT_WC = 1 61 PAT_WT = 4 62 PAT_WP = 5 63 PAT_WB = 6 64 PAT_UCMINUS = 7 65 66 COMMENT_CHAR = '#' 67 68 NUM_PDPTE = 4 69 NUM_PDE = 512 70 NUM_PTE = 512 71 72 SIZE_4KiB = uint64(1 << 12) 73 MASK_4KiB = SIZE_4KiB - 1 74 SIZE_2MiB = uint64(1 << 21) 75 MASK_2MiB = SIZE_2MiB - 1 76 77 // This is a fake physical address for doing fixups when loading 78 // the page tables. There's room for 4096 4KiB physical PD or PTE 79 // tables. Anything with the present bit set will be pointing to an 80 // offset based on this address. At runtime the entries will be fixed up 81 BASE_ADDR = uint64(0xaa000000) 82 83 // Size of PD and PT structures 84 METADATA_TABLE_SIZE = 4096 85 86 PDPTE_PRES = uint64(1 << 0) 87 PDPTE_PWT = uint64(1 << 3) 88 PDPTE_PCD = uint64(1 << 4) 89 90 PDE_PRES = uint64(1 << 0) 91 PDE_RW = uint64(1 << 1) 92 PDE_US = uint64(1 << 2) 93 PDE_PWT = uint64(1 << 3) 94 PDE_PCD = uint64(1 << 4) 95 PDE_A = uint64(1 << 5) 96 PDE_D = uint64(1 << 6) // only valid with PS=1 97 PDE_PS = uint64(1 << 7) 98 PDE_G = uint64(1 << 8) // only valid with PS=1 99 PDE_PAT = uint64(1 << 12) // only valid with PS=1 100 PDE_XD = uint64(1 << 63) 101 102 PTE_PRES = uint64(1 << 0) 103 PTE_RW = uint64(1 << 1) 104 PTE_US = uint64(1 << 2) 105 PTE_PWT = uint64(1 << 3) 106 PTE_PCD = uint64(1 << 4) 107 PTE_A = uint64(1 << 5) 108 PTE_D = uint64(1 << 6) 109 PTE_PAT = uint64(1 << 7) 110 PTE_G = uint64(1 << 8) 111 PTE_XD = uint64(1 << 63) 112 113 PDPTE_IDX_SHIFT = 30 114 PDPTE_IDX_MASK = 0x3 115 116 PDE_IDX_SHIFT = 21 117 PDE_IDX_MASK = 0x1ff 118 119 PTE_IDX_SHIFT = 12 120 PTE_IDX_MASK = 0x1ff 121) 122 123// Different 'writers' implement this interface. 124type pageTableEntryWriter interface { 125 WritePageEntry(data interface{}) error 126} 127 128// The full page objects, page directories and page tables, implement this 129// interface to write their entire contents out 130type pageTableWriter interface { 131 WritePage(wr pageTableEntryWriter) error 132} 133 134type binaryWriter struct { 135 wr io.Writer 136} 137 138func (bw *binaryWriter) WritePageEntry(data interface{}) error { 139 return binary.Write(bw.wr, binary.LittleEndian, data) 140} 141 142type cWriter struct { 143 name string 144 wr io.Writer 145 totalEntries uint 146 currentIndex uint 147} 148 149func newCWriter(wr io.Writer, name string, nr_entries uint) *cWriter { 150 cw := &cWriter{wr: wr, name: name, totalEntries: nr_entries} 151 return cw 152} 153 154func (cw *cWriter) WritePageEntry(data interface{}) error { 155 var entry uint64 156 doPrint := false 157 158 entry, ok := data.(uint64) 159 if !ok { 160 return fmt.Errorf("entry not uint64 %T", data) 161 } 162 163 if cw.currentIndex == 0 { 164 if _, err := fmt.Fprint(cw.wr, generatedCodeLicense); err != nil { 165 return err 166 } 167 if _, err := fmt.Fprintf(cw.wr, "/* Generated by:\n util/x86/%s %s\n */\n", 168 filepath.Base(os.Args[0]), 169 strings.Join(os.Args[1:], " ")); err != nil { 170 return err 171 } 172 includes := []string{ 173 "stdint.h", 174 } 175 for _, l := range includes { 176 if _, err := fmt.Fprintf(cw.wr, "#include <%s>\n", l); err != nil { 177 return err 178 } 179 } 180 181 if _, err := fmt.Fprintf(cw.wr, "uint64_t %s[] = {\n", cw.name); err != nil { 182 return err 183 } 184 } 185 186 if cw.currentIndex%NUM_PTE == 0 { 187 doPrint = true 188 page_num := cw.currentIndex / NUM_PTE 189 if _, err := fmt.Fprintf(cw.wr, "\t/* Page %d */\n", page_num); err != nil { 190 return err 191 } 192 } 193 194 // filter out 0 entries 195 if entry != 0 || doPrint { 196 _, err := fmt.Fprintf(cw.wr, "\t[%d] = %#016xULL,\n", cw.currentIndex, entry) 197 if err != nil { 198 return err 199 } 200 } 201 202 cw.currentIndex += 1 203 204 if cw.currentIndex == cw.totalEntries { 205 if _, err := fmt.Fprintln(cw.wr, "};"); err != nil { 206 return err 207 } 208 } 209 210 return nil 211} 212 213// This map represents what the IA32_PAT MSR should be at runtime. The indices 214// are what the linux kernel uses. Reserved entries are not used. 215// 0 WB : _PAGE_CACHE_MODE_WB 216// 1 WC : _PAGE_CACHE_MODE_WC 217// 2 UC-: _PAGE_CACHE_MODE_UC_MINUS 218// 3 UC : _PAGE_CACHE_MODE_UC 219// 4 WB : Reserved 220// 5 WP : _PAGE_CACHE_MODE_WP 221// 6 UC-: Reserved 222// 7 WT : _PAGE_CACHE_MODE_WT 223// In order to use WP and WC then the IA32_PAT MSR needs to be updated 224// as these are not the power on reset values. 225var patMsrIndexByType = map[uint]uint{ 226 PAT_WB: 0, 227 PAT_WC: 1, 228 PAT_UCMINUS: 2, 229 PAT_UC: 3, 230 PAT_WP: 5, 231 PAT_WT: 7, 232} 233 234type addressRange struct { 235 begin uint64 236 end uint64 237 pat uint 238 nx bool 239} 240 241type addrRangeMerge func(a, b *addressRange) bool 242 243func (ar *addressRange) Size() uint64 { 244 return ar.end - ar.begin 245} 246 247func (ar *addressRange) Base() uint64 { 248 return ar.begin 249} 250 251func (ar *addressRange) Pat() uint { 252 return ar.pat 253} 254 255func (ar *addressRange) Nx() bool { 256 return ar.nx 257} 258 259func (ar *addressRange) String() string { 260 var nx string 261 if ar.nx { 262 nx = "NX" 263 } else { 264 nx = " " 265 } 266 return fmt.Sprintf("%016x -- %016x %s %s", ar.begin, ar.end, patTypeToString(ar.pat), nx) 267} 268 269type pageTableEntry struct { 270 physAddr uint64 271 flags uint64 272} 273 274func (pte *pageTableEntry) Encode() uint64 { 275 return pte.physAddr | pte.flags 276} 277 278func ptePatFlags(base uint64, pat uint) uint64 { 279 idx, ok := patMsrIndexByType[pat] 280 patStr, _ := patTypesToString[pat] 281 282 if !ok { 283 log.Fatalf("Invalid pat entry for page %x: %s\n", base, patStr) 284 } 285 286 switch idx { 287 case 0: 288 return 0 289 case 1: 290 return PTE_PWT 291 case 2: 292 return PTE_PCD 293 case 3: 294 return PTE_PCD | PTE_PWT 295 case 4: 296 return PTE_PAT 297 case 5: 298 return PTE_PAT | PTE_PWT 299 case 6: 300 return PTE_PAT | PTE_PCD 301 case 7: 302 return PTE_PAT | PTE_PCD | PTE_PWT 303 } 304 305 log.Fatalf("Invalid PAT index %d for PTE %x %s\n", idx, base, patStr) 306 return 0 307} 308 309func (pte *pageTableEntry) SetMapping(base uint64, pat uint, nx bool) { 310 // Present and accessed 311 pte.flags |= PTE_PRES | PTE_A 312 313 // Non write protected entries mark as writable and dirty 314 if pat != PAT_WP { 315 pte.flags |= PTE_RW 316 pte.flags |= PTE_D 317 } 318 319 if nx { 320 pte.flags |= PTE_XD 321 } 322 323 pte.flags |= ptePatFlags(base, pat) 324 pte.physAddr = base 325} 326 327type pageTable struct { 328 ptes [NUM_PTE]pageTableEntry 329} 330 331func (pt *pageTable) WritePage(wr pageTableEntryWriter) error { 332 for i := range pt.ptes { 333 pte := &pt.ptes[i] 334 err := wr.WritePageEntry(pte.Encode()) 335 if err != nil { 336 return err 337 } 338 } 339 return nil 340} 341 342type pageDirectoryEntry struct { 343 physAddr uint64 344 flags uint64 345 pt *pageTable 346} 347 348func (pde *pageDirectoryEntry) Encode() uint64 { 349 return pde.physAddr | pde.flags 350} 351 352func pdeTablePatFlags(pat uint) uint64 { 353 idx, ok := patMsrIndexByType[pat] 354 patStr, _ := patTypesToString[pat] 355 356 if !ok || idx >= 4 { 357 log.Fatalf("Invalid pat entry for PDE page table %s\n", patStr) 358 } 359 360 switch idx { 361 case 0: 362 return 0 363 case 1: 364 return PDE_PWT 365 case 2: 366 return PDE_PCD 367 case 3: 368 return PDE_PCD | PDE_PWT 369 } 370 371 log.Fatalf("Invalid PAT index %d for PDE page table %s\n", idx, patStr) 372 return 0 373} 374 375func pdeLargePatFlags(base uint64, pat uint) uint64 { 376 idx, ok := patMsrIndexByType[pat] 377 patStr, _ := patTypesToString[pat] 378 379 if !ok { 380 log.Fatalf("Invalid pat entry for large page %x: %s\n", base, patStr) 381 } 382 383 switch idx { 384 case 0: 385 return 0 386 case 1: 387 return PDE_PWT 388 case 2: 389 return PDE_PCD 390 case 3: 391 return PDE_PCD | PDE_PWT 392 case 4: 393 return PDE_PAT 394 case 5: 395 return PDE_PAT | PDE_PWT 396 case 6: 397 return PDE_PAT | PDE_PCD 398 case 7: 399 return PDE_PAT | PDE_PCD | PDE_PWT 400 } 401 402 log.Fatalf("Invalid PAT index %d for PDE %x %s\n", idx, base, patStr) 403 return 0 404} 405 406func (pde *pageDirectoryEntry) SetPageTable(pt_addr uint64, pat uint) { 407 // Set writable for whole region covered by page table. Individual 408 // ptes will have the correct writability flags 409 pde.flags |= PDE_PRES | PDE_A | PDE_RW 410 411 pde.flags |= pdeTablePatFlags(pat) 412 413 pde.physAddr = pt_addr 414} 415 416func (pde *pageDirectoryEntry) SetMapping(base uint64, pat uint, nx bool) { 417 // Present, accessed, and large 418 pde.flags |= PDE_PRES | PDE_A | PDE_PS 419 420 // Non write protected entries mark as writable and dirty 421 if pat != PAT_WP { 422 pde.flags |= PDE_RW 423 pde.flags |= PDE_D 424 } 425 426 if nx { 427 pde.flags |= PDE_XD 428 } 429 430 pde.flags |= pdeLargePatFlags(base, pat) 431 pde.physAddr = base 432} 433 434type pageDirectory struct { 435 pdes [NUM_PDE]pageDirectoryEntry 436} 437 438func (pd *pageDirectory) WritePage(wr pageTableEntryWriter) error { 439 for i := range pd.pdes { 440 pde := &pd.pdes[i] 441 err := wr.WritePageEntry(pde.Encode()) 442 if err != nil { 443 return nil 444 } 445 } 446 return nil 447} 448 449type pageDirectoryPointerEntry struct { 450 physAddr uint64 451 flags uint64 452 pd *pageDirectory 453} 454 455func (pdpte *pageDirectoryPointerEntry) Encode() uint64 { 456 return pdpte.physAddr | pdpte.flags 457} 458 459func (pdpte *pageDirectoryPointerEntry) Init(addr uint64, pat uint) { 460 idx, ok := patMsrIndexByType[pat] 461 462 // Only 2 bits worth of PAT indexing in PDPTE 463 if !ok || idx >= 4 { 464 patStr, _ := patTypesToString[pat] 465 log.Fatalf("Can't use type '%s' as PDPTE type.\n", patStr) 466 } 467 468 pdpte.physAddr = addr 469 pdpte.flags = PDPTE_PRES 470 471 switch idx { 472 case 0: 473 pdpte.flags |= 0 474 case 1: 475 pdpte.flags |= PDPTE_PWT 476 case 2: 477 pdpte.flags |= PDPTE_PCD 478 case 3: 479 pdpte.flags |= PDPTE_PCD | PDPTE_PWT 480 default: 481 log.Fatalf("Invalid PAT index %d for PDPTE\n", idx) 482 } 483} 484 485type addressSpace struct { 486 ranges []*addressRange 487 mergeFunc addrRangeMerge 488 metatdataBaseAddr uint64 489 pdptes [NUM_PDPTE]pageDirectoryPointerEntry 490 numMetaPages uint 491 page_writers []pageTableWriter 492} 493 494func (as *addressSpace) newPage(pw pageTableWriter) uint64 { 495 v := as.metatdataBaseAddr + METADATA_TABLE_SIZE*uint64(as.numMetaPages) 496 as.numMetaPages += 1 497 as.page_writers = append(as.page_writers, pw) 498 return v 499} 500 501func newAddrSpace(mergeFunc addrRangeMerge, metatdataBaseAddr uint64) *addressSpace { 502 as := &addressSpace{mergeFunc: mergeFunc, metatdataBaseAddr: metatdataBaseAddr} 503 // Fill in all PDPTEs 504 for i := range as.pdptes { 505 pdpte := &as.pdptes[i] 506 pdpte.pd = &pageDirectory{} 507 // fetch paging structures as WB 508 pdpte.Init(as.newPage(pdpte.pd), PAT_WB) 509 } 510 return as 511} 512 513func (as *addressSpace) deleteEntries(indices []int) { 514 // deletions need to be processed in reverse order so as not 515 // delete the wrong entries 516 sort.Sort(sort.Reverse(sort.IntSlice(indices))) 517 for _, i := range indices { 518 as.ranges = append(as.ranges[:i], as.ranges[i+1:]...) 519 } 520} 521 522func (as *addressSpace) mergeRanges() { 523 var toRemove []int 524 var prev *addressRange 525 526 for i, cur := range as.ranges { 527 if prev == nil { 528 prev = cur 529 continue 530 } 531 532 // merge previous with current 533 if as.mergeFunc(prev, cur) { 534 prev.end = cur.end 535 toRemove = append(toRemove, i) 536 cur = prev 537 } 538 prev = cur 539 } 540 541 as.deleteEntries(toRemove) 542} 543 544type addressRangeSlice []*addressRange 545 546func (p addressRangeSlice) Len() int { 547 return len(p) 548} 549 550func (p addressRangeSlice) Less(i, j int) bool { 551 return !p[i].After(p[j]) 552} 553 554func (p addressRangeSlice) Swap(i, j int) { 555 p[i], p[j] = p[j], p[i] 556} 557 558func (as *addressSpace) insertRange(r *addressRange) { 559 as.ranges = append(as.ranges, r) 560 sort.Sort(addressRangeSlice(as.ranges)) 561} 562 563// Remove complete entries or trim existing ones 564func (as *addressSpace) trimRanges(r *addressRange) { 565 var toRemove []int 566 567 // First remove all entries that are completely overlapped 568 for i, cur := range as.ranges { 569 if r.FullyOverlaps(cur) { 570 toRemove = append(toRemove, i) 571 continue 572 } 573 } 574 as.deleteEntries(toRemove) 575 576 var ar *addressRange 577 578 // Process partial overlaps 579 for _, cur := range as.ranges { 580 // Overlapping may be at beginning, middle, end. Only the 581 // middle overlap needs to create a new range since the 582 // beginning and end overlap can just adjust the current 583 // range. 584 if r.Overlaps(cur) { 585 586 // beginning overlap 587 if r.begin <= cur.begin { 588 cur.begin = r.end 589 continue 590 } 591 592 // end overlap 593 if r.end >= cur.end { 594 cur.end = r.begin 595 continue 596 } 597 598 // middle overlap. create new entry from the hole 599 // punched in the current entry. There's nothing 600 // further to do after this 601 begin := r.end 602 end := cur.end 603 pat := cur.pat 604 nx := cur.nx 605 606 // current needs new ending 607 cur.end = r.begin 608 609 ar = newAddrRange(begin, end, pat, nx) 610 611 break 612 } 613 } 614 615 if ar != nil { 616 as.insertRange(ar) 617 } 618} 619 620func (as *addressSpace) PrintEntries() { 621 for _, cur := range as.ranges { 622 log.Println(cur) 623 } 624} 625 626func (as *addressSpace) AddRange(r *addressRange) { 627 as.trimRanges(r) 628 as.insertRange(r) 629 as.mergeRanges() 630} 631 632func (as *addressSpace) insertMapping(base uint64, size uint64, pat uint, nx bool) { 633 pdpteIndex := (base >> PDPTE_IDX_SHIFT) & PDPTE_IDX_MASK 634 pdeIndex := (base >> PDE_IDX_SHIFT) & PDE_IDX_MASK 635 pteIndex := (base >> PTE_IDX_SHIFT) & PTE_IDX_MASK 636 637 pd := as.pdptes[pdpteIndex].pd 638 pde := &pd.pdes[pdeIndex] 639 640 if size == SIZE_2MiB { 641 pde.SetMapping(base, pat, nx) 642 return 643 } 644 645 if pde.pt == nil { 646 pde.pt = &pageTable{} 647 // Fetch paging structures as WB 648 pde.SetPageTable(as.newPage(pde.pt), PAT_WB) 649 } 650 651 pte := &pde.pt.ptes[pteIndex] 652 pte.SetMapping(base, pat, nx) 653} 654 655func (as *addressSpace) CreatePageTables() { 656 var size uint64 657 var base uint64 658 659 for _, r := range as.ranges { 660 size = r.Size() 661 base = r.Base() 662 pat := r.Pat() 663 nx := r.Nx() 664 665 numSmallEntries := 0 666 numBigEntries := 0 667 668 for size != 0 { 669 mappingSize := SIZE_4KiB 670 671 if (base&MASK_2MiB) == 0 && size >= SIZE_2MiB { 672 mappingSize = SIZE_2MiB 673 numBigEntries += 1 674 } else { 675 numSmallEntries += 1 676 } 677 678 as.insertMapping(base, mappingSize, pat, nx) 679 680 base += mappingSize 681 size -= mappingSize 682 683 } 684 685 log.Printf("%s : %d big %d small\n", r, numBigEntries, numSmallEntries) 686 } 687} 688 689func (as *addressSpace) PageTableSize() uint { 690 return as.numMetaPages * METADATA_TABLE_SIZE 691} 692 693func (as *addressSpace) NumPages() uint { 694 return as.numMetaPages 695} 696 697func (as *addressSpace) WritePageTable(ptew pageTableEntryWriter) error { 698 for _, pw := range as.page_writers { 699 err := pw.WritePage(ptew) 700 if err != nil { 701 return err 702 } 703 } 704 705 return nil 706} 707 708func (as *addressSpace) WritePageDirectoryPointerTable(ptew pageTableEntryWriter) error { 709 for i := range as.pdptes { 710 err := ptew.WritePageEntry(as.pdptes[i].Encode()) 711 if err != nil { 712 return err 713 } 714 } 715 716 return nil 717} 718 719var pat_types_from_str = map[string]uint{ 720 "UC": PAT_UC, 721 "WC": PAT_WC, 722 "WT": PAT_WT, 723 "WP": PAT_WP, 724 "WB": PAT_WB, 725 "UC-": PAT_UCMINUS, 726} 727 728var patTypesToString = map[uint]string{ 729 PAT_UC: "UC", 730 PAT_WC: "WC", 731 PAT_WT: "WT", 732 PAT_WP: "WP", 733 PAT_WB: "WB", 734 PAT_UCMINUS: "UC-", 735} 736 737func openCsvFile(file string) (*csv.Reader, error) { 738 f, err := os.Open(file) 739 740 if err != nil { 741 return nil, err 742 } 743 744 csvr := csv.NewReader(f) 745 csvr.Comment = COMMENT_CHAR 746 csvr.TrimLeadingSpace = true 747 return csvr, nil 748} 749 750// After returns true if ar beings at or after other.end. 751func (ar addressRange) After(other *addressRange) bool { 752 return ar.begin >= other.end 753} 754 755func (ar addressRange) FullyOverlaps(other *addressRange) bool { 756 return ar.begin <= other.begin && ar.end >= other.end 757} 758 759func (ar addressRange) Overlaps(other *addressRange) bool { 760 if other.end <= ar.begin || other.begin >= ar.end { 761 return false 762 } 763 return true 764} 765 766func MergeByPat(a, b *addressRange) bool { 767 // 'b' is assumed to be following 'a' 768 if a.end != b.begin { 769 return false 770 } 771 772 if a.pat != b.pat { 773 return false 774 } 775 776 return true 777} 778 779func MergeByNx(a, b *addressRange) bool { 780 // 'b' is assumed to be following 'a' 781 if a.end != b.begin { 782 return false 783 } 784 785 if a.nx != b.nx { 786 return false 787 } 788 789 return true 790} 791 792func MergeByPatNx(a, b *addressRange) bool { 793 return MergeByPat(a, b) && MergeByNx(a, b) 794} 795 796func hexNumber(s string) (uint64, error) { 797 return strconv.ParseUint(strings.TrimSpace(s), 0, 0) 798} 799 800func patTypeToString(pat uint) string { 801 return patTypesToString[pat] 802} 803 804func patTypeFromString(s string) (uint, error) { 805 s1 := strings.TrimSpace(s) 806 v, ok := pat_types_from_str[s1] 807 808 if !ok { 809 return 0, fmt.Errorf("No PAT type '%s'", s1) 810 } 811 812 return v, nil 813} 814 815func removeComment(field, comment string) string { 816 str_slice := strings.Split(field, comment) 817 return strings.TrimSpace(str_slice[0]) 818} 819 820func newAddrRange(begin, end uint64, pat uint, nx bool) *addressRange { 821 return &addressRange{begin: begin, end: end, pat: pat, nx: nx} 822} 823 824func readRecords(csvr *csv.Reader, as *addressSpace) { 825 i := 0 826 for true { 827 fields, err := csvr.Read() 828 i++ 829 830 if err == io.EOF { 831 break 832 } 833 834 if err != nil { 835 log.Fatal(err) 836 } 837 838 if len(fields) < 3 { 839 log.Fatal("Need at least 3 fields: begin, end, PAT\n") 840 } 841 842 begin, err := hexNumber(fields[0]) 843 844 if err != nil { 845 log.Fatal(err) 846 } 847 848 end, err := hexNumber(fields[1]) 849 850 if err != nil { 851 log.Fatal(err) 852 } 853 854 if begin&MASK_4KiB != 0 { 855 log.Fatalf("begin %x must be at least 4KiB aligned\n", begin) 856 } 857 858 if end&MASK_4KiB != 0 { 859 log.Fatalf("end %x must be at least 4KiB aligned\n", end) 860 } 861 if begin >= end { 862 log.Fatalf("%x must be < %x at record %d\n", begin, end, i) 863 } 864 865 pat, err := patTypeFromString(fields[2]) 866 867 if err != nil { 868 log.Fatal(err) 869 } 870 871 var nx bool = false 872 873 if len(fields) > 3 && len(removeComment(fields[3], string(COMMENT_CHAR))) > 0 { 874 nx = true 875 } 876 877 as.AddRange(newAddrRange(begin, end, pat, nx)) 878 } 879} 880 881func main() { 882 log.SetFlags(0) 883 flag.Parse() 884 var ptWriters []pageTableEntryWriter 885 var pdptWriters []pageTableEntryWriter 886 887 if *iomapFilePtr == "" { 888 log.Fatal("No iomap_file provided.\n") 889 } 890 891 csvr, err := openCsvFile(*iomapFilePtr) 892 if err != nil { 893 log.Fatal(err) 894 } 895 896 as := newAddrSpace(MergeByPatNx, *pagesBaseAddress) 897 readRecords(csvr, as) 898 899 log.Println("Merged address space:") 900 as.CreatePageTables() 901 log.Println() 902 log.Printf("Total Pages of page tables: %d\n", as.NumPages()) 903 log.Println() 904 log.Printf("Pages linked using base address of %#x.\n", *pagesBaseAddress) 905 906 if *ptCFilePtr != "" { 907 f, err := os.Create(*ptCFilePtr) 908 if err != nil { 909 log.Fatal(err) 910 } 911 defer f.Close() 912 bwr := bufio.NewWriter(f) 913 defer bwr.Flush() 914 cw := newCWriter(bwr, "page_tables", as.NumPages()*NUM_PTE) 915 ptWriters = append(ptWriters, cw) 916 } 917 918 if *ptBinFilePtr != "" { 919 f, err := os.Create(*ptBinFilePtr) 920 if err != nil { 921 log.Fatal(err) 922 } 923 defer f.Close() 924 bwr := bufio.NewWriter(f) 925 defer bwr.Flush() 926 bw := &binaryWriter{wr: bwr} 927 ptWriters = append(ptWriters, bw) 928 } 929 930 if *pdptCFilePtr != "" { 931 f, err := os.Create(*pdptCFilePtr) 932 if err != nil { 933 log.Fatal(err) 934 } 935 defer f.Close() 936 bwr := bufio.NewWriter(f) 937 defer bwr.Flush() 938 cw := newCWriter(bwr, "pdptes", NUM_PDPTE) 939 pdptWriters = append(pdptWriters, cw) 940 } 941 942 if *pdptBinFilePtr != "" { 943 f, err := os.Create(*pdptBinFilePtr) 944 if err != nil { 945 log.Fatal(err) 946 } 947 defer f.Close() 948 bwr := bufio.NewWriter(f) 949 defer bwr.Flush() 950 bw := &binaryWriter{wr: bwr} 951 pdptWriters = append(pdptWriters, bw) 952 } 953 954 // Write out page tables 955 for _, w := range ptWriters { 956 err = as.WritePageTable(w) 957 if err != nil { 958 log.Fatal(err) 959 } 960 } 961 962 // Write out pdptes 963 for _, w := range pdptWriters { 964 err = as.WritePageDirectoryPointerTable(w) 965 if err != nil { 966 log.Fatal(err) 967 } 968 } 969} 970