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