8000 Rb info by AjanZhong · Pull Request #3357 · u-root/u-root · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Rb info #3357

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 6, 2025
Merged

Rb info #3357

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
330 changes: 315 additions & 15 deletions pkg/boot/universalpayload/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,54 @@
Reserved [2]uint16
}

type MCFGBaseAddressAllocation struct {
BaseAddr EFIPhysicalAddress
PCISegGrp uint16
StartBus uint8
EndBus uint8
Reserved uint32
}

type ResourceInfo struct {
Type string
BaseAddress string
EndAddress string
Attributes string
}

type ResourceRegions struct {
MMIO64Base uint64
MMIO64Limit uint64
MMIO32Base uint64
MMIO32Limit uint64
IOPortBase uint64
IOPortLimit uint64
}

const (
ACPIMCFGSysFilePath = "/sys/firmware/acpi/tables/MCFG"
ACPIMCFGPciSegInfoStructureSize = 0xC
ACPIMCFGPciSegInfoDataLength = 0xA
ACPIMCFGBaseAddressAllocationLenth = 0x10
ACPIMCFGBaseAddressAllocationOffset = 0x2c
ACPIMCFGSignature = "MCFG"
)

const (
PCISearchPath = "/sys/bus/pci/devices/"
PCIMMIO64Attr = 0x140204
PCIMMIO32Attr = 0x40200
PCIIOPortAttr = 0x40100
PCIMMIOReadOnly = 0x4000
PCIMMIO64Type = "MMIO64"
PCIMMIO32Type = "MMIO32"
PCIIOPortType = "IOPORT"

PCIMMIO64InvalidBase = 0xFFFF_FFFF_FFFF_FFFF
PCIMMIO32InvalidBase = 0xFFFF_FFFF< 10000 /td>
PCIIOPortInvalidBase = 0xFFFF
)

type FdtLoad struct {
Load uint64
EntryStart uint64
Expand Down Expand Up @@ -219,6 +267,10 @@
ErrCPUAddressConvert = errors.New("failed to convert physical bits size")
ErrCPUAddressRead = errors.New("failed to read 'address sizes'")
ErrCPUAddressNotFound = errors.New("'address sizes' information not found")
ErrMcfgDataLenthTooShort = errors.New("acpi mcfg data lenth too short")
ErrMcfgSignatureMismatch = errors.New("acpi mcfg signature mismatch")
ErrMcfgBaseAddrAllocCorrupt = errors.New("acpi mcfg base address allocation data corrupt")
ErrMcfgBaseAddrAllocDecode = errors.New("failed to decode mcfg base address allocation structure")
)

func parseUint64ToUint32(val uint64) uint32 {
Expand Down Expand Up @@ -672,6 +724,7 @@
)),
dt.NewNode("upl-params", dt.WithProperty(
dt.PropertyU32("addr-width", uint32(phyAddrSize)),
dt.PropertyU32("pci-enum-done", 1),
dt.PropertyString("boot-mode", "normal"),
)),
dt.NewNode("upl-custom", dt.WithProperty(
Expand Down Expand Up @@ -715,6 +768,245 @@
return dt.NewNode("reserved-memory", dt.WithChildren(rsvdNodes...))
}

func retrieveRootBridgeResources(path string, item MCFGBaseAddressAllocation) (*ResourceRegions, error) {
domainIDHex := fmt.Sprintf("%04x", item.PCISegGrp)

var MMIO64Base uint64 = PCIMMIO64InvalidBase
var MMIO32Base uint64 = PCIMMIO32InvalidBase
var IOPortBase uint64 = PCIIOPortInvalidBase
var mmio64End uint64
var mmio32End uint64
var ioPortEnd uint64

err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

Check warning on line 784 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L783-L784

Added lines #L783 - L784 were not covered by tests

deviceName := filepath.Base(path)
parts := strings.Split(deviceName, ":")
// deviceName fetched from filepath can be separated into 3 parts:
// 0000:00:00.0 which is DOMAIN_ID:BUS_ID:DEVICE_ID:FUNCTION_ID
// To retrieve the memory resource regions for 64-bit/32-bit MMIO
// and IO, we need to ensure:
// 1. Domain ID matches
// 2. Bus ID is valid
if len(parts) != 3 || parts[0] != domainIDHex {
// Skip unmatched Bus number
return nil
}

if bus, err := strconv.ParseUint(parts[1], 16, 64); err != nil {
// Should not happen, if failed to parse Bus number, return error directly
return err

Check warning on line 801 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L800-L801

Added lines #L800 - L801 were not covered by tests
} else if (bus >= uint64(item.StartBus)) && (bus <= uint64(item.EndBus)) {
resourcePath := filepath.Join(path, "resource")
resources, err := retrieveDeviceResources(resourcePath)
if err != nil {
return nil // Continue scanning other devices
}

Check warning on line 807 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L806-L807

Added lines #L806 - L807 were not covered by tests
for _, res := range resources {
if base, err := strconv.ParseUint(res.BaseAddress, 0, 64); err != nil {
// Should not happen, if failed to parse uint, skip this region
continue

Check warning on line 811 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L810-L811

Added lines #L810 - L811 were not covered by tests
} else if end, err := strconv.ParseUint(res.EndAddress, 0, 64); err != nil {
// Should not happen, if failed to parse uint, skip this region
continue

Check warning on line 814 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L813-L814

Added lines #L813 - L814 were not covered by tests
} else {
// Region found, merge it to domain resource region
switch res.Type {
case PCIMMIO64Type:
MMIO64Base = min(base, MMIO64Base)
mmio64End = max(end, mmio64End)
case PCIMMIO32Type:
MMIO32Base = min(base, MMIO32Base)
mmio32End = max(end, mmio32End)
case PCIIOPortType:
IOPortBase = min(base, IOPortBase)
ioPortEnd = max(end, ioPortEnd)
}
}
}
}

return nil
})

