xref: /aosp_15_r20/external/coreboot/util/x86/x86_page_tables.go (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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