13 func readBoardInfo(dir NamedFS
) map[string]string {
14 result
:= make(map[string]string)
15 c
, err
:= fs
.ReadFile(dir
.FS
, filepath
.Join(dir
.Name
, "board_info.txt"))
19 ls
:= strings
.Split(string(c
), "\n")
20 for _
, l
:= range ls
{
21 spl
:= strings
.SplitN(l
, ":", 2)
23 // This shouldn't ever happen, but let's try to
24 // extract as much information from erroneous
25 // board_info files (if they exist) as possible.
28 result
[strings
.TrimSpace(spl
[0])] = strings
.TrimSpace(spl
[1])
33 func fetchBoards(dirs
chan<- NamedFS
) {
35 ds
, err
:= fs
.Glob(cbdirFS
, filepath
.Join("src", "mainboard", "*", "*"))
37 fmt
.Fprintf(os
.Stderr
, "Could not find mainboard directories: %v\n", err
)
40 for _
, d
:= range ds
{
41 if _
, err
:= fs
.ReadDir(cbdirFS
, d
); err
!= nil {
51 var niceVendors
= make(map[string]string)
53 func getNiceVendor(dir
string, vendor
string) (string, error
) {
54 if _
, exists
:= niceVendors
[vendor
]; !exists
{
55 c
, err
:= fs
.ReadFile(cbdirFS
, filepath
.Join(dir
, "..", "Kconfig.name"))
59 re
, err
:= regexp
.Compile("(?i)config VENDOR_" + vendor
)
63 ls
:= strings
.Split(string(c
), "\n")
65 for _
, l
:= range ls
{
67 niceVendors
[vendor
] = strings
.Split(l
, "\"")[1]
70 if re
.Match([]byte(l
)) {
75 return niceVendors
[vendor
], nil
78 func readKconfig(dir NamedFS
) (string, string, string, string, string, error
) {
79 var north
, south
, superio
, cpu
, partnum
string
80 c
, err
:= fs
.ReadFile(dir
.FS
, filepath
.Join(dir
.Name
, "Kconfig"))
82 return north
, south
, superio
, cpu
, partnum
, err
84 ls
:= strings
.Split(string(c
), "\n")
86 for _
, l
:= range ls
{
87 l
= strings
.TrimSpace(l
)
91 // TODO: handling of MAINBOARD_PART_NUMBER is rather broken
92 // and fragile. Doesn't help that many boards use different
93 // part numbers for different models and this code can't
95 if strings
.Contains(strings
.ToLower(l
), "config mainboard_part_number") {
101 if strings
.Contains(l
, "default") {
102 partnum
= strings
.Split(l
, "\"")[1]
106 if l
[0:7] != "select " {
110 if len(l
) > 12 && l
[0:12] == "NORTHBRIDGE_" {
114 if len(l
) > 12 && l
[0:12] == "SOUTHBRIDGE_" {
115 if strings
.Contains(l
, "SKIP_") ||
116 strings
.Contains(l
, "DISABLE_") {
122 if len(l
) > 8 && l
[0:8] == "SUPERIO_" {
126 if len(l
) > 4 && (l
[0:4] == "CPU_" || l
[0:4] == "SOC_") {
127 if strings
.Contains(l
, "AMD_AGESA_FAMILY") ||
128 strings
.Contains(l
, "AMD_COMMON_") ||
129 strings
.Contains(l
, "INTEL_COMMON_") ||
130 strings
.Contains(l
, "INTEL_DISABLE_") ||
131 strings
.Contains(l
, "INTEL_CSE_") ||
132 strings
.Contains(l
, "CPU_MICROCODE_CBFS_NONE") {
138 return north
, south
, superio
, cpu
, partnum
, nil
141 type reReplace
struct {
142 pattern
*regexp
.Regexp
146 func prettify(input
string, rules
*[]reReplace
) string {
147 for _
, rule
:= range *rules
{
148 input
= rule
.pattern
.ReplaceAllString(input
, rule
.replace
)
153 var northbridgeRules
= []reReplace
{
155 pattern
: regexp
.MustCompile("AMD_AGESA_FAMILY([0-9a-fA-F]*)(.*)"),
156 replace
: "AMD Family ${1}h${2} (AGESA)",
159 pattern
: regexp
.MustCompile("AMD_PI_(.*)"),
160 replace
: "AMD ${1} (PI)",
163 pattern
: regexp
.MustCompile("INTEL_FSP_(.*)"),
164 replace
: "Intel® ${1} (FSP)",
167 pattern
: regexp
.MustCompile("AMD_FAMILY([0-9a-fA-F]*)"),
168 replace
: "AMD Family ${1}h,",
171 pattern
: regexp
.MustCompile("AMD_AMDFAM([0-9a-fA-F]*)"),
172 replace
: "AMD Family ${1}h",
175 pattern
: regexp
.MustCompile("_"),
179 pattern
: regexp
.MustCompile("INTEL"),
184 func prettifyNorthbridge(northbridge
string) string {
185 return prettify(northbridge
, &northbridgeRules
)
188 var southbridgeRules
= []reReplace
{
190 pattern
: regexp
.MustCompile("_"),
194 pattern
: regexp
.MustCompile("INTEL"),
199 func prettifySouthbridge(southbridge
string) string {
200 return prettify(southbridge
, &southbridgeRules
)
203 var superIORules
= []reReplace
{
205 pattern
: regexp
.MustCompile("_"),
209 pattern
: regexp
.MustCompile("WINBOND"),
210 replace
: "Winbond™,",
213 pattern
: regexp
.MustCompile("ITE"),
217 pattern
: regexp
.MustCompile("SMSC"),
221 pattern
: regexp
.MustCompile("NUVOTON"),
226 func prettifySuperIO(superio
string) string {
227 return prettify(superio
, &superIORules
)
230 type cpuMapping
struct {
235 var cpuMappings
= map[string]cpuMapping
{
237 cpu
: "Allwinner A10",
241 cpu
: "AMD Geode™ LX",
245 cpu
: "AMD Sempron™ / Athlon™ 64 / Turion™ 64",
246 socket
: "Socket 754",
249 cpu
: "AMD Turion™ II Neo/Athlon™ II Neo",
250 socket
: "ASB2 (BGA812)",
253 cpu
: "AMD Turion™ / X2 Sempron™",
254 socket
: "Socket S1G1",
257 cpu
: "AMD Opteron™ Magny-Cours/Interlagos",
258 socket
: "Socket G34",
260 "AMD_SOCKET_G34_NON_AGESA": {
261 cpu
: "AMD Opteron™ Magny-Cours/Interlagos",
262 socket
: "Socket G34",
265 cpu
: "AMD Opteron™ Magny-Cours/Interlagos",
266 socket
: "Socket C32",
268 "AMD_SOCKET_C32_NON_AGESA": {
269 cpu
: "AMD Opteron™ Magny-Cours/Interlagos",
270 socket
: "Socket C32",
274 socket
: "Socket AM2",
277 cpu
: "AMD Athlon™ 64 / FX / X2",
278 socket
: "Socket AM3",
280 "AMD_SOCKET_AM2R2": {
281 cpu
: "AMD Athlon™ 64 / X2 / FX, Sempron™",
282 socket
: "Socket AM2+",
288 "AMD_SOCKET_F_1207": {
290 socket
: "Socket F 1207",
294 socket
: "Socket 940",
297 cpu
: "AMD Athlon™ 64 / FX / X2",
298 socket
: "Socket 939",
301 cpu
: "AMD Élan™SC520",
304 "AMD_STONEYRIDGE_FP4": {
305 cpu
: "AMD Stoney Ridge",
308 "ARMLTD_CORTEX_A9": {
309 cpu
: "ARM Cortex A9",
313 cpu
: "DMP VORTEX86EX",
317 cpu
: "MediaTek MT8173",
321 cpu
: "NVIDIA Tegra 124",
325 cpu
: "NVIDIA Tegra 210",
328 "SAMSUNG_EXYNOS5420": {
329 cpu
: "Samsung Exynos 5420",
332 "SAMSUNG_EXYNOS5250": {
333 cpu
: "Samsung Exynos 5250",
340 "INTEL_APOLLOLAKE": {
341 cpu
: "Intel® Apollo Lake",
345 cpu
: "Intel® Bay Trail",
349 cpu
: "Intel® Braswell",
353 cpu
: "Intel® Broadwell",
356 "INTEL_DENVERTON_NS": {
357 cpu
: "Intel® Denverton-NS",
360 "INTEL_FSP_BROADWELL_DE": {
361 cpu
: "Intel® Broadwell-DE",
365 cpu
: "Intel® Gemini Lake",
368 "INTEL_GEMINILAKE": {
369 cpu
: "Intel® Gemini Lake",
373 cpu
: "Intel® Ice Lake",
377 cpu
: "Intel® Kaby Lake",
380 "INTEL_SANDYBRIDGE": {
381 cpu
: "Intel® Sandy Bridge",
385 cpu
: "Intel® Skylake",
389 cpu
: "Intel® Pentium® II/III, Celeron®",
392 "INTEL_SOCKET_MPGA604": {
394 socket
: "Socket 604",
397 cpu
: "Intel® Core™ 2 Duo Mobile, Core™ Duo/Solo, Celeron® M",
398 socket
: "Socket M (mPGA478MT)",
400 "INTEL_SOCKET_LGA771": {
401 cpu
: "Intel Xeon™ 5000 series",
402 socket
: "Socket LGA771",
404 "INTEL_SOCKET_LGA775": {
405 cpu
: "Intel® Core 2, Pentium 4/D",
406 socket
: "Socket LGA775",
408 "INTEL_SOCKET_PGA370": {
409 cpu
: "Intel® Pentium® III-800, Celeron®",
410 socket
: "Socket PGA370",
412 "INTEL_SOCKET_MPGA479M": {
413 cpu
: "Intel® Mobile Celeron",
414 socket
: "Socket 479",
417 cpu
: "Intel® 4th Gen (Haswell) Core i3/i5/i7",
420 "INTEL_FSP_RANGELEY": {
421 cpu
: "Intel® Atom Rangeley (FSP)",
424 "INTEL_SOCKET_441": {
425 cpu
: "Intel® Atom™ 230",
426 socket
: "Socket 441",
428 "INTEL_SOCKET_FC_PGA370": {
429 cpu
: "Intel® Pentium® III, Celeron®",
430 socket
: "Socket PGA370",
433 cpu
: "Intel® EP80579",
434 socket
: "Intel® EP80579",
436 "INTEL_SOCKET_MFCBGA479": {
437 cpu
: "Intel® Mobile Celeron",
438 socket
: "Socket 479",
440 "INTEL_WHISKEYLAKE": {
441 cpu
: "Intel® Whiskey Lake",
445 cpu
: "Qualcomm IPQ806x",
449 cpu
: "Qualcomm QCS405",
453 cpu
: "Rockchip RK3288",
457 cpu
: "Rockchip RK3399",
478 func prettifyCPU(cpu
, north
string, northNice
string) (string, string) {
479 if match
, ok
:= cpuMappings
[cpu
]; ok
{
480 return match
.cpu
, match
.socket
483 if match
, ok
:= cpuMappings
[north
]; ok
{
484 return match
.cpu
, match
.socket
486 if north
== "INTEL_IRONLAKE" {
487 return "Intel® 1st Gen (Westmere) Core i3/i5/i7", "?"
489 if north
== "RDC_R8610" {
490 return "RDC R8610", "—"
492 if (len(north
) > 10 && north
[0:10] == "AMD_AGESA_") ||
(len(north
) > 7 && north
[0:7] == "AMD_PI_") {
493 return northNice
, "?"
497 if cpu
== "INTEL_SOCKET_BGA956" {
498 if north
== "INTEL_GM45" {
499 return "Intel® Core 2 Duo (Penryn)", "Socket P"
501 return "Intel® Pentium® M", "BGA956"
503 if cpu
== "INTEL_SOCKET_RPGA989" || cpu
== "INTEL_SOCKET_LGA1155" || cpu
== "INTEL_SOCKET_RPGA988B" {
504 socket
:= "Socket " + cpu
[13:]
505 if north
== "INTEL_HASWELL" {
506 return "Intel® 4th Gen (Haswell) Core i3/i5/i7", socket
508 if north
== "INTEL_IVYBRIDGE" || north
== "INTEL_FSP_IVYBRIDGE" {
509 return "Intel® 3rd Gen (Ivybridge) Core i3/i5/i7", socket
511 if north
== "INTEL_SANDYBRIDGE" {
512 return "Intel® 2nd Gen (Sandybridge) Core i3/i5/i7", socket
519 func collectBoards(dirs
<-chan NamedFS
) {
520 for dir
:= range dirs
{
521 path
:= strings
.Split(dir
.Name
, string(filepath
.Separator
))
522 vendor
, board
:= path
[2], path
[3]
523 vendorNice
, err
:= getNiceVendor(dir
.Name
, vendor
)
526 fmt
.Fprintf(os
.Stderr
, "Could not find nice vendor name for %s: %v\n", dir
.Name
, err
)
530 bi
:= readBoardInfo(dir
)
531 cat
:= Category(bi
["Category"])
532 if _
, ok
:= data
.CategoryNiceNames
[cat
]; !ok
{
535 if bi
["Vendor cooperation score"] == "" {
536 bi
["Vendor cooperation score"] = "—"
539 venboard
:= vendor
+ string(filepath
.Separator
) + board
540 if bi
["Clone of"] != "" {
541 venboard
= bi
["Clone of"]
542 venboard
= strings
.ReplaceAll(venboard
, "/", string(filepath
.Separator
))
543 newpath
:= filepath
.Join(dir
.Name
, "..", "..", venboard
)
547 north
, south
, superio
, cpu
, partnum
, err
:= readKconfig(dir
)
549 fmt
.Fprintf(os
.Stderr
, "'%s' is not a mainboard directory: %v\n", dir
.Name
, err
)
550 // Continue with the path because that's what the
551 // shell script did. We might want to change semantics
554 northbridgeNice
:= prettifyNorthbridge(north
)
555 southbridgeNice
:= prettifySouthbridge(south
)
556 superIONice
:= prettifySuperIO(superio
)
557 cpuNice
, socketNice
:= prettifyCPU(cpu
, north
, northbridgeNice
)
559 boardNice
:= bi
["Board name"]
564 boardNice
= strings
.ReplaceAll(boardNice
, "_", " ")
565 boardNice
= strings
.ToUpper(boardNice
)
570 Vendor2nd
: bi
["Vendor name"],
571 VendorNice
: vendorNice
,
572 VendorBoard
: vendor
+ "/" + board
,
574 BoardNice
: boardNice
,
575 BoardURL
: bi
["Board URL"],
576 NorthbridgeNice
: northbridgeNice
,
577 SouthbridgeNice
: southbridgeNice
,
578 SuperIONice
: superIONice
,
580 SocketNice
: socketNice
,
581 ROMPackage
: bi
["ROM package"],
582 ROMProtocol
: bi
["ROM protocol"],
583 ROMSocketed
: bi
["ROM socketed"],
584 FlashromSupport
: bi
["Flashrom support"],
585 VendorCooperationScore
: bi
["Vendor cooperation score"],
586 VendorCooperationPage
: bi
["Vendor cooperation page"],
588 if b
.ROMPackage
== "" {
591 if b
.ROMProtocol
== "" {
595 if data
.BoardsByCategory
[cat
] == nil {
596 data
.BoardsByCategory
[cat
] = []Board
{}
598 data
.BoardsByCategory
[cat
] = append(data
.BoardsByCategory
[cat
], b
)
600 for ci
:= range data
.BoardsByCategory
{
601 cat
:= data
.BoardsByCategory
[ci
]
602 sort
.Slice(data
.BoardsByCategory
[ci
], func(i
, j
int) bool {
603 if cat
[i
].Vendor
== cat
[j
].Vendor
{
604 return cat
[i
].Board
< cat
[j
].Board
606 return cat
[i
].Vendor
< cat
[j
].Vendor