blob: 8fd24eb28161e6dbd5c628fad2bfc19508a7f284 [file] [log] [blame]
Patrick Georgi7333a112020-05-08 20:48:04 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Aaron Durbine5372de2018-02-28 12:59:00 -07002
3package main
4
5import "bufio"
6import "encoding/binary"
7import "encoding/csv"
8import "flag"
9import "fmt"
10import "io"
11import "log"
12import "os"
Aaron Durbin94984a82018-04-25 14:10:46 -060013import "path/filepath"
Aaron Durbine5372de2018-02-28 12:59:00 -070014import "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
Aaron Durbinb5eee6822018-04-19 00:22:02 -060029var 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
Aaron Durbine5372de2018-02-28 12:59:00 -070058const (
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 {
Aaron Durbinb5eee6822018-04-19 00:22:02 -0600164 if _, err := fmt.Fprint(cw.wr, generatedCodeLicense); err != nil {
Aaron Durbin94984a82018-04-25 14:10:46 -0600165 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 }
Aaron Durbine5372de2018-02-28 12:59:00 -0700172 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
Elyes HAOUASbd96a842019-05-18 06:57:07 +0200213// This map represents what the IA32_PAT MSR should be at runtime. The indices
Aaron Durbin2b72e6b2018-04-17 08:45:36 -0600214// 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.
Aaron Durbine5372de2018-02-28 12:59:00 -0700225var patMsrIndexByType = map[uint]uint{
226 PAT_WB: 0,
Aaron Durbin2b72e6b2018-04-17 08:45:36 -0600227 PAT_WC: 1,
Aaron Durbine5372de2018-02-28 12:59:00 -0700228 PAT_UCMINUS: 2,
229 PAT_UC: 3,
Aaron Durbin2b72e6b2018-04-17 08:45:36 -0600230 PAT_WP: 5,
231 PAT_WT: 7,
Aaron Durbine5372de2018-02-28 12:59:00 -0700232}
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
Elyes HAOUASbd96a842019-05-18 06:57:07 +0200513func (as *addressSpace) deleteEntries(indices []int) {
Aaron Durbine5372de2018-02-28 12:59:00 -0700514 // deletions need to be processed in reverse order so as not
515 // delete the wrong entries
Elyes HAOUASbd96a842019-05-18 06:57:07 +0200516 sort.Sort(sort.Reverse(sort.IntSlice(indices)))
517 for _, i := range indices {
Aaron Durbine5372de2018-02-28 12:59:00 -0700518 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}