From 91471c29628ed1fc19e1f4c042d4d819ee5e8669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=85gren?= Date: Tue, 25 Mar 2025 12:59:57 +0100 Subject: [PATCH] tool: Add tool to inspect and create partition table binaries --- .gitignore | 1 + .../tools/partition_table/go.mod | 7 + .../tools/partition_table/go.sum | 4 + .../tools/partition_table/partition_table.go | 172 ++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 hw/application_fpga/tools/partition_table/go.mod create mode 100644 hw/application_fpga/tools/partition_table/go.sum create mode 100644 hw/application_fpga/tools/partition_table/partition_table.go diff --git a/.gitignore b/.gitignore index ac500a4..7dbfeb3 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ /hw/application_fpga/tkey-libs/libcrt0.a /hw/application_fpga/tkey-libs/libmonocypher.a /hw/application_fpga/tkey-libs/libblake2s.a +/hw/application_fpga/tools/partition_table/partition_table synth.json synth.txt synth.v diff --git a/hw/application_fpga/tools/partition_table/go.mod b/hw/application_fpga/tools/partition_table/go.mod new file mode 100644 index 0000000..f14a95d --- /dev/null +++ b/hw/application_fpga/tools/partition_table/go.mod @@ -0,0 +1,7 @@ +module partition_table + +go 1.23.0 + +require golang.org/x/crypto v0.36.0 + +require golang.org/x/sys v0.31.0 // indirect diff --git a/hw/application_fpga/tools/partition_table/go.sum b/hw/application_fpga/tools/partition_table/go.sum new file mode 100644 index 0000000..927b255 --- /dev/null +++ b/hw/application_fpga/tools/partition_table/go.sum @@ -0,0 +1,4 @@ +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= diff --git a/hw/application_fpga/tools/partition_table/partition_table.go b/hw/application_fpga/tools/partition_table/partition_table.go new file mode 100644 index 0000000..f7774a6 --- /dev/null +++ b/hw/application_fpga/tools/partition_table/partition_table.go @@ -0,0 +1,172 @@ +package main + +import ( + "encoding/binary" + "flag" + "fmt" + "io" + "os" + + "golang.org/x/crypto/blake2s" +) + +type PreLoadedAppData struct { + Size uint32 + Digest [32]uint8 + Signature [64]uint8 +} + +type Auth struct { + Nonce [16]uint8 + AuthDigest [16]uint8 +} + +type AppStorage struct { + Status uint8 + Auth Auth +} + +type PartTable struct { + Version uint8 + PreLoadedAppData [2]PreLoadedAppData + AppStorage [4]AppStorage +} + +type PartTableStorage struct { + PartTable PartTable + Digest [16]uint8 +} + +type Flash struct { + Bitstream [0x20000]uint8 + PartitionTableStorage PartTableStorage + PartitionTablePadding [64*1024 - 349]uint8 + PreLoadedApp0 [0x20000]uint8 + PreLoadedApp1 [0x20000]uint8 + AppStorage [4][0x20000]uint8 + EndPadding [0x10000]uint8 +} + +func readStruct[T PartTableStorage | Flash](filename string) T { + var s T + + file, err := os.Open(filename) + if err != nil { + panic(err) + } + + if err := binary.Read(file, binary.LittleEndian, &s); err != nil { + panic(err) + } + + sLen, err := file.Seek(0, io.SeekCurrent) + if err != nil { + panic(err) + } + + fmt.Fprintf(os.Stderr, "INFO: %T struct is %d byte long\n", *new(T), sLen) + + return s +} + +func printPartTableStorageCondensed(storage PartTableStorage) { + fmt.Printf("Partition Table Storage\n") + fmt.Printf(" Partition Table\n") + fmt.Printf(" Header\n") + fmt.Printf(" Version : %d\n", storage.PartTable.Version) + + for i, appData := range storage.PartTable.PreLoadedAppData { + fmt.Printf(" Preloaded App %d\n", i) + fmt.Printf(" Size : %d\n", appData.Size) + fmt.Printf(" Digest : %x\n", appData.Digest[:16]) + fmt.Printf(" %x\n", appData.Digest[16:]) + fmt.Printf(" Signature : %x\n", appData.Signature[:16]) + fmt.Printf(" %x\n", appData.Signature[16:32]) + fmt.Printf(" %x\n", appData.Signature[32:48]) + fmt.Printf(" %x\n", appData.Signature[48:]) + } + fmt.Printf(" Digest : %x\n", storage.Digest) +} + +func calculateStorageDigest(data []byte) []byte { + key := [16]byte{} + + hash, err := blake2s.New128(key[:]) + if err != nil { + panic(err) + } + + hash.Write(data) + digest := hash.Sum([]byte{}) + + return digest +} + +func generatePartTableStorage(outputFilename string, app0Filename string) { + storage := PartTableStorage{ + PartTable: PartTable{ + Version: 1, + PreLoadedAppData: [2]PreLoadedAppData{}, + AppStorage: [4]AppStorage{}, + }, + } + + if app0Filename != "" { + stat, err := os.Stat(app0Filename) + if err != nil { + panic(err) + } + storage.PartTable.PreLoadedAppData[0].Size = uint32(stat.Size()) + } + + buf := make([]byte, 4096, 4096) + len, err := binary.Encode(buf, binary.LittleEndian, storage.PartTable) + if err != nil { + panic(err) + } + fmt.Printf("buf - len: %d, data: %x\n", len, buf[:len]) + + digest := calculateStorageDigest(buf[:len]) + copy(storage.Digest[:], digest) + fmt.Printf("digest: %x\n", digest) + + storageFile, err := os.Create(outputFilename) + if err != nil { + panic(err) + } + + if err := binary.Write(storageFile, binary.LittleEndian, storage); err != nil { + panic(err) + } +} + +func main() { + input := "" + output := "" + app0 := "" + flash := false + + flag.StringVar(&input, "i", "", "Input binary dump file. Cannot be used with -o.") + flag.StringVar(&output, "o", "", "Output binary dump file. Cannot be used with -i.") + flag.StringVar(&app0, "app0", "", "Binary in pre loaded app slot 0. Can be used with -o.") + flag.BoolVar(&flash, "f", false, "Treat input file as a dump of the entire flash memory.") + flag.Parse() + + if (input == "" && output == "") || (input != "" && output != "") { + flag.Usage() + os.Exit(1) + } + + if input != "" { + var storage PartTableStorage + + if flash { + storage = readStruct[Flash](input).PartitionTableStorage + } else { + storage = readStruct[PartTableStorage](input) + } + printPartTableStorageCondensed(storage) + } else if output != "" { + generatePartTableStorage(output, app0) + } +}