Updated MCTP send code

While the existing documentation is good, there are a couple things that have changed since it was originally written, and I had to make a couple minor adjustments to get it to work. Here’s the code to send a message. The receive part should work as originally published; what is important is the set of headers. I built and ran this on an AARCH64 platform running Fedora 38.

Continue reading

socket system call from python

While the Python socket API is mature, it does not yet support MCTP. I thought I would thus try to make a call from python into native code. The first step is to create a socket. Here is my code to do that.

Note that this is not the entire C code needed to make network call, just the very first step.I did include the code to read errno if the call fails.

#!/usr/bin/python3
from ctypes import *
libc = CDLL("/lib64/libc.so.6")
AF_MCTP = 45
SOCK_DGRAM  = 2
rc = libc.socket (AF_MCTP, SOCK_DGRAM, 0)
#print("rc = %d " % rc)
get_errno_loc = libc.__errno_location
get_errno_loc.restype = POINTER(c_int)
errno = get_errno_loc()[0]
print("rc = %d errno =  %d" % (rc, errno)   )
print("OK")

Running this code on my machine shows success

# ./spdm.py 
rc = 3 errno =  0
OK

Round Trip with MCTP over PCC

The future Ampere System-on-a-chip that is the basis for my work has a couple of processors that are for providing system wide services, not for end users to run things on directly. One of these is called the Management Processor, or Mpro. We have to talk to one of these services from the operating system using the Management Control Transport Protocol, or MCTP, over a Platform Communication Channel (PCC).

I just sent ran a user-land program that sends a message via a socket into the operating system, via PCC, to the MPro, and got a response back.

It took a while for it to sink in. And then I raised my hands in the air and proclaimed in my Best Dr. Frankenstein voice,

“It’s Alive!”

Continue reading

Building a Fedora Based Linux Kernel

We have a few different ways we build a Kernel for internal consumption. One is very minimal, to be used when space is at a premium. Another is very closely based on the Fedora configuration to be used as a replacement Kernel for a Fedora install. While we do provide our team with RPMs to install, development often requires building from source. I’ve done this (and forgotten steps) enough times to want to have a quick reference. The following should work on a recent Fedora install.

Continue reading

Building a Kernel RPM with the Built-in Makefile target

Note that you need to have a .config file that will be included in the build. It will also use the Version as specified in your Makefile. Then run

make rpm-pkg

Which will use the RPM build infra set up for your user to put the rpm in $HOME/rpmbuild/

Edit: Note that a bunch of dependencies are needed to get the Kernel to build. If you run the above command and it fails out with a message that you are missing a dependency, you can use this pair of commands to get the yum-build dep tool installed, and use that to install the dependencies as listed by the generated kernel.spec file.


wget https://src.fedoraproject.org/rpms/kernel/raw/rawhide/f/kernel.spec
yum install dnf-utils
yum-builddep ./kernel.spec

Faking a device via ACPI

I need to write a driver for a device that does not exist yet. So, I am going to use the Linux kernel tooling fro ACPI to create the illusion that the device exists. Here is how.

Devices on an ACPI enabled Linux machine typically exist in a able called the DSDT. This has a real name, but I just thing of it as “Different Stuff Different Table”. However, you can also have a machine specific table that you create at boot time and put entries in there. This is called the SSDT. Again, it has a real name, but I just think of it as “Same Device Different Table” Here is my simple SSDT definition in the ACPI domain specific language.

 /*
 * Template for [SSDT] ACPI Table (AML byte code table)
 */
DefinitionBlock("","SSDT", 2, "Ampere", "_SSDT_01", 0x00000001)
{

    Scope(\_SB)
    {
       Device(MCTP)
       {
           Name (_HID, "MCTPA1B2")

           Name (_STA, 0x0F)
       }
       Device(PLDM)
       {
           Name (_HID, "PLDMA1B2")

           Name (_STA, 0x0F)
       }
       Device(PSTL)
       {
           Name (_HID, "POSTA1B2")

           Name (_STA, 0x0F)
       }
     }

}

