/ util / autoport / main.go
main.go
  1  /* This is just an experiment. Full automatic porting
  2     is probably not possible but a lot can be automated. */
  3  package main
  4  
  5  import (
  6  	"bytes"
  7  	"flag"
  8  	"fmt"
  9  	"log"
 10  	"os"
 11  	"path/filepath"
 12  	"sort"
 13  	"strings"
 14  )
 15  
 16  type PCIAddr struct {
 17  	Bus  int
 18  	Dev  int
 19  	Func int
 20  }
 21  
 22  type PCIDevData struct {
 23  	PCIAddr
 24  	PCIVenID   uint16
 25  	PCIDevID   uint16
 26  	ConfigDump []uint8
 27  }
 28  
 29  type PCIDevice interface {
 30  	Scan(ctx Context, addr PCIDevData)
 31  }
 32  
 33  type InteltoolData struct {
 34  	GPIO   map[uint16]uint32
 35  	RCBA   map[uint16]uint32
 36  	IOBP   map[uint32]uint32
 37  	IGD    map[uint32]uint32
 38  	MCHBAR map[uint16]uint32
 39  	PMBASE map[uint16]uint32
 40  }
 41  
 42  type DMIData struct {
 43  	Vendor   string
 44  	Model    string
 45  	Version  string
 46  	IsLaptop bool
 47  }
 48  
 49  type AzaliaCodec struct {
 50  	Name        string
 51  	VendorID    uint32
 52  	SubsystemID uint32
 53  	CodecNo     int
 54  	PinConfig   map[int]uint32
 55  }
 56  
 57  type DevReader interface {
 58  	GetPCIList() []PCIDevData
 59  	GetDMI() DMIData
 60  	GetInteltool() InteltoolData
 61  	GetAzaliaCodecs() []AzaliaCodec
 62  	GetACPI() map[string][]byte
 63  	GetCPUModel() []uint32
 64  	GetEC() []byte
 65  	GetIOPorts() []IOPorts
 66  	HasPS2() bool
 67  }
 68  
 69  type IOPorts struct {
 70  	Start uint16
 71  	End   uint16
 72  	Usage string
 73  }
 74  
 75  type SouthBridger interface {
 76  	GetGPIOHeader() string
 77  	EncodeGPE(int) int
 78  	DecodeGPE(int) int
 79  	EnableGPE(int)
 80  	NeedRouteGPIOManually()
 81  }
 82  
 83  var SouthBridge SouthBridger
 84  var BootBlockFiles map[string]string = map[string]string{}
 85  var ROMStageFiles map[string]string = map[string]string{}
 86  var RAMStageFiles map[string]string = map[string]string{}
 87  var SMMFiles map[string]string = map[string]string{}
 88  var MainboardInit string
 89  var MainboardEnable string
 90  var MainboardIncludes []string
 91  
 92  type Context struct {
 93  	MoboID        string
 94  	KconfigName   string
 95  	Vendor        string
 96  	Model         string
 97  	BaseDirectory string
 98  	InfoSource    DevReader
 99  	SaneVendor    string
100  }
101  
102  type Filetype int
103  
104  const (
105  	Ada Filetype = iota
106  	ASL
107  	C
108  	Kconfig
109  	Makefile
110  )
111  
112  var CommentFormatStrings map[Filetype]string = map[Filetype]string {
113  	Ada: "-- %s\n",
114  	ASL: "/* %s */\n",
115  	C: "/* %s */\n",
116  	Kconfig: "## %s\n",
117  	Makefile: "## %s\n",
118  }
119  
120  type License string
121  
122  const (
123      GPL2_only License = "GPL-2.0-only"
124      GPL2_or_later     = "GPL-2.0-or-later"
125  )
126  
127  var KconfigBool map[string]bool = map[string]bool{}
128  var KconfigComment map[string]string = map[string]string{}
129  var KconfigString map[string]string = map[string]string{}
130  var KconfigHex map[string]uint32 = map[string]uint32{}
131  var KconfigInt map[string]int = map[string]int{}
132  var ROMSizeKB = 0
133  var ROMProtocol = ""
134  var FlashROMSupport = ""
135  
136  func GetLE16(inp []byte) uint16 {
137  	return uint16(inp[0]) | (uint16(inp[1]) << 8)
138  }
139  
140  func FormatHexLE16(inp []byte) string {
141  	return fmt.Sprintf("0x%04x", GetLE16(inp))
142  }
143  
144  func FormatHex32(u uint32) string {
145  	return fmt.Sprintf("0x%08x", u)
146  }
147  
148  func FormatHex8(u uint8) string {
149  	return fmt.Sprintf("0x%02x", u)
150  }
151  
152  func FormatInt32(u uint32) string {
153  	return fmt.Sprintf("%d", u)
154  }
155  
156  func FormatHexLE32(d []uint8) string {
157  	u := uint32(d[0]) | (uint32(d[1]) << 8) | (uint32(d[2]) << 16) | (uint32(d[3]) << 24)
158  	return FormatHex32(u)
159  }
160  
161  func FormatBool(inp bool) string {
162  	if inp {
163  		return "1"
164  	} else {
165  		return "0"
166  	}
167  }
168  
169  func sanitize(inp string) string {
170  	result := strings.ToLower(inp)
171  	result = strings.Replace(result, " ", "_", -1)
172  	result = strings.Replace(result, ",", "_", -1)
173  	result = strings.Replace(result, "-", "_", -1)
174  	for strings.HasSuffix(result, ".") {
175  		result = result[0 : len(result)-1]
176  	}
177  	return result
178  }
179  
180  func AddBootBlockFile(Name string, Condition string) {
181  	BootBlockFiles[Name] = Condition
182  }
183  
184  func AddROMStageFile(Name string, Condition string) {
185  	ROMStageFiles[Name] = Condition
186  }
187  
188  func AddRAMStageFile(Name string, Condition string) {
189  	RAMStageFiles[Name] = Condition
190  }
191  
192  func AddSMMFile(Name string, Condition string) {
193  	SMMFiles[Name] = Condition
194  }
195  
196  func IsIOPortUsedBy(ctx Context, port uint16, name string) bool {
197  	for _, io := range ctx.InfoSource.GetIOPorts() {
198  		if io.Start <= port && port <= io.End && io.Usage == name {
199  			return true
200  		}
201  	}
202  	return false
203  }
204  
205  var FlagOutDir = flag.String("coreboot_dir", ".", "Resulting coreboot directory")
206  
207  func writeMF(mf *os.File, files map[string]string, category string) {
208  	keys := []string{}
209  	for file, _ := range files {
210  		keys = append(keys, file)
211  	}
212  
213  	sort.Strings(keys)
214  
215  	for _, file := range keys {
216  		condition := files[file]
217  		if condition == "" {
218  			fmt.Fprintf(mf, "%s-y += %s\n", category, file)
219  		} else {
220  			fmt.Fprintf(mf, "%s-$(%s) += %s\n", category, condition, file)
221  		}
222  	}
223  }
224  
225  func Create(ctx Context, name string) *os.File {
226  	li := strings.LastIndex(name, "/")
227  	if li > 0 {
228  		os.MkdirAll(ctx.BaseDirectory+"/"+name[0:li], 0700)
229  	}
230  	mf, err := os.Create(ctx.BaseDirectory + "/" + name)
231  	if err != nil {
232  		log.Fatal(err)
233  	}
234  	return mf
235  }
236  
237  func Add_SPDX(f *os.File, filetype Filetype, license License) {
238  	Add_Comment(f, filetype, "SPDX-License-Identifier: " + string(license))
239  	fmt.Fprintln(f)
240  }
241  
242  func Add_Comment(f *os.File, filetype Filetype, comment string) {
243  	fmt.Fprintf(f, CommentFormatStrings[filetype], comment)
244  }
245  
246  func RestorePCI16Simple(f *os.File, pcidev PCIDevData, addr uint16) {
247  	fmt.Fprintf(f, "	pci_write_config16(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x);\n",
248  		pcidev.Bus, pcidev.Dev, pcidev.Func, addr,
249  		pcidev.ConfigDump[addr+1],
250  		pcidev.ConfigDump[addr])
251  }
252  
253  func RestorePCI32Simple(f *os.File, pcidev PCIDevData, addr uint16) {
254  	fmt.Fprintf(f, "	pci_write_config32(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x%02x%02x);\n",
255  		pcidev.Bus, pcidev.Dev, pcidev.Func, addr,
256  		pcidev.ConfigDump[addr+3],
257  		pcidev.ConfigDump[addr+2],
258  		pcidev.ConfigDump[addr+1],
259  		pcidev.ConfigDump[addr])
260  }
261  
262  func RestoreRCBA32(f *os.File, inteltool InteltoolData, addr uint16) {
263  	fmt.Fprintf(f, "\tRCBA32(0x%04x) = 0x%08x;\n", addr, inteltool.RCBA[addr])
264  }
265  
266  type PCISlot struct {
267  	PCIAddr
268  	alias             string
269  	additionalComment string
270  	writeEmpty        bool
271  }
272  
273  type DevTreeNode struct {
274  	Bus           int
275  	Dev           int
276  	Func          int
277  	Disabled      bool
278  	Registers     map[string]string
279  	IOs           map[uint16]uint16
280  	Children      []DevTreeNode
281  	PCISlots      []PCISlot
282  	PCIController bool
283  	ChildPCIBus   int
284  	MissingParent string
285  	SubVendor     uint16
286  	SubSystem     uint16
287  	Chip          string
288  	Ops           string
289  	Comment       string
290  }
291  
292  var DevTree DevTreeNode
293  var MissingChildren map[string][]DevTreeNode = map[string][]DevTreeNode{}
294  var unmatchedPCIChips map[PCIAddr]DevTreeNode = map[PCIAddr]DevTreeNode{}
295  var unmatchedPCIDevices map[PCIAddr]DevTreeNode = map[PCIAddr]DevTreeNode{}
296  
297  func Offset(dt *os.File, offset int) {
298  	for i := 0; i < offset; i++ {
299  		fmt.Fprintf(dt, "\t")
300  	}
301  }
302  
303  func MatchDev(dev *DevTreeNode) {
304  	for idx := range dev.Children {
305  		MatchDev(&dev.Children[idx])
306  	}
307  
308  	for _, slot := range dev.PCISlots {
309  		slotDev, ok := unmatchedPCIDevices[slot.PCIAddr]
310  		if !ok {
311  			if slot.writeEmpty {
312  				dev.Children = append(dev.Children,
313  					DevTreeNode{
314  						Registers: map[string]string{},
315  						Chip:      "pci",
316  						Bus:       slot.Bus,
317  						Dev:       slot.Dev,
318  						Func:      slot.Func,
319  						Comment:   slot.additionalComment,
320  						Disabled:  true,
321  					},
322  				)
323  			}
324  			continue
325  		}
326  
327  		if slot.additionalComment != "" && slotDev.Comment != "" {
328  			slotDev.Comment = slot.additionalComment + " " + slotDev.Comment
329  		} else {
330  			slotDev.Comment = slot.additionalComment + slotDev.Comment
331  		}
332  
333  		MatchDev(&slotDev)
334  		dev.Children = append(dev.Children, slotDev)
335  		delete(unmatchedPCIDevices, slot.PCIAddr)
336  	}
337  
338  	for _, slot := range dev.PCISlots {
339  		slotChip, ok := unmatchedPCIChips[slot.PCIAddr]
340  
341  		if !ok {
342  			continue
343  		}
344  
345  		if slot.additionalComment != "" && slotChip.Comment != "" {
346  			slotChip.Comment = slot.additionalComment + " " + slotChip.Comment
347  		} else {
348  			slotChip.Comment = slot.additionalComment + slotChip.Comment
349  		}
350  
351  		delete(unmatchedPCIChips, slot.PCIAddr)
352  		MatchDev(&slotChip)
353  		dev.Children = append(dev.Children, slotChip)
354  	}
355  
356  	if dev.PCIController {
357  		for slot, slotDev := range unmatchedPCIChips {
358  			if slot.Bus == dev.ChildPCIBus {
359  				delete(unmatchedPCIChips, slot)
360  				MatchDev(&slotDev)
361  				dev.Children = append(dev.Children, slotDev)
362  			}
363  		}
364  	}
365  
366  	if dev.MissingParent != "" {
367  		for _, child := range MissingChildren[dev.MissingParent] {
368  			MatchDev(&child)
369  			dev.Children = append(dev.Children, child)
370  		}
371  		delete(MissingChildren, dev.MissingParent)
372  	}
373  
374  	if dev.PCIController {
375  		for slot, slotDev := range unmatchedPCIDevices {
376  			if slot.Bus == dev.ChildPCIBus {
377  				MatchDev(&slotDev)
378  				dev.Children = append(dev.Children, slotDev)
379  				delete(unmatchedPCIDevices, slot)
380  			}
381  		}
382  	}
383  }
384  
385  func writeOn(dt *os.File, dev DevTreeNode) {
386  	if dev.Disabled {
387  		fmt.Fprintf(dt, "off")
388  	} else {
389  		fmt.Fprintf(dt, "on")
390  	}
391  }
392  
393  func WriteDev(dt *os.File, offset int, alias string, dev DevTreeNode) {
394  	Offset(dt, offset)
395  	switch dev.Chip {
396  	case "cpu_cluster", "domain":
397  		fmt.Fprintf(dt, "device %s 0x%x ", dev.Chip, dev.Dev)
398  		writeOn(dt, dev)
399  	case "pci", "pnp":
400  		if alias != "" {
401  			fmt.Fprintf(dt, "device ref %s ", alias)
402  		} else {
403  			fmt.Fprintf(dt, "device %s %02x.%x ", dev.Chip, dev.Dev, dev.Func)
404  		}
405  		writeOn(dt, dev)
406  	case "i2c":
407  		fmt.Fprintf(dt, "device %s %02x ", dev.Chip, dev.Dev)
408  		writeOn(dt, dev)
409  	default:
410  		fmt.Fprintf(dt, "chip %s", dev.Chip)
411  	}
412  	if dev.Comment != "" {
413  		fmt.Fprintf(dt, " # %s", dev.Comment)
414  	}
415  	fmt.Fprintf(dt, "\n")
416  	if dev.Ops != "" {
417  		Offset(dt, offset+1)
418  		fmt.Fprintf(dt, "ops %s\n", dev.Ops)
419  	}
420  	if dev.Chip == "pci" && dev.SubSystem != 0 && dev.SubVendor != 0 {
421  		Offset(dt, offset+1)
422  		fmt.Fprintf(dt, "subsystemid 0x%04x 0x%04x\n", dev.SubVendor, dev.SubSystem)
423  	}
424  
425  	keys := []string{}
426  	for reg, _ := range dev.Registers {
427  		keys = append(keys, reg)
428  	}
429  
430  	sort.Strings(keys)
431  
432  	for _, reg := range keys {
433  		val := dev.Registers[reg]
434  		Offset(dt, offset+1)
435  		fmt.Fprintf(dt, "register \"%s\" = \"%s\"\n", reg, val)
436  	}
437  
438  	ios := []int{}
439  	for reg, _ := range dev.IOs {
440  		ios = append(ios, int(reg))
441  	}
442  
443  	sort.Ints(ios)
444  
445  	for _, reg := range ios {
446  		val := dev.IOs[uint16(reg)]
447  		Offset(dt, offset+1)
448  		fmt.Fprintf(dt, "io 0x%x = 0x%x\n", reg, val)
449  	}
450  
451  	for _, child := range dev.Children {
452  		alias = ""
453  		for _, slot := range dev.PCISlots {
454  			if slot.PCIAddr.Bus == child.Bus &&
455  				slot.PCIAddr.Dev == child.Dev && slot.PCIAddr.Func == child.Func {
456  				alias = slot.alias
457  			}
458  		}
459  		WriteDev(dt, offset+1, alias, child)
460  	}
461  
462  	Offset(dt, offset)
463  	fmt.Fprintf(dt, "end\n")
464  }
465  
466  func PutChip(domain string, cur DevTreeNode) {
467  	MissingChildren[domain] = append(MissingChildren[domain], cur)
468  }
469  
470  func PutPCIChip(addr PCIDevData, cur DevTreeNode) {
471  	unmatchedPCIChips[addr.PCIAddr] = cur
472  }
473  
474  func PutPCIDevParent(addr PCIDevData, comment string, parent string) {
475  	cur := DevTreeNode{
476  		Registers:     map[string]string{},
477  		Chip:          "pci",
478  		Bus:           addr.Bus,
479  		Dev:           addr.Dev,
480  		Func:          addr.Func,
481  		MissingParent: parent,
482  		Comment:       comment,
483  	}
484  	if addr.ConfigDump[0xa] == 0x04 && addr.ConfigDump[0xb] == 0x06 {
485  		cur.PCIController = true
486  		cur.ChildPCIBus = int(addr.ConfigDump[0x19])
487  
488  		loopCtr := 0
489  		for capPtr := addr.ConfigDump[0x34]; capPtr != 0; capPtr = addr.ConfigDump[capPtr+1] {
490  			/* Avoid hangs. There are only 0x100 different possible values for capPtr.
491  			   If we iterate longer than that, we're in endless loop. */
492  			loopCtr++
493  			if loopCtr > 0x100 {
494  				break
495  			}
496  			if addr.ConfigDump[capPtr] == 0x0d {
497  				cur.SubVendor = GetLE16(addr.ConfigDump[capPtr+4 : capPtr+6])
498  				cur.SubSystem = GetLE16(addr.ConfigDump[capPtr+6 : capPtr+8])
499  			}
500  		}
501  	} else {
502  		cur.SubVendor = GetLE16(addr.ConfigDump[0x2c:0x2e])
503  		cur.SubSystem = GetLE16(addr.ConfigDump[0x2e:0x30])
504  	}
505  	unmatchedPCIDevices[addr.PCIAddr] = cur
506  }
507  
508  func PutPCIDev(addr PCIDevData, comment string) {
509  	PutPCIDevParent(addr, comment, "")
510  }
511  
512  type GenericPCI struct {
513  	Comment       string
514  	Bus0Subdiv    string
515  	MissingParent string
516  }
517  
518  type GenericVGA struct {
519  	GenericPCI
520  }
521  
522  type DSDTInclude struct {
523  	Comment string
524  	File    string
525  }
526  
527  type DSDTDefine struct {
528  	Key     string
529  	Comment string
530  	Value   string
531  }
532  
533  var DSDTIncludes []DSDTInclude
534  var DSDTPCI0Includes []DSDTInclude
535  var DSDTDefines []DSDTDefine
536  
537  func (g GenericPCI) Scan(ctx Context, addr PCIDevData) {
538  	PutPCIDevParent(addr, g.Comment, g.MissingParent)
539  }
540  
541  var IGDEnabled bool = false
542  
543  func (g GenericVGA) Scan(ctx Context, addr PCIDevData) {
544  	KconfigString["VGA_BIOS_ID"] = fmt.Sprintf("%04x,%04x",
545  		addr.PCIVenID,
546  		addr.PCIDevID)
547  	PutPCIDevParent(addr, g.Comment, g.MissingParent)
548  	IGDEnabled = true
549  }
550  
551  func makeKconfigName(ctx Context) {
552  	kn := Create(ctx, "Kconfig.name")
553  	defer kn.Close()
554  	Add_SPDX(kn, Kconfig, GPL2_only)
555  
556  	fmt.Fprintf(kn, "config %s\n\tbool \"%s\"\n", ctx.KconfigName, ctx.Model)
557  }
558  
559  func makeComment(name string) string {
560  	cmt, ok := KconfigComment[name]
561  	if !ok {
562  		return ""
563  	}
564  	return " # " + cmt
565  }
566  
567  func makeKconfig(ctx Context) {
568  	kc := Create(ctx, "Kconfig")
569  	defer kc.Close()
570  	Add_SPDX(kc, Kconfig, GPL2_only)
571  
572  	fmt.Fprintf(kc, "if %s\n\n", ctx.KconfigName)
573  
574  	fmt.Fprintf(kc, "config BOARD_SPECIFIC_OPTIONS\n\tdef_bool y\n")
575  	keys := []string{}
576  	for name, val := range KconfigBool {
577  		if val {
578  			keys = append(keys, name)
579  		}
580  	}
581  
582  	sort.Strings(keys)
583  
584  	for _, name := range keys {
585  		fmt.Fprintf(kc, "\tselect %s%s\n", name, makeComment(name))
586  	}
587  
588  	keys = nil
589  	for name, val := range KconfigBool {
590  		if !val {
591  			keys = append(keys, name)
592  		}
593  	}
594  
595  	sort.Strings(keys)
596  
597  	for _, name := range keys {
598  		fmt.Fprintf(kc, `
599  config %s%s
600  	bool
601  	default n
602  `, name, makeComment(name))
603  	}
604  
605  	keys = nil
606  	for name, _ := range KconfigString {
607  		keys = append(keys, name)
608  	}
609  
610  	sort.Strings(keys)
611  
612  	for _, name := range keys {
613  		fmt.Fprintf(kc, `
614  config %s%s
615  	string
616  	default "%s"
617  `, name, makeComment(name), KconfigString[name])
618  	}
619  
620  	keys = nil
621  	for name, _ := range KconfigHex {
622  		keys = append(keys, name)
623  	}
624  
625  	sort.Strings(keys)
626  
627  	for _, name := range keys {
628  		fmt.Fprintf(kc, `
629  config %s%s
630  	hex
631  	default 0x%x
632  `, name, makeComment(name), KconfigHex[name])
633  	}
634  
635  	keys = nil
636  	for name, _ := range KconfigInt {
637  		keys = append(keys, name)
638  	}
639  
640  	sort.Strings(keys)
641  
642  	for _, name := range keys {
643  		fmt.Fprintf(kc, `
644  config %s%s
645  	int
646  	default %d
647  `, name, makeComment(name), KconfigInt[name])
648  	}
649  
650  	fmt.Fprintf(kc, "endif\n")
651  }
652  
653  const MoboDir = "/src/mainboard/"
654  
655  func makeVendor(ctx Context) {
656  	vendor := ctx.Vendor
657  	vendorSane := ctx.SaneVendor
658  	vendorDir := *FlagOutDir + MoboDir + vendorSane
659  	vendorUpper := strings.ToUpper(vendorSane)
660  	kconfig := vendorDir + "/Kconfig"
661  	if _, err := os.Stat(kconfig); os.IsNotExist(err) {
662  		f, err := os.Create(kconfig)
663  		if err != nil {
664  			log.Fatal(err)
665  		}
666  		defer f.Close()
667  		Add_SPDX(f, Kconfig, GPL2_only)
668  		f.WriteString(`if VENDOR_` + vendorUpper + `
669  
670  choice
671  	prompt "Mainboard model"
672  
673  source "src/mainboard/` + vendorSane + `/*/Kconfig.name"
674  
675  endchoice
676  
677  source "src/mainboard/` + vendorSane + `/*/Kconfig"
678  
679  config MAINBOARD_VENDOR
680  	string
681  	default "` + vendor + `"
682  
683  endif # VENDOR_` + vendorUpper + "\n")
684  	}
685  	kconfigName := vendorDir + "/Kconfig.name"
686  	if _, err := os.Stat(kconfigName); os.IsNotExist(err) {
687  		f, err := os.Create(kconfigName)
688  		if err != nil {
689  			log.Fatal(err)
690  		}
691  		defer f.Close()
692  		Add_SPDX(f, Kconfig, GPL2_only)
693  		f.WriteString(`config VENDOR_` + vendorUpper + `
694  	bool "` + vendor + `"
695  `)
696  	}
697  
698  }
699  
700  func GuessECGPE(ctx Context) int {
701  	/* FIXME:XX Use iasl -d and/or better parsing  */
702  	dsdt := ctx.InfoSource.GetACPI()["DSDT"]
703  	idx := bytes.Index(dsdt, []byte{0x08, '_', 'G', 'P', 'E', 0x0a}) /* Name (_GPE, byte).  */
704  	if idx > 0 {
705  		return int(dsdt[idx+6])
706  	}
707  	return -1
708  }
709  
710  func GuessSPDMap(ctx Context) []uint8 {
711  	dmi := ctx.InfoSource.GetDMI()
712  
713  	if dmi.Vendor == "LENOVO" {
714  		return []uint8{0x50, 0x52, 0x51, 0x53}
715  	}
716  	return []uint8{0x50, 0x51, 0x52, 0x53}
717  }
718  
719  func main() {
720  	flag.Parse()
721  
722  	ctx := Context{}
723  
724  	ctx.InfoSource = MakeLogReader()
725  
726  	dmi := ctx.InfoSource.GetDMI()
727  
728  	ctx.Vendor = dmi.Vendor
729  
730  	if dmi.Vendor == "LENOVO" {
731  		ctx.Model = dmi.Version
732  	} else {
733  		ctx.Model = dmi.Model
734  	}
735  
736  	if dmi.IsLaptop {
737  		KconfigBool["SYSTEM_TYPE_LAPTOP"] = true
738  	}
739  	ctx.SaneVendor = sanitize(ctx.Vendor)
740  	for {
741  		last := ctx.SaneVendor
742  		for _, suf := range []string{"_inc", "_co", "_corp"} {
743  			ctx.SaneVendor = strings.TrimSuffix(ctx.SaneVendor, suf)
744  		}
745  		if last == ctx.SaneVendor {
746  			break
747  		}
748  	}
749  	ctx.MoboID = ctx.SaneVendor + "/" + sanitize(ctx.Model)
750  	ctx.KconfigName = "BOARD_" + strings.ToUpper(ctx.SaneVendor+"_"+sanitize(ctx.Model))
751  	ctx.BaseDirectory = *FlagOutDir + MoboDir + ctx.MoboID
752  	KconfigString["MAINBOARD_DIR"] = ctx.MoboID
753  	KconfigString["MAINBOARD_PART_NUMBER"] = ctx.Model
754  
755  	os.MkdirAll(ctx.BaseDirectory, 0700)
756  
757  	makeVendor(ctx)
758  
759  	ScanRoot(ctx)
760  
761  	if IGDEnabled {
762  		KconfigBool["MAINBOARD_HAS_LIBGFXINIT"] = true
763  		KconfigComment["MAINBOARD_HAS_LIBGFXINIT"] = "FIXME: check this"
764  		AddRAMStageFile("gma-mainboard.ads", "CONFIG_MAINBOARD_USE_LIBGFXINIT")
765  	}
766  
767  	if len(BootBlockFiles) > 0 || len(ROMStageFiles) > 0 || len(RAMStageFiles) > 0 || len(SMMFiles) > 0 {
768  		mf := Create(ctx, "Makefile.mk")
769  		defer mf.Close()
770  		Add_SPDX(mf, Makefile, GPL2_only)
771  		writeMF(mf, BootBlockFiles, "bootblock")
772  		writeMF(mf, ROMStageFiles, "romstage")
773  		writeMF(mf, RAMStageFiles, "ramstage")
774  		writeMF(mf, SMMFiles, "smm")
775  	}
776  
777  	devtree := Create(ctx, "devicetree.cb")
778  	defer devtree.Close()
779  
780  	MatchDev(&DevTree)
781  	WriteDev(devtree, 0, "", DevTree)
782  
783  	if MainboardInit != "" || MainboardEnable != "" || MainboardIncludes != nil {
784  		mainboard := Create(ctx, "mainboard.c")
785  		defer mainboard.Close()
786  		Add_SPDX(mainboard, C, GPL2_only)
787  		mainboard.WriteString("#include <device/device.h>\n")
788  		for _, include := range MainboardIncludes {
789  			mainboard.WriteString("#include <" + include + ">\n")
790  		}
791  		mainboard.WriteString("\n")
792  		if MainboardInit != "" {
793  			mainboard.WriteString(`static void mainboard_init(struct device *dev)
794  {
795  ` + MainboardInit + "}\n\n")
796  		}
797  		if MainboardInit != "" || MainboardEnable != "" {
798  			mainboard.WriteString("static void mainboard_enable(struct device *dev)\n{\n")
799  			if MainboardInit != "" {
800  				mainboard.WriteString("\tdev->ops->init = mainboard_init;\n\n")
801  			}
802  			mainboard.WriteString(MainboardEnable)
803  			mainboard.WriteString("}\n\n")
804  			mainboard.WriteString(`struct chip_operations mainboard_ops = {
805  	.enable_dev = mainboard_enable,
806  };
807  `)
808  		}
809  	}
810  
811  	bi := Create(ctx, "board_info.txt")
812  	defer bi.Close()
813  
814  	fixme := ""
815  
816  	if dmi.IsLaptop {
817  		bi.WriteString("Category: laptop\n")
818  	} else {
819  		bi.WriteString("Category: desktop\n")
820  		fixme += "check category, "
821  	}
822  
823  	missing := "ROM package, ROM socketed"
824  
825  	if ROMProtocol != "" {
826  		fmt.Fprintf(bi, "ROM protocol: %s\n", ROMProtocol)
827  	} else {
828  		missing += ", ROM protocol"
829  	}
830  
831  	if FlashROMSupport != "" {
832  		fmt.Fprintf(bi, "Flashrom support: %s\n", FlashROMSupport)
833  	} else {
834  		missing += ", Flashrom support"
835  	}
836  
837  	missing += ", Release year"
838  
839  	if fixme != "" {
840  		fmt.Fprintf(bi, "FIXME: %s, put %s\n", fixme, missing)
841  	} else {
842  		fmt.Fprintf(bi, "FIXME: put %s\n", missing)
843  	}
844  
845  	if ROMSizeKB == 0 {
846  		KconfigBool["BOARD_ROMSIZE_KB_2048"] = true
847  		KconfigComment["BOARD_ROMSIZE_KB_2048"] = "FIXME: correct this"
848  	} else {
849  		KconfigBool[fmt.Sprintf("BOARD_ROMSIZE_KB_%d", ROMSizeKB)] = true
850  	}
851  
852  	makeKconfig(ctx)
853  	makeKconfigName(ctx)
854  
855  	dsdt := Create(ctx, "dsdt.asl")
856  	defer dsdt.Close()
857  	Add_SPDX(dsdt, ASL, GPL2_only)
858  
859  	for _, define := range DSDTDefines {
860  		if define.Comment != "" {
861  			fmt.Fprintf(dsdt, "\t/* %s. */\n", define.Comment)
862  		}
863  		dsdt.WriteString("#define " + define.Key + " " + define.Value + "\n")
864  	}
865  
866  	dsdt.WriteString(
867  `#include <acpi/acpi.h>
868  
869  DefinitionBlock(
870  	"dsdt.aml",
871  	"DSDT",
872  	ACPI_DSDT_REV_2,
873  	OEM_ID,
874  	ACPI_TABLE_CREATOR,
875  	0x20141018
876  )
877  {
878  	#include <acpi/dsdt_top.asl>
879  	#include "acpi/platform.asl"
880  `)
881  
882  	for _, x := range DSDTIncludes {
883  		if x.Comment != "" {
884  			fmt.Fprintf(dsdt, "\t/* %s. */\n", x.Comment)
885  		}
886  		fmt.Fprintf(dsdt, "\t#include <%s>\n", x.File)
887  	}
888  
889  	dsdt.WriteString(`
890  	Device (\_SB.PCI0)
891  	{
892  `)
893  	for _, x := range DSDTPCI0Includes {
894  		if x.Comment != "" {
895  			fmt.Fprintf(dsdt, "\t/* %s. */\n", x.Comment)
896  		}
897  		fmt.Fprintf(dsdt, "\t\t#include <%s>\n", x.File)
898  	}
899  	dsdt.WriteString(
900  		`	}
901  }
902  `)
903  
904  	if IGDEnabled {
905  		gma := Create(ctx, "gma-mainboard.ads")
906  		defer gma.Close()
907  		Add_SPDX(gma, Ada, GPL2_or_later)
908  
909  		gma.WriteString(`with HW.GFX.GMA;
910  with HW.GFX.GMA.Display_Probing;
911  
912  use HW.GFX.GMA;
913  use HW.GFX.GMA.Display_Probing;
914  
915  private package GMA.Mainboard is
916  
917     -- FIXME: check this
918     ports : constant Port_List :=
919       (DP1,
920        DP2,
921        DP3,
922        HDMI1,
923        HDMI2,
924        HDMI3,
925        Analog,
926        LVDS,
927        eDP);
928  
929  end GMA.Mainboard;
930  `)
931  	}
932  	outputPath, _ := filepath.Abs(ctx.BaseDirectory)
933  	fmt.Printf("Done! Generated sources are in %s\n", outputPath)
934  }