if err != nil {
return nil, err
}

Check warning on line 837 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L836-L837

Added lines #L836 - L837 were not covered by tests

return &ResourceRegions{
MMIO64Base: MMIO64Base,
MMIO64Limit: mmio64End - MMIO64Base + 1,
MMIO32Base: MMIO32Base,
MMIO32Limit: mmio32End - MMIO32Base + 1,
IOPortBase: IOPortBase,
IOPortLimit: ioPortEnd - IOPortBase + 1,
}, nil
}

func retrieveDeviceResources(resourcePath string) ([]ResourceInfo, error) {
contentBytes, err := os.ReadFile(resourcePath)
if err != nil {
return nil, err
}

Check warning on line 853 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L852-L853

Added lines #L852 - L853 were not covered by tests

content := string(contentBytes)
lines := strings.Split(content, "\n")
var resources []ResourceInfo

for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue
}
parts := strings.Split(line, " ")

if len(parts) == 3 {
base := strings.TrimSpace(parts[0])
end := strings.TrimSpace(parts[1])
attr := strings.TrimSpace(parts[2])

if attrInt, err := strconv.ParseUint(attr, 0, 64); err != nil {
// Should not happen, skip this line in case it happens
continue

Check warning on line 873 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L872-L873

Added lines #L872 - L873 were not covered by tests
} else {
var resourceType string
if attrInt&PCIMMIOReadOnly != 0 {
// Skip ReadOnly MMIO, this is ROM region
continue
}

if attrInt&PCIMMIO64Attr == PCIMMIO64Attr {
base64, err := strconv.ParseUint(base, 0, 64)
if err == nil {
// Some platform provides 64-bit MMIO with all zero in high 32 bits,
// it leads to huge MMIO region for 64-bit, and triggers assertation
// in EDK2 since it is actual a 32-bit address, not a 64-bit address.
//
// Skip this scenario to address above issue.
if base64>>32 == 0 {
continue
}
}
resourceType = PCIMMIO64Type
} else if attrInt&PCIMMIO32Attr == PCIMMIO32Attr {
resourceType = PCIMMIO32Type
} else if attrInt&PCIIOPortAttr == PCIIOPortAttr {
// Do not care about IRQ specific bits (BITS 0~5)
resourceType = PCIIOPortType
} else {
continue // Skip unknown resource types
}

resources = append(resources, ResourceInfo{
Type: resourceType,
BaseAddress: base,
EndAddress: end,
Attributes: attr,
})
}
}
}
return resources, nil
}

func fetchACPIMCFGData(data []byte) ([]MCFGBaseAddressAllocation, error) {
var mcfgDataArray []MCFGBaseAddressAllocation

// Check if the data is long enough to contain data from offset 0x2c.
if len(data) <= ACPIMCFGBaseAddressAllocationOffset {
return nil, ErrMcfgDataLenthTooShort
}

// Check if the magic word is "MCFG".
if !bytes.Equal(data[:4], []byte(ACPIMCFGSignature)) {
return nil, ErrMcfgSignatureMismatch
}

segInfoContent := data[ACPIMCFGBaseAddressAllocationOffset:]

// Check whether content in Base Address Allocation Structure is valid
if len(segInfoContent)%ACPIMCFGBaseAddressAllocationLenth != 0 {
return nil, ErrMcfgBaseAddrAllocCorrupt
}

for i := 0; i < len(segInfoContent); i += ACPIMCFGBaseAddressAllocationLenth {
mcfgDataBytes := segInfoContent[i : i+ACPIMCFGBaseAddressAllocationLenth]
mcfgData := MCFGBaseAddressAllocation{}
reader := bytes.NewReader(mcfgDataBytes)

err := binary.Read(reader, binary.LittleEndian, &mcfgData)
if err != nil {
return nil, ErrMcfgBaseAddrAllocDecode
}

Check warning on line 943 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L942-L943

Added lines #L942 - L943 were not covered by tests

mcfgDataArray = append(mcfgDataArray, mcfgData)
}
return mcfgDataArray, nil
}

