drivers/wifi: Remove unnecessary data structure copy
[coreboot2.git] / util / x86 / x86_page_tables.go
blob8fd24eb28161e6dbd5c628fad2bfc19508a7f284
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 package main
5 import "bufio"
6 import "encoding/binary"
7 import "encoding/csv"
8 import "flag"
9 import "fmt"
10 import "io"
11 import "log"
12 import "os"
13 import "path/filepath"
14 import "sort"
15 import "strconv"
16 import "strings"
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.
22 var iomapFilePtr = flag.String("iomap_file", "", "CSV file detailing page table mapping")
23 var ptCFilePtr = flag.String("pt_output_c_file", "", "File to write page tables to in C code")
24 var ptBinFilePtr = flag.String("pt_output_bin_file", "", "File to write page tables to in binary")
25 var pdptCFilePtr = flag.String("pdpt_output_c_file", "", "File to write PDPT to in C code")
26 var pdptBinFilePtr = flag.String("pdpt_output_bin_file", "", "File to write PDPT to in binary")
27 var pagesBaseAddress = flag.Uint64("metadata_base_address", BASE_ADDR, "Physical base address where metadata pages allocated from")
29 var generatedCodeLicense string =
30 `/*
31 * Copyright 2018 Generated Code
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.
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.
58 const (
59 PAT_UC = 0
60 PAT_WC = 1
61 PAT_WT = 4
62 PAT_WP = 5
63 PAT_WB = 6
64 PAT_UCMINUS = 7
66 COMMENT_CHAR = '#'
68 NUM_PDPTE = 4
69 NUM_PDE = 512
70 NUM_PTE = 512
72 SIZE_4KiB = uint64(1 << 12)
73 MASK_4KiB = SIZE_4KiB - 1
74 SIZE_2MiB = uint64(1 << 21)
75 MASK_2MiB = SIZE_2MiB - 1
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)
83 // Size of PD and PT structures
84 METADATA_TABLE_SIZE = 4096
86 PDPTE_PRES = uint64(1 << 0)
87 PDPTE_PWT = uint64(1 << 3)
88 PDPTE_PCD = uint64(1 << 4)
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)
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)
113 PDPTE_IDX_SHIFT = 30
114 PDPTE_IDX_MASK = 0x3
116 PDE_IDX_SHIFT = 21
117 PDE_IDX_MASK = 0x1ff
119 PTE_IDX_SHIFT = 12
120 PTE_IDX_MASK = 0x1ff
123 // Different 'writers' implement this interface.
124 type pageTableEntryWriter interface {
125 WritePageEntry(data interface{}) error
128 // The full page objects, page directories and page tables, implement this
129 // interface to write their entire contents out
130 type pageTableWriter interface {
131 WritePage(wr pageTableEntryWriter) error
134 type binaryWriter struct {
135 wr io.Writer
138 func (bw *binaryWriter) WritePageEntry(data interface{}) error {
139 return binary.Write(bw.wr, binary.LittleEndian, data)
142 type cWriter struct {
143 name string
144 wr io.Writer
145 totalEntries uint
146 currentIndex uint
149 func newCWriter(wr io.Writer, name string, nr_entries uint) *cWriter {
150 cw := &cWriter{wr: wr, name: name, totalEntries: nr_entries}
151 return cw
154 func (cw *cWriter) WritePageEntry(data interface{}) error {
155 var entry uint64
156 doPrint := false
158 entry, ok := data.(uint64)
159 if !ok {
160 return fmt.Errorf("entry not uint64 %T", data)
163 if cw.currentIndex == 0 {
164 if _, err := fmt.Fprint(cw.wr, generatedCodeLicense); err != nil {
165 return err
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
172 includes := []string{
173 "stdint.h",
175 for _, l := range includes {
176 if _, err := fmt.Fprintf(cw.wr, "#include <%s>\n", l); err != nil {
177 return err
181 if _, err := fmt.Fprintf(cw.wr, "uint64_t %s[] = {\n", cw.name); err != nil {
182 return err
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
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
202 cw.currentIndex += 1
204 if cw.currentIndex == cw.totalEntries {
205 if _, err := fmt.Fprintln(cw.wr, "};"); err != nil {
206 return err
210 return nil
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.
225 var 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,
234 type addressRange struct {
235 begin uint64
236 end uint64
237 pat uint
238 nx bool
241 type addrRangeMerge func(a, b *addressRange) bool
243 func (ar *addressRange) Size() uint64 {
244 return ar.end - ar.begin
247 func (ar *addressRange) Base() uint64 {
248 return ar.begin
251 func (ar *addressRange) Pat() uint {
252 return ar.pat
255 func (ar *addressRange) Nx() bool {
256 return ar.nx
259 func (ar *addressRange) String() string {
260 var nx string
261 if ar.nx {
262 nx = "NX"
263 } else {
264 nx = " "
266 return fmt.Sprintf("%016x -- %016x %s %s", ar.begin, ar.end, patTypeToString(ar.pat), nx)
269 type pageTableEntry struct {
270 physAddr uint64
271 flags uint64
274 func (pte *pageTableEntry) Encode() uint64 {
275 return pte.physAddr | pte.flags
278 func ptePatFlags(base uint64, pat uint) uint64 {
279 idx, ok := patMsrIndexByType[pat]
280 patStr, _ := patTypesToString[pat]
282 if !ok {
283 log.Fatalf("Invalid pat entry for page %x: %s\n", base, patStr)
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
305 log.Fatalf("Invalid PAT index %d for PTE %x %s\n", idx, base, patStr)
306 return 0
309 func (pte *pageTableEntry) SetMapping(base uint64, pat uint, nx bool) {
310 // Present and accessed
311 pte.flags |= PTE_PRES | PTE_A
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
319 if nx {
320 pte.flags |= PTE_XD
323 pte.flags |= ptePatFlags(base, pat)
324 pte.physAddr = base
327 type pageTable struct {
328 ptes [NUM_PTE]pageTableEntry
331 func (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
339 return nil
342 type pageDirectoryEntry struct {
343 physAddr uint64
344 flags uint64
345 pt *pageTable
348 func (pde *pageDirectoryEntry) Encode() uint64 {
349 return pde.physAddr | pde.flags
352 func pdeTablePatFlags(pat uint) uint64 {
353 idx, ok := patMsrIndexByType[pat]
354 patStr, _ := patTypesToString[pat]
356 if !ok || idx >= 4 {
357 log.Fatalf("Invalid pat entry for PDE page table %s\n", patStr)
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
371 log.Fatalf("Invalid PAT index %d for PDE page table %s\n", idx, patStr)
372 return 0
375 func pdeLargePatFlags(base uint64, pat uint) uint64 {
376 idx, ok := patMsrIndexByType[pat]
377 patStr, _ := patTypesToString[pat]
379 if !ok {
380 log.Fatalf("Invalid pat entry for large page %x: %s\n", base, patStr)
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
402 log.Fatalf("Invalid PAT index %d for PDE %x %s\n", idx, base, patStr)
403 return 0
406 func (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
411 pde.flags |= pdeTablePatFlags(pat)
413 pde.physAddr = pt_addr
416 func (pde *pageDirectoryEntry) SetMapping(base uint64, pat uint, nx bool) {
417 // Present, accessed, and large
418 pde.flags |= PDE_PRES | PDE_A | PDE_PS
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
426 if nx {
427 pde.flags |= PDE_XD
430 pde.flags |= pdeLargePatFlags(base, pat)
431 pde.physAddr = base
434 type pageDirectory struct {
435 pdes [NUM_PDE]pageDirectoryEntry
438 func (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
446 return nil
449 type pageDirectoryPointerEntry struct {
450 physAddr uint64
451 flags uint64
452 pd *pageDirectory
455 func (pdpte *pageDirectoryPointerEntry) Encode() uint64 {
456 return pdpte.physAddr | pdpte.flags
459 func (pdpte *pageDirectoryPointerEntry) Init(addr uint64, pat uint) {
460 idx, ok := patMsrIndexByType[pat]
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)
468 pdpte.physAddr = addr
469 pdpte.flags = PDPTE_PRES
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)
485 type addressSpace struct {
486 ranges []*addressRange
487 mergeFunc addrRangeMerge
488 metatdataBaseAddr uint64
489 pdptes [NUM_PDPTE]pageDirectoryPointerEntry
490 numMetaPages uint
491 page_writers []pageTableWriter
494 func (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
501 func 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)
510 return as
513 func (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:]...)
522 func (as *addressSpace) mergeRanges() {
523 var toRemove []int
524 var prev *addressRange
526 for i, cur := range as.ranges {
527 if prev == nil {
528 prev = cur
529 continue
532 // merge previous with current
533 if as.mergeFunc(prev, cur) {
534 prev.end = cur.end
535 toRemove = append(toRemove, i)
536 cur = prev
538 prev = cur
541 as.deleteEntries(toRemove)
544 type addressRangeSlice []*addressRange
546 func (p addressRangeSlice) Len() int {
547 return len(p)
550 func (p addressRangeSlice) Less(i, j int) bool {
551 return !p[i].After(p[j])
554 func (p addressRangeSlice) Swap(i, j int) {
555 p[i], p[j] = p[j], p[i]
558 func (as *addressSpace) insertRange(r *addressRange) {
559 as.ranges = append(as.ranges, r)
560 sort.Sort(addressRangeSlice(as.ranges))
563 // Remove complete entries or trim existing ones
564 func (as *addressSpace) trimRanges(r *addressRange) {
565 var toRemove []int
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
574 as.deleteEntries(toRemove)
576 var ar *addressRange
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) {
586 // beginning overlap
587 if r.begin <= cur.begin {
588 cur.begin = r.end
589 continue
592 // end overlap
593 if r.end >= cur.end {
594 cur.end = r.begin
595 continue
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
606 // current needs new ending
607 cur.end = r.begin
609 ar = newAddrRange(begin, end, pat, nx)
611 break
615 if ar != nil {
616 as.insertRange(ar)
620 func (as *addressSpace) PrintEntries() {
621 for _, cur := range as.ranges {
622 log.Println(cur)
626 func (as *addressSpace) AddRange(r *addressRange) {
627 as.trimRanges(r)
628 as.insertRange(r)
629 as.mergeRanges()
632 func (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
637 pd := as.pdptes[pdpteIndex].pd
638 pde := &pd.pdes[pdeIndex]
640 if size == SIZE_2MiB {
641 pde.SetMapping(base, pat, nx)
642 return
645 if pde.pt == nil {
646 pde.pt = &pageTable{}
647 // Fetch paging structures as WB
648 pde.SetPageTable(as.newPage(pde.pt), PAT_WB)
651 pte := &pde.pt.ptes[pteIndex]
652 pte.SetMapping(base, pat, nx)
655 func (as *addressSpace) CreatePageTables() {
656 var size uint64
657 var base uint64
659 for _, r := range as.ranges {
660 size = r.Size()
661 base = r.Base()
662 pat := r.Pat()
663 nx := r.Nx()
665 numSmallEntries := 0
666 numBigEntries := 0
668 for size != 0 {
669 mappingSize := SIZE_4KiB
671 if (base&MASK_2MiB) == 0 && size >= SIZE_2MiB {
672 mappingSize = SIZE_2MiB
673 numBigEntries += 1
674 } else {
675 numSmallEntries += 1
678 as.insertMapping(base, mappingSize, pat, nx)
680 base += mappingSize
681 size -= mappingSize
685 log.Printf("%s : %d big %d small\n", r, numBigEntries, numSmallEntries)
689 func (as *addressSpace) PageTableSize() uint {
690 return as.numMetaPages * METADATA_TABLE_SIZE
693 func (as *addressSpace) NumPages() uint {
694 return as.numMetaPages
697 func (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
705 return nil
708 func (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
716 return nil
719 var 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,
728 var 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-",
737 func openCsvFile(file string) (*csv.Reader, error) {
738 f, err := os.Open(file)
740 if err != nil {
741 return nil, err
744 csvr := csv.NewReader(f)
745 csvr.Comment = COMMENT_CHAR
746 csvr.TrimLeadingSpace = true
747 return csvr, nil
750 // After returns true if ar beings at or after other.end.
751 func (ar addressRange) After(other *addressRange) bool {
752 return ar.begin >= other.end
755 func (ar addressRange) FullyOverlaps(other *addressRange) bool {
756 return ar.begin <= other.begin && ar.end >= other.end
759 func (ar addressRange) Overlaps(other *addressRange) bool {
760 if other.end <= ar.begin || other.begin >= ar.end {
761 return false
763 return true
766 func MergeByPat(a, b *addressRange) bool {
767 // 'b' is assumed to be following 'a'
768 if a.end != b.begin {
769 return false
772 if a.pat != b.pat {
773 return false
776 return true
779 func MergeByNx(a, b *addressRange) bool {
780 // 'b' is assumed to be following 'a'
781 if a.end != b.begin {
782 return false
785 if a.nx != b.nx {
786 return false
789 return true
792 func MergeByPatNx(a, b *addressRange) bool {
793 return MergeByPat(a, b) && MergeByNx(a, b)
796 func hexNumber(s string) (uint64, error) {
797 return strconv.ParseUint(strings.TrimSpace(s), 0, 0)
800 func patTypeToString(pat uint) string {
801 return patTypesToString[pat]
804 func patTypeFromString(s string) (uint, error) {
805 s1 := strings.TrimSpace(s)
806 v, ok := pat_types_from_str[s1]
808 if !ok {
809 return 0, fmt.Errorf("No PAT type '%s'", s1)
812 return v, nil
815 func removeComment(field, comment string) string {
816 str_slice := strings.Split(field, comment)
817 return strings.TrimSpace(str_slice[0])
820 func newAddrRange(begin, end uint64, pat uint, nx bool) *addressRange {
821 return &addressRange{begin: begin, end: end, pat: pat, nx: nx}
824 func readRecords(csvr *csv.Reader, as *addressSpace) {
825 i := 0
826 for true {
827 fields, err := csvr.Read()
830 if err == io.EOF {
831 break
834 if err != nil {
835 log.Fatal(err)
838 if len(fields) < 3 {
839 log.Fatal("Need at least 3 fields: begin, end, PAT\n")
842 begin, err := hexNumber(fields[0])
844 if err != nil {
845 log.Fatal(err)
848 end, err := hexNumber(fields[1])
850 if err != nil {
851 log.Fatal(err)
854 if begin&MASK_4KiB != 0 {
855 log.Fatalf("begin %x must be at least 4KiB aligned\n", begin)
858 if end&MASK_4KiB != 0 {
859 log.Fatalf("end %x must be at least 4KiB aligned\n", end)
861 if begin >= end {
862 log.Fatalf("%x must be < %x at record %d\n", begin, end, i)
865 pat, err := patTypeFromString(fields[2])
867 if err != nil {
868 log.Fatal(err)
871 var nx bool = false
873 if len(fields) > 3 && len(removeComment(fields[3], string(COMMENT_CHAR))) > 0 {
874 nx = true
877 as.AddRange(newAddrRange(begin, end, pat, nx))
881 func main() {
882 log.SetFlags(0)
883 flag.Parse()
884 var ptWriters []pageTableEntryWriter
885 var pdptWriters []pageTableEntryWriter
887 if *iomapFilePtr == "" {
888 log.Fatal("No iomap_file provided.\n")
891 csvr, err := openCsvFile(*iomapFilePtr)
892 if err != nil {
893 log.Fatal(err)
896 as := newAddrSpace(MergeByPatNx, *pagesBaseAddress)
897 readRecords(csvr, as)
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)
906 if *ptCFilePtr != "" {
907 f, err := os.Create(*ptCFilePtr)
908 if err != nil {
909 log.Fatal(err)
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)
918 if *ptBinFilePtr != "" {
919 f, err := os.Create(*ptBinFilePtr)
920 if err != nil {
921 log.Fatal(err)
923 defer f.Close()
924 bwr := bufio.NewWriter(f)
925 defer bwr.Flush()
926 bw := &binaryWriter{wr: bwr}
927 ptWriters = append(ptWriters, bw)
930 if *pdptCFilePtr != "" {
931 f, err := os.Create(*pdptCFilePtr)
932 if err != nil {
933 log.Fatal(err)
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)
942 if *pdptBinFilePtr != "" {
943 f, err := os.Create(*pdptBinFilePtr)
944 if err != nil {
945 log.Fatal(err)
947 defer f.Close()
948 bwr := bufio.NewWriter(f)
949 defer bwr.Flush()
950 bw := &binaryWriter{wr: bwr}
951 pdptWriters = append(pdptWriters, bw)
954 // Write out page tables
955 for _, w := range ptWriters {
956 err = as.WritePageTable(w)
957 if err != nil {
958 log.Fatal(err)
962 // Write out pdptes
963 for _, w := range pdptWriters {
964 err = as.WritePageDirectoryPointerTable(w)
965 if err != nil {
966 log.Fatal(err)