Now, this actually has three devices in it, and I was doing some unit testing setup with dependent devices so I though I might use the other ones. I left them in as an example to show how multiple devices look in an SSDT.

To convert this to the binary format, I use iasl, a utility in the acpica-tools RPM. Yes, I still do RPM, although all of this works on Debian based systems as well.

Here is my script to load it into the Linux kernel. It uses a module for the ACPI configuration filesystem.

#! /bin/sh 
modprobe acpi_configfs
mkdir /sys/kernel/config/acpi/table/ssdd
cat ~/acpi/bak/mctpdev.aml > /sys/kernel/config/acpi/table/ssdd/aml

To confirm that the file exists, you can use the acpidump command. If you run it with the -b flag you get all the tables in binary format.

[root@hackery tmp]# mkdir acpi
[root@hackery tmp]# cd acpi/
[root@hackery acpi]# acpidump -b

The iasl command will then decompile the table and you can view the contents. I’ll leave you with the full content.

[root@hackery acpi]# iasl ssdt.dat 

Intel ACPI Component Architecture
ASL+ Optimizing Compiler/Disassembler version 20220331
Copyright (c) 2000 - 2022 Intel Corporation

File appears to be binary: found 31 non-ASCII characters, disassembling
Binary file appears to be a valid ACPI table, disassembling
Input file ssdt.dat, Length 0x83 (131) bytes
ACPI: SSDT 0x0000000000000000 000083 (v02 Ampere _SSDT_01 00000001 INTL 20220331)
Pass 1 parse of [SSDT]
Pass 2 parse of [SSDT]
Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)

Parsing completed
Disassembly completed
ASL Output:    ssdt.dsl - 1141 bytes
[root@hackery acpi]# cat ssdt.dsl 
/*
 * Intel ACPI Component Architecture
 * AML/ASL+ Disassembler version 20220331 (64-bit version)
 * Copyright (c) 2000 - 2022 Intel Corporation
 * 
 * Disassembling to symbolic ASL+ operators
 *
 * Disassembly of ssdt.dat, Sat Jul  8 04:42:31 2023
 *
 * Original Table Header:
 *     Signature        "SSDT"
 *     Length           0x00000083 (131)
 *     Revision         0x02
 *     Checksum         0xCE
 *     OEM ID           "Ampere"
 *     OEM Table ID     "_SSDT_01"
 *     OEM Revision     0x00000001 (1)
 *     Compiler ID      "INTL"
 *     Compiler Version 0x20220331 (539099953)
 */
DefinitionBlock ("", "SSDT", 2, "Ampere", "_SSDT_01", 0x00000001)
{
    Scope (\_SB)
    {
        Device (MCTP)
        {
            Name (_HID, "MCTPA1B2")  // _HID: Hardware ID
            Name (_STA, 0x0F)  // _STA: Status
        }

        Device (PLDM)
        {
            Name (_HID, "PLDMA1B2")  // _HID: Hardware ID
            Name (_STA, 0x0F)  // _STA: Status
        }

        Device (PSTL)
        {
            Name (_HID, "POSTA1B2")  // _HID: Hardware ID
            Name (_STA, 0x0F)  // _STA: Status
        }
    }
}

Testing an MCTP Driver via Echo request

MCTP stands for Management Component Transport Protocol. While it is designed around a server, it is also designed as a network protocol. As such, the Linux implementation makes use of the Socket interface and the Kernel plumbing for dealing with network protocols. To support a new transport mechanism, you implement a new device driver specific to that transport mechanism that implements the struct net_device contract, which includes implementing the functions for struct net_device_ops.

Before I write a full implementation, I want to write something that only echos a packet back to the receiver. This mimics the behavior of the mctp-echo server in the user tools, and can make use of the mctp-req echo client.

Continue reading