func createPCIRootBridgeNode(path string, item MCFGBaseAddressAllocation) (*dt.Node, error) {
high64 := func(val uint64) uint32 {
return uint32(val >> 32)
}

low64 := func(val uint64) uint32 {
return uint32(val & 0x0000_0000_FFFF_FFFF)
}

resource, err := retrieveRootBridgeResources(path, item)
if err != nil {
return nil, err
}

Check warning on line 962 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L961-L962

Added lines #L961 - L962 were not covered by tests

return dt.NewNode("pci-rb", dt.WithProperty(
dt.PropertyString("compatible", "pci-rb"),
dt.PropertyU64("reg", uint64(item.BaseAddr)),
dt.PropertyU32Array("bus-range", []uint32{uint32(item.StartBus), uint32(item.EndBus)}),
dt.PropertyU32Array("ranges", []uint32{
0x300_0000, // 64BITS
high64(resource.MMIO64Base), low64(resource.MMIO64Base),
0x0, 0x0,
high64(resource.MMIO64Limit), low64(resource.MMIO64Limit),
0x200_0000, // 32BITS
high64(resource.MMIO32Base), low64(resource.MMIO32Base),
0x0, 0x0,
high64(resource.MMIO32Limit), low64(resource.MMIO32Limit),
0x100_0000, // IO
high64(resource.IOPortBase), low64(resource.IOPortBase),
0x0, 0x0,
high64(resource.IOPortLimit), low64(resource.IOPortLimit),
}),
)), nil
}

func constructPCIRootBridgeNodes() ([]*dt.Node, error) {
var rbNodes []*dt.Node

fileData, err := os.ReadFile(ACPIMCFGSysFilePath)
if err != nil {
return nil, err
}

mcfgData, err := fetchACPIMCFGData(fileData)
if err != nil {
return nil, err
}

Check warning on line 996 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L993-L996

Added lines #L993 - L996 were not covered by tests

for _, item := range mcfgData {
rbNode, err := createPCIRootBridgeNode(PCISearchPath, item)
if err != nil {
return nil, err
}

Check warning on line 1002 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L998-L1002

Added lines #L998 - L1002 were not covered by tests

rbNodes = append(rbNodes, rbNode)

Check warning on line 1004 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch FCCD

pkg/boot/universalpayload/utilities.go#L1004

Added line #L1004 was not covered by tests

}
return rbNodes, nil

Check warning on line 1007 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L1007

Added line #L1007 was not covered by tests
}

func buildDeviceTreeInfo(buf io.Writer, mem *kexec.Memory, loadAddr uint64, rsdpBase uint64) error {
memNodes := buildDtMemoryNode(mem)

Expand All @@ -727,30 +1019,38 @@
return err
}

gmaNode, err := buildGraphicNode()
if err != nil {
serialPortNode := constructSerialPortNode()

dtNodes := append(memNodes, rsvdMemNode)
dtNodes = append(dtNodes, optionsNode)
dtNodes = append(dtNodes, serialPortNode)

if gmaNode, err := buildGraphicNode(); err != nil {
// If we failed to retrieve Graphic configurations, prompt error
// message to indicate error message, and continue construct DTB.
warningMsg = append(warningMsg, err)
} else {
dtNodes = append(dtNodes, gmaNode)
}

fbNode, err := buildFrameBufferNode()
if err != nil {
if fbNode, err := buildFrameBufferNode(); err != nil {
// If we failed to retrieve Frame Buffer configurations, prompt error
// message to indicate error message, and continue construct DTB.
warningMsg = append(warningMsg, err)
}

serialPortNode := constructSerialPortNode()

dtNodes := append(memNodes, rsvdMemNode)
dtNodes = append(dtNodes, serialPortNode)
dtNodes = append(dtNodes, optionsNode)

if fbNode != nil {
} else {
dtNodes = append(dtNodes, fbNode)

}

if gmaNode != nil {
dtNodes = append(dtNodes, gmaNode)
if pciRbNodes, err := constructPCIRootBridgeNodes(); err != nil {
// If we failed to construct PCI Root Bridge info, prompt error
// message to indicate error message, and continue construct DTB.
// In this case, allows UPL to scan PCI Bus itself.
warningMsg = append(warningMsg, err)
} else {
if pciRbNodes != nil {
dtNodes = append(dtNodes, pciRbNodes...)
}

Check warning on line 1053 in pkg/boot/universalpayload/utilities.go

View check run for this annotation

Codecov / codecov/patch

pkg/boot/universalpayload/utilities.go#L1051-L1053

Added lines #L1051 - L1053 were not covered by tests
}

dtHeader := dt.Header{
Expand Down
Loading
Loading
0