summaryrefslogtreecommitdiff
path: root/util/x86/x86_page_tables.go
diff options
context:
space:
mode:
Diffstat (limited to 'util/x86/x86_page_tables.go')
-rw-r--r--util/x86/x86_page_tables.go935
1 files changed, 935 insertions, 0 deletions
diff --git a/util/x86/x86_page_tables.go b/util/x86/x86_page_tables.go
new file mode 100644
index 0000000000..25ad6a2543
--- /dev/null
+++ b/util/x86/x86_page_tables.go
@@ -0,0 +1,935 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+package main
+
+import "bufio"
+import "encoding/binary"
+import "encoding/csv"
+import "flag"
+import "fmt"
+import "io"
+import "log"
+import "os"
+import "sort"
+import "strconv"
+import "strings"
+
+// This program generates 32-bit PAE page tables based on a CSV input file.
+// By default each PDPTE entry is allocated a PD page such that it's easy
+// fault in new entries that are 2MiB aligned and size.
+
+var iomapFilePtr = flag.String("iomap_file", "", "CSV file detailing page table mapping")
+var ptCFilePtr = flag.String("pt_output_c_file", "", "File to write page tables to in C code")
+var ptBinFilePtr = flag.String("pt_output_bin_file", "", "File to write page tables to in binary")
+var pdptCFilePtr = flag.String("pdpt_output_c_file", "", "File to write PDPT to in C code")
+var pdptBinFilePtr = flag.String("pdpt_output_bin_file", "", "File to write PDPT to in binary")
+var pagesBaseAddress = flag.Uint64("metadata_base_address", BASE_ADDR, "Physical base address where metadata pages allocated from")
+
+const (
+ PAT_UC = 0
+ PAT_WC = 1
+ PAT_WT = 4
+ PAT_WP = 5
+ PAT_WB = 6
+ PAT_UCMINUS = 7
+
+ COMMENT_CHAR = '#'
+
+ NUM_PDPTE = 4
+ NUM_PDE = 512
+ NUM_PTE = 512
+
+ SIZE_4KiB = uint64(1 << 12)
+ MASK_4KiB = SIZE_4KiB - 1
+ SIZE_2MiB = uint64(1 << 21)
+ MASK_2MiB = SIZE_2MiB - 1
+
+ // This is a fake physical address for doing fixups when loading
+ // the page tables. There's room for 4096 4KiB physical PD or PTE
+ // tables. Anything with the present bit set will be pointing to an
+ // offset based on this address. At runtime the entries will be fixed up
+ BASE_ADDR = uint64(0xaa000000)
+
+ // Size of PD and PT structures
+ METADATA_TABLE_SIZE = 4096
+
+ PDPTE_PRES = uint64(1 << 0)
+ PDPTE_PWT = uint64(1 << 3)
+ PDPTE_PCD = uint64(1 << 4)
+
+ PDE_PRES = uint64(1 << 0)
+ PDE_RW = uint64(1 << 1)
+ PDE_US = uint64(1 << 2)
+ PDE_PWT = uint64(1 << 3)
+ PDE_PCD = uint64(1 << 4)
+ PDE_A = uint64(1 << 5)
+ PDE_D = uint64(1 << 6) // only valid with PS=1
+ PDE_PS = uint64(1 << 7)
+ PDE_G = uint64(1 << 8) // only valid with PS=1
+ PDE_PAT = uint64(1 << 12) // only valid with PS=1
+ PDE_XD = uint64(1 << 63)
+
+ PTE_PRES = uint64(1 << 0)
+ PTE_RW = uint64(1 << 1)
+ PTE_US = uint64(1 << 2)
+ PTE_PWT = uint64(1 << 3)
+ PTE_PCD = uint64(1 << 4)
+ PTE_A = uint64(1 << 5)
+ PTE_D = uint64(1 << 6)
+ PTE_PAT = uint64(1 << 7)
+ PTE_G = uint64(1 << 8)
+ PTE_XD = uint64(1 << 63)
+
+ PDPTE_IDX_SHIFT = 30
+ PDPTE_IDX_MASK = 0x3
+
+ PDE_IDX_SHIFT = 21
+ PDE_IDX_MASK = 0x1ff
+
+ PTE_IDX_SHIFT = 12
+ PTE_IDX_MASK = 0x1ff
+)
+
+// Different 'writers' implement this interface.
+type pageTableEntryWriter interface {
+ WritePageEntry(data interface{}) error
+}
+
+// The full page objects, page directories and page tables, implement this
+// interface to write their entire contents out
+type pageTableWriter interface {
+ WritePage(wr pageTableEntryWriter) error
+}
+
+type binaryWriter struct {
+ wr io.Writer
+}
+
+func (bw *binaryWriter) WritePageEntry(data interface{}) error {
+ return binary.Write(bw.wr, binary.LittleEndian, data)
+}
+
+type cWriter struct {
+ name string
+ wr io.Writer
+ totalEntries uint
+ currentIndex uint
+}
+
+func newCWriter(wr io.Writer, name string, nr_entries uint) *cWriter {
+ cw := &cWriter{wr: wr, name: name, totalEntries: nr_entries}
+ return cw
+}
+
+func (cw *cWriter) WritePageEntry(data interface{}) error {
+ var entry uint64
+ doPrint := false
+
+ entry, ok := data.(uint64)
+ if !ok {
+ return fmt.Errorf("entry not uint64 %T", data)
+ }
+
+ if cw.currentIndex == 0 {
+ includes := []string{
+ "stdint.h",
+ }
+ for _, l := range includes {
+ if _, err := fmt.Fprintf(cw.wr, "#include <%s>\n", l); err != nil {
+ return err
+ }
+ }
+
+ if _, err := fmt.Fprintf(cw.wr, "uint64_t %s[] = {\n", cw.name); err != nil {
+ return err
+ }
+ }
+
+ if cw.currentIndex%NUM_PTE == 0 {
+ doPrint = true
+ page_num := cw.currentIndex / NUM_PTE
+ if _, err := fmt.Fprintf(cw.wr, "\t/* Page %d */\n", page_num); err != nil {
+ return err
+ }
+ }
+
+ // filter out 0 entries
+ if entry != 0 || doPrint {
+ _, err := fmt.Fprintf(cw.wr, "\t[%d] = %#016xULL,\n", cw.currentIndex, entry)
+ if err != nil {
+ return err
+ }
+ }
+
+ cw.currentIndex += 1
+
+ if cw.currentIndex == cw.totalEntries {
+ if _, err := fmt.Fprintln(cw.wr, "};"); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// This map represents what the IA32_PAT MSR
+var patMsrIndexByType = map[uint]uint{
+ PAT_WB: 0,
+ PAT_WT: 1,
+ PAT_UCMINUS: 2,
+ PAT_UC: 3,
+ // In order to use WP and WC then the IA32_PAT MSR needs to be updated
+ // as these are not the power on reset values.
+ PAT_WP: 6,
+ PAT_WC: 7,
+}
+
+type addressRange struct {
+ begin uint64
+ end uint64
+ pat uint
+ nx bool
+}
+
+type addrRangeMerge func(a, b *addressRange) bool
+
+func (ar *addressRange) Size() uint64 {
+ return ar.end - ar.begin
+}
+
+func (ar *addressRange) Base() uint64 {
+ return ar.begin
+}
+
+func (ar *addressRange) Pat() uint {
+ return ar.pat
+}
+
+func (ar *addressRange) Nx() bool {
+ return ar.nx
+}
+
+func (ar *addressRange) String() string {
+ var nx string
+ if ar.nx {
+ nx = "NX"
+ } else {
+ nx = " "
+ }
+ return fmt.Sprintf("%016x -- %016x %s %s", ar.begin, ar.end, patTypeToString(ar.pat), nx)
+}
+
+type pageTableEntry struct {
+ physAddr uint64
+ flags uint64
+}
+
+func (pte *pageTableEntry) Encode() uint64 {
+ return pte.physAddr | pte.flags
+}
+
+func ptePatFlags(base uint64, pat uint) uint64 {
+ idx, ok := patMsrIndexByType[pat]
+ patStr, _ := patTypesToString[pat]
+
+ if !ok {
+ log.Fatalf("Invalid pat entry for page %x: %s\n", base, patStr)
+ }
+
+ switch idx {
+ case 0:
+ return 0
+ case 1:
+ return PTE_PWT
+ case 2:
+ return PTE_PCD
+ case 3:
+ return PTE_PCD | PTE_PWT
+ case 4:
+ return PTE_PAT
+ case 5:
+ return PTE_PAT | PTE_PWT
+ case 6:
+ return PTE_PAT | PTE_PCD
+ case 7:
+ return PTE_PAT | PTE_PCD | PTE_PWT
+ }
+
+ log.Fatalf("Invalid PAT index %d for PTE %x %s\n", idx, base, patStr)
+ return 0
+}
+
+func (pte *pageTableEntry) SetMapping(base uint64, pat uint, nx bool) {
+ // Present and accessed
+ pte.flags |= PTE_PRES | PTE_A
+
+ // Non write protected entries mark as writable and dirty
+ if pat != PAT_WP {
+ pte.flags |= PTE_RW
+ pte.flags |= PTE_D
+ }
+
+ if nx {
+ pte.flags |= PTE_XD
+ }
+
+ pte.flags |= ptePatFlags(base, pat)
+ pte.physAddr = base
+}
+
+type pageTable struct {
+ ptes [NUM_PTE]pageTableEntry
+}
+
+func (pt *pageTable) WritePage(wr pageTableEntryWriter) error {
+ for i := range pt.ptes {
+ pte := &pt.ptes[i]
+ err := wr.WritePageEntry(pte.Encode())
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+type pageDirectoryEntry struct {
+ physAddr uint64
+ flags uint64
+ pt *pageTable
+}
+
+func (pde *pageDirectoryEntry) Encode() uint64 {
+ return pde.physAddr | pde.flags
+}
+
+func pdeTablePatFlags(pat uint) uint64 {
+ idx, ok := patMsrIndexByType[pat]
+ patStr, _ := patTypesToString[pat]
+
+ if !ok || idx >= 4 {
+ log.Fatalf("Invalid pat entry for PDE page table %s\n", patStr)
+ }
+
+ switch idx {
+ case 0:
+ return 0
+ case 1:
+ return PDE_PWT
+ case 2:
+ return PDE_PCD
+ case 3:
+ return PDE_PCD | PDE_PWT
+ }
+
+ log.Fatalf("Invalid PAT index %d for PDE page table %s\n", idx, patStr)
+ return 0
+}
+
+func pdeLargePatFlags(base uint64, pat uint) uint64 {
+ idx, ok := patMsrIndexByType[pat]
+ patStr, _ := patTypesToString[pat]
+
+ if !ok {
+ log.Fatalf("Invalid pat entry for large page %x: %s\n", base, patStr)
+ }
+
+ switch idx {
+ case 0:
+ return 0
+ case 1:
+ return PDE_PWT
+ case 2:
+ return PDE_PCD
+ case 3:
+ return PDE_PCD | PDE_PWT
+ case 4:
+ return PDE_PAT
+ case 5:
+ return PDE_PAT | PDE_PWT
+ case 6:
+ return PDE_PAT | PDE_PCD
+ case 7:
+ return PDE_PAT | PDE_PCD | PDE_PWT
+ }
+
+ log.Fatalf("Invalid PAT index %d for PDE %x %s\n", idx, base, patStr)
+ return 0
+}
+
+func (pde *pageDirectoryEntry) SetPageTable(pt_addr uint64, pat uint) {
+ // Set writable for whole region covered by page table. Individual
+ // ptes will have the correct writability flags
+ pde.flags |= PDE_PRES | PDE_A | PDE_RW
+
+ pde.flags |= pdeTablePatFlags(pat)
+
+ pde.physAddr = pt_addr
+}
+
+func (pde *pageDirectoryEntry) SetMapping(base uint64, pat uint, nx bool) {
+ // Present, accessed, and large
+ pde.flags |= PDE_PRES | PDE_A | PDE_PS
+
+ // Non write protected entries mark as writable and dirty
+ if pat != PAT_WP {
+ pde.flags |= PDE_RW
+ pde.flags |= PDE_D
+ }
+
+ if nx {
+ pde.flags |= PDE_XD
+ }
+
+ pde.flags |= pdeLargePatFlags(base, pat)
+ pde.physAddr = base
+}
+
+type pageDirectory struct {
+ pdes [NUM_PDE]pageDirectoryEntry
+}
+
+func (pd *pageDirectory) WritePage(wr pageTableEntryWriter) error {
+ for i := range pd.pdes {
+ pde := &pd.pdes[i]
+ err := wr.WritePageEntry(pde.Encode())
+ if err != nil {
+ return nil
+ }
+ }
+ return nil
+}
+
+type pageDirectoryPointerEntry struct {
+ physAddr uint64
+ flags uint64
+ pd *pageDirectory
+}
+
+func (pdpte *pageDirectoryPointerEntry) Encode() uint64 {
+ return pdpte.physAddr | pdpte.flags
+}
+
+func (pdpte *pageDirectoryPointerEntry) Init(addr uint64, pat uint) {
+ idx, ok := patMsrIndexByType[pat]
+
+ // Only 2 bits worth of PAT indexing in PDPTE
+ if !ok || idx >= 4 {
+ patStr, _ := patTypesToString[pat]
+ log.Fatalf("Can't use type '%s' as PDPTE type.\n", patStr)
+ }
+
+ pdpte.physAddr = addr
+ pdpte.flags = PDPTE_PRES
+
+ switch idx {
+ case 0:
+ pdpte.flags |= 0
+ case 1:
+ pdpte.flags |= PDPTE_PWT
+ case 2:
+ pdpte.flags |= PDPTE_PCD
+ case 3:
+ pdpte.flags |= PDPTE_PCD | PDPTE_PWT
+ default:
+ log.Fatalf("Invalid PAT index %d for PDPTE\n", idx)
+ }
+}
+
+type addressSpace struct {
+ ranges []*addressRange
+ mergeFunc addrRangeMerge
+ metatdataBaseAddr uint64
+ pdptes [NUM_PDPTE]pageDirectoryPointerEntry
+ numMetaPages uint
+ page_writers []pageTableWriter
+}
+
+func (as *addressSpace) newPage(pw pageTableWriter) uint64 {
+ v := as.metatdataBaseAddr + METADATA_TABLE_SIZE*uint64(as.numMetaPages)
+ as.numMetaPages += 1
+ as.page_writers = append(as.page_writers, pw)
+ return v
+}
+
+func newAddrSpace(mergeFunc addrRangeMerge, metatdataBaseAddr uint64) *addressSpace {
+ as := &addressSpace{mergeFunc: mergeFunc, metatdataBaseAddr: metatdataBaseAddr}
+ // Fill in all PDPTEs
+ for i := range as.pdptes {
+ pdpte := &as.pdptes[i]
+ pdpte.pd = &pageDirectory{}
+ // fetch paging structures as WB
+ pdpte.Init(as.newPage(pdpte.pd), PAT_WB)
+ }
+ return as
+}
+
+func (as *addressSpace) deleteEntries(indicies []int) {
+ // deletions need to be processed in reverse order so as not
+ // delete the wrong entries
+ sort.Sort(sort.Reverse(sort.IntSlice(indicies)))
+ for _, i := range indicies {
+ as.ranges = append(as.ranges[:i], as.ranges[i+1:]...)
+ }
+}
+
+func (as *addressSpace) mergeRanges() {
+ var toRemove []int
+ var prev *addressRange
+
+ for i, cur := range as.ranges {
+ if prev == nil {
+ prev = cur
+ continue
+ }
+
+ // merge previous with current
+ if as.mergeFunc(prev, cur) {
+ prev.end = cur.end
+ toRemove = append(toRemove, i)
+ cur = prev
+ }
+ prev = cur
+ }
+
+ as.deleteEntries(toRemove)
+}
+
+type addressRangeSlice []*addressRange
+
+func (p addressRangeSlice) Len() int {
+ return len(p)
+}
+
+func (p addressRangeSlice) Less(i, j int) bool {
+ return !p[i].After(p[j])
+}
+
+func (p addressRangeSlice) Swap(i, j int) {
+ p[i], p[j] = p[j], p[i]
+}
+
+func (as *addressSpace) insertRange(r *addressRange) {
+ as.ranges = append(as.ranges, r)
+ sort.Sort(addressRangeSlice(as.ranges))
+}
+
+// Remove complete entries or trim existing ones
+func (as *addressSpace) trimRanges(r *addressRange) {
+ var toRemove []int
+
+ // First remove all entries that are completely overlapped
+ for i, cur := range as.ranges {
+ if r.FullyOverlaps(cur) {
+ toRemove = append(toRemove, i)
+ continue
+ }
+ }
+ as.deleteEntries(toRemove)
+
+ var ar *addressRange
+
+ // Process partial overlaps
+ for _, cur := range as.ranges {
+ // Overlapping may be at beginning, middle, end. Only the
+ // middle overlap needs to create a new range since the
+ // beginning and end overlap can just adjust the current
+ // range.
+ if r.Overlaps(cur) {
+
+ // beginning overlap
+ if r.begin <= cur.begin {
+ cur.begin = r.end
+ continue
+ }
+
+ // end overlap
+ if r.end >= cur.end {
+ cur.end = r.begin
+ continue
+ }
+
+ // middle overlap. create new entry from the hole
+ // punched in the current entry. There's nothing
+ // further to do after this
+ begin := r.end
+ end := cur.end
+ pat := cur.pat
+ nx := cur.nx
+
+ // current needs new ending
+ cur.end = r.begin
+
+ ar = newAddrRange(begin, end, pat, nx)
+
+ break
+ }
+ }
+
+ if ar != nil {
+ as.insertRange(ar)
+ }
+}
+
+func (as *addressSpace) PrintEntries() {
+ for _, cur := range as.ranges {
+ log.Println(cur)
+ }
+}
+
+func (as *addressSpace) AddRange(r *addressRange) {
+ as.trimRanges(r)
+ as.insertRange(r)
+ as.mergeRanges()
+}
+
+func (as *addressSpace) insertMapping(base uint64, size uint64, pat uint, nx bool) {
+ pdpteIndex := (base >> PDPTE_IDX_SHIFT) & PDPTE_IDX_MASK
+ pdeIndex := (base >> PDE_IDX_SHIFT) & PDE_IDX_MASK
+ pteIndex := (base >> PTE_IDX_SHIFT) & PTE_IDX_MASK
+
+ pd := as.pdptes[pdpteIndex].pd
+ pde := &pd.pdes[pdeIndex]
+
+ if size == SIZE_2MiB {
+ pde.SetMapping(base, pat, nx)
+ return
+ }
+
+ if pde.pt == nil {
+ pde.pt = &pageTable{}
+ // Fetch paging structures as WB
+ pde.SetPageTable(as.newPage(pde.pt), PAT_WB)
+ }
+
+ pte := &pde.pt.ptes[pteIndex]
+ pte.SetMapping(base, pat, nx)
+}
+
+func (as *addressSpace) CreatePageTables() {
+ var size uint64
+ var base uint64
+
+ for _, r := range as.ranges {
+ size = r.Size()
+ base = r.Base()
+ pat := r.Pat()
+ nx := r.Nx()
+
+ numSmallEntries := 0
+ numBigEntries := 0
+
+ for size != 0 {
+ mappingSize := SIZE_4KiB
+
+ if (base&MASK_2MiB) == 0 && size >= SIZE_2MiB {
+ mappingSize = SIZE_2MiB
+ numBigEntries += 1
+ } else {
+ numSmallEntries += 1
+ }
+
+ as.insertMapping(base, mappingSize, pat, nx)
+
+ base += mappingSize
+ size -= mappingSize
+
+ }
+
+ log.Printf("%s : %d big %d small\n", r, numBigEntries, numSmallEntries)
+ }
+}
+
+func (as *addressSpace) PageTableSize() uint {
+ return as.numMetaPages * METADATA_TABLE_SIZE
+}
+
+func (as *addressSpace) NumPages() uint {
+ return as.numMetaPages
+}
+
+func (as *addressSpace) WritePageTable(ptew pageTableEntryWriter) error {
+ for _, pw := range as.page_writers {
+ err := pw.WritePage(ptew)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (as *addressSpace) WritePageDirectoryPointerTable(ptew pageTableEntryWriter) error {
+ for i := range as.pdptes {
+ err := ptew.WritePageEntry(as.pdptes[i].Encode())
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+var pat_types_from_str = map[string]uint{
+ "UC": PAT_UC,
+ "WC": PAT_WC,
+ "WT": PAT_WT,
+ "WP": PAT_WP,
+ "WB": PAT_WB,
+ "UC-": PAT_UCMINUS,
+}
+
+var patTypesToString = map[uint]string{
+ PAT_UC: "UC",
+ PAT_WC: "WC",
+ PAT_WT: "WT",
+ PAT_WP: "WP",
+ PAT_WB: "WB",
+ PAT_UCMINUS: "UC-",
+}
+
+func openCsvFile(file string) (*csv.Reader, error) {
+ f, err := os.Open(file)
+
+ if err != nil {
+ return nil, err
+ }
+
+ csvr := csv.NewReader(f)
+ csvr.Comment = COMMENT_CHAR
+ csvr.TrimLeadingSpace = true
+ return csvr, nil
+}
+
+// After returns true if ar beings at or after other.end.
+func (ar addressRange) After(other *addressRange) bool {
+ return ar.begin >= other.end
+}
+
+func (ar addressRange) FullyOverlaps(other *addressRange) bool {
+ return ar.begin <= other.begin && ar.end >= other.end
+}
+
+func (ar addressRange) Overlaps(other *addressRange) bool {
+ if other.end <= ar.begin || other.begin >= ar.end {
+ return false
+ }
+ return true
+}
+
+func MergeByPat(a, b *addressRange) bool {
+ // 'b' is assumed to be following 'a'
+ if a.end != b.begin {
+ return false
+ }
+
+ if a.pat != b.pat {
+ return false
+ }
+
+ return true
+}
+
+func MergeByNx(a, b *addressRange) bool {
+ // 'b' is assumed to be following 'a'
+ if a.end != b.begin {
+ return false
+ }
+
+ if a.nx != b.nx {
+ return false
+ }
+
+ return true
+}
+
+func MergeByPatNx(a, b *addressRange) bool {
+ return MergeByPat(a, b) && MergeByNx(a, b)
+}
+
+func hexNumber(s string) (uint64, error) {
+ return strconv.ParseUint(strings.TrimSpace(s), 0, 0)
+}
+
+func patTypeToString(pat uint) string {
+ return patTypesToString[pat]
+}
+
+func patTypeFromString(s string) (uint, error) {
+ s1 := strings.TrimSpace(s)
+ v, ok := pat_types_from_str[s1]
+
+ if !ok {
+ return 0, fmt.Errorf("No PAT type '%s'", s1)
+ }
+
+ return v, nil
+}
+
+func removeComment(field, comment string) string {
+ str_slice := strings.Split(field, comment)
+ return strings.TrimSpace(str_slice[0])
+}
+
+func newAddrRange(begin, end uint64, pat uint, nx bool) *addressRange {
+ return &addressRange{begin: begin, end: end, pat: pat, nx: nx}
+}
+
+func readRecords(csvr *csv.Reader, as *addressSpace) {
+ i := 0
+ for true {
+ fields, err := csvr.Read()
+ i++
+
+ if err == io.EOF {
+ break
+ }
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if len(fields) < 3 {
+ log.Fatal("Need at least 3 fields: begin, end, PAT\n")
+ }
+
+ begin, err := hexNumber(fields[0])
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ end, err := hexNumber(fields[1])
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if begin&MASK_4KiB != 0 {
+ log.Fatalf("begin %x must be at least 4KiB aligned\n", begin)
+ }
+
+ if end&MASK_4KiB != 0 {
+ log.Fatalf("end %x must be at least 4KiB aligned\n", end)
+ }
+ if begin >= end {
+ log.Fatalf("%x must be < %x at record %d\n", begin, end, i)
+ }
+
+ pat, err := patTypeFromString(fields[2])
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var nx bool = false
+
+ if len(fields) > 3 && len(removeComment(fields[3], string(COMMENT_CHAR))) > 0 {
+ nx = true
+ }
+
+ as.AddRange(newAddrRange(begin, end, pat, nx))
+ }
+}
+
+func main() {
+ log.SetFlags(0)
+ flag.Parse()
+ var ptWriters []pageTableEntryWriter
+ var pdptWriters []pageTableEntryWriter
+
+ if *iomapFilePtr == "" {
+ log.Fatal("No iomap_file provided.\n")
+ }
+
+ csvr, err := openCsvFile(*iomapFilePtr)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ as := newAddrSpace(MergeByPatNx, *pagesBaseAddress)
+ readRecords(csvr, as)
+
+ log.Println("Merged address space:")
+ as.CreatePageTables()
+ log.Println()
+ log.Printf("Total Pages of page tables: %d\n", as.NumPages())
+ log.Println()
+ log.Printf("Pages linked using base address of %#x.\n", *pagesBaseAddress)
+
+ if *ptCFilePtr != "" {
+ f, err := os.Create(*ptCFilePtr)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ bwr := bufio.NewWriter(f)
+ defer bwr.Flush()
+ cw := newCWriter(bwr, "page_tables", as.NumPages()*NUM_PTE)
+ ptWriters = append(ptWriters, cw)
+ }
+
+ if *ptBinFilePtr != "" {
+ f, err := os.Create(*ptBinFilePtr)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ bwr := bufio.NewWriter(f)
+ defer bwr.Flush()
+ bw := &binaryWriter{wr: bwr}
+ ptWriters = append(ptWriters, bw)
+ }
+
+ if *pdptCFilePtr != "" {
+ f, err := os.Create(*pdptCFilePtr)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ bwr := bufio.NewWriter(f)
+ defer bwr.Flush()
+ cw := newCWriter(bwr, "pdptes", NUM_PDPTE)
+ pdptWriters = append(pdptWriters, cw)
+ }
+
+ if *pdptBinFilePtr != "" {
+ f, err := os.Create(*pdptBinFilePtr)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ bwr := bufio.NewWriter(f)
+ defer bwr.Flush()
+ bw := &binaryWriter{wr: bwr}
+ pdptWriters = append(pdptWriters, bw)
+ }
+
+ // Write out page tables
+ for _, w := range ptWriters {
+ err = as.WritePageTable(w)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ // Write out pdptes
+ for _, w := range pdptWriters {
+ err = as.WritePageDirectoryPointerTable(w)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+}