mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-08-02 11:46:06 -04:00
tool: Rename partition_table to tkeyimage
This commit is contained in:
parent
fab126b695
commit
a1f37d17c9
6 changed files with 10 additions and 10 deletions
114
hw/application_fpga/tools/tkeyimage/README.md
Normal file
114
hw/application_fpga/tools/tkeyimage/README.md
Normal file
|
@ -0,0 +1,114 @@
|
|||
# tkeyimage
|
||||
|
||||
A tool to parse or generate partition table or entire filesystems for
|
||||
the TKey.
|
||||
|
||||
- Parse with `-i file.bin` for "input".
|
||||
- Generate with `-o file.bin` for "output".
|
||||
|
||||
Add `-f` to parse or generate an entire flash image file.
|
||||
|
||||
## Usage
|
||||
|
||||
### Inspect a partition table dump
|
||||
|
||||
Dump the entire data from flash, then inspect:
|
||||
|
||||
```
|
||||
$ tillitis-iceprog -R 1M dump.bin
|
||||
$ ./tkeyimage -i dump.bin -f
|
||||
INFO: main.Flash struct is 1048576 byte long
|
||||
Partition Table Storage
|
||||
Partition Table
|
||||
Header
|
||||
Version : 1
|
||||
Preloaded App 0
|
||||
Size : 23796
|
||||
Digest : 00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
Signature : 00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
Preloaded App 1
|
||||
Size : 264
|
||||
Digest : 96bb4c90603dbbbe09b9a1d7259b5e9e
|
||||
61bedd89a897105c30c9d4bf66a98d97
|
||||
Signature : ccb60c034e559b8c695f25233b80c245
|
||||
e099316324e1a4e68a14c82d834eee58
|
||||
5700cd5c29b64e74159a4dbf3fed030a
|
||||
140e981fb3b6972c125afb4d4497da0a
|
||||
Digest : 4628f142764f724e45e05b20363960967705cfcee8285b2d9d207e04a46e275e
|
||||
```
|
||||
|
||||
Read only the first copy of the partition table from flash to file,
|
||||
then inspect:
|
||||
|
||||
```
|
||||
$ tillitis-iceprog -o 128k -r partition.bin
|
||||
$ ./tkeyimage -i partition.bin
|
||||
INFO: main.PartTableStorage struct is 365 byte long
|
||||
Partition Table Storage
|
||||
Partition Table
|
||||
Header
|
||||
Version : 1
|
||||
Preloaded App 0
|
||||
Size : 23796
|
||||
Digest : 00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
Signature : 00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
Preloaded App 1
|
||||
Size : 0
|
||||
Digest : 00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
Signature : 00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
00000000000000000000000000000000
|
||||
Digest : 40c6dbb4c8fda561369ec54a907452ae352ccbd736ba7824c4e173fd438b7d7a
|
||||
```
|
||||
|
||||
### Generate a partition table
|
||||
|
||||
If you want to generate just a partition table:
|
||||
|
||||
```
|
||||
$ ./tkeyimage -o partition.bin
|
||||
```
|
||||
|
||||
With an app in slot 0, filling in the size in the partition table:
|
||||
|
||||
```
|
||||
$ ./tkeyimage -o partition.bin -app0 ../../fw/testloadapp/testloadapp.bin
|
||||
```
|
||||
|
||||
### Generate flash image
|
||||
|
||||
The program can also generate an entire flash image for use either
|
||||
with real hardware or qemu.
|
||||
|
||||
Generate like this:
|
||||
|
||||
```
|
||||
$ ./tkeyimage -o flash.bin -f -app0 ../../fw/testloadapp/testloadapp.bin
|
||||
```
|
||||
|
||||
Using `-app0` is mandatory because TKey firmware won't start without
|
||||
an app in slot 0.
|
||||
|
||||
The qemu args to use to run with `flash.bin` as the flash are:
|
||||
|
||||
```
|
||||
-drive file=flash.bin,if=mtd,format=raw,index=0
|
||||
```
|
||||
|
||||
A complete command example:
|
||||
|
||||
```
|
||||
$ qemu-system-riscv32 -nographic -M tk1-castor,fifo=chrid \
|
||||
-bios qemu_firmware.elf -chardev pty,id=chrid -s -d guest_errors \
|
||||
-drive file=flash.bin,if=mtd,format=raw,index=0
|
||||
```
|
7
hw/application_fpga/tools/tkeyimage/go.mod
Normal file
7
hw/application_fpga/tools/tkeyimage/go.mod
Normal file
|
@ -0,0 +1,7 @@
|
|||
module tkeyimage
|
||||
|
||||
go 1.23.0
|
||||
|
||||
require golang.org/x/crypto v0.36.0
|
||||
|
||||
require golang.org/x/sys v0.31.0 // indirect
|
4
hw/application_fpga/tools/tkeyimage/go.sum
Normal file
4
hw/application_fpga/tools/tkeyimage/go.sum
Normal file
|
@ -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=
|
266
hw/application_fpga/tools/tkeyimage/tkeyimage.go
Normal file
266
hw/application_fpga/tools/tkeyimage/tkeyimage.go
Normal file
|
@ -0,0 +1,266 @@
|
|||
// SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/blake2s"
|
||||
)
|
||||
|
||||
// Maximum allowed size in bytes of a preloaded app.
|
||||
const MaxAppSize = (128 * 1024)
|
||||
|
||||
// Size in bytes of the partition table binary. Find out with -o and
|
||||
// check the file size.
|
||||
const PartitionSize = 365
|
||||
|
||||
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
|
||||
Checksum [32]byte
|
||||
}
|
||||
|
||||
func (p *PartTableStorage) GenChecksum() {
|
||||
buf := make([]byte, 4096)
|
||||
len, err := binary.Encode(buf, binary.LittleEndian, p.PartTable)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
p.Checksum = blake2s.Sum256(buf[:len])
|
||||
}
|
||||
|
||||
// Name Size Start addr
|
||||
// ---- ---- ----
|
||||
// Bitstream 128KiB 0x00
|
||||
// ---- ---- ----
|
||||
// Partition 64KiB 0x20000
|
||||
// ---- ---- ----
|
||||
// Pre load 0 128KiB 0x30000
|
||||
// Pre load 1 128KiB 0x50000
|
||||
// ---- ---- ----
|
||||
// storage 0 128KiB 0x70000
|
||||
// storage 1 128KiB 0x90000
|
||||
// storage 2 128KiB 0xB0000
|
||||
// storage 3 128KiB 0xD0000
|
||||
// ---- ---- ----
|
||||
// Partition2 64KiB 0xf0000
|
||||
type Flash struct {
|
||||
Bitstream [0x20000]uint8 // Reserved for FPGA bitstream
|
||||
PartitionTable PartTableStorage // 0x20000 partition table
|
||||
PartitionTablePadding [64*1024 - PartitionSize]uint8 // ~64k padding
|
||||
PreLoadedApp0 [0x20000]uint8 // 0x30000
|
||||
PreLoadedApp1 [0x20000]uint8 // 0x50000
|
||||
AppStorage [4][0x20000]uint8 // 0x70000, 4 * 128 storage for apps
|
||||
PartitionTable2 PartTableStorage // 0xf0000 second copy of table
|
||||
PartitionTablePadding2 [64*1024 - PartitionSize]uint8 // ~64k padding
|
||||
}
|
||||
|
||||
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.Checksum)
|
||||
}
|
||||
|
||||
func genPartitionFile(outputFilename string, app0Filename string) {
|
||||
partition := newPartTable(app0Filename)
|
||||
partition.GenChecksum()
|
||||
|
||||
storageFile, err := os.Create(outputFilename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := binary.Write(storageFile, binary.LittleEndian, partition); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// newPartTable generates a new partition table suitable for storage.
|
||||
// If given app0Filename it also fills in the size of the file.
|
||||
//
|
||||
// When you're done with filling in the struct, remember to call
|
||||
// GenChecksum().
|
||||
//
|
||||
// It returns the partition table.
|
||||
func newPartTable(app0Filename string) PartTableStorage {
|
||||
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())
|
||||
}
|
||||
|
||||
return storage
|
||||
}
|
||||
|
||||
func memset(s []byte, c byte) {
|
||||
for i := range s {
|
||||
s[i] = c
|
||||
}
|
||||
}
|
||||
|
||||
func genFlashFile(outputFilename string, app0Filename string) {
|
||||
var flash Flash
|
||||
|
||||
// Set all bits in flash to erased.
|
||||
memset(flash.Bitstream[:], 0xff)
|
||||
// partition0 will be filled in below
|
||||
memset(flash.PartitionTablePadding[:], 0xff)
|
||||
memset(flash.PreLoadedApp0[:], 0xff)
|
||||
memset(flash.PreLoadedApp1[:], 0xff)
|
||||
memset(flash.AppStorage[0][:], 0xff)
|
||||
memset(flash.AppStorage[1][:], 0xff)
|
||||
memset(flash.AppStorage[2][:], 0xff)
|
||||
memset(flash.AppStorage[3][:], 0xff)
|
||||
// partition1 will be filled in below
|
||||
memset(flash.PartitionTablePadding2[:], 0xff)
|
||||
|
||||
partition := newPartTable(app0Filename)
|
||||
partition.GenChecksum()
|
||||
|
||||
flash.PartitionTable = partition
|
||||
flash.PartitionTable2 = partition
|
||||
|
||||
// Read the entire file.
|
||||
appBuf, err := os.ReadFile(app0Filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(appBuf) > MaxAppSize {
|
||||
fmt.Printf("max app size is 128 k")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
copy(flash.PreLoadedApp0[:], appBuf)
|
||||
|
||||
storageFile, err := os.Create(outputFilename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := binary.Write(storageFile, binary.LittleEndian, flash); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var input string
|
||||
var output string
|
||||
var app0 string
|
||||
var flash bool
|
||||
|
||||
flag.StringVar(&input, "i", "", "Input binary file. Cannot be used with -o.")
|
||||
flag.StringVar(&output, "o", "", "Output binary file. Cannot be used with -i. If used with -f, -app0 must also be specified.")
|
||||
flag.StringVar(&app0, "app0", "", "Binary in pre loaded app slot 0. Can be used with -o.")
|
||||
flag.BoolVar(&flash, "f", false, "Treat file as a dump of the entire flash memory.")
|
||||
flag.Parse()
|
||||
|
||||
if len(flag.Args()) > 0 {
|
||||
fmt.Printf("superfluous args\n")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if (input == "" && output == "") || (input != "" && output != "") {
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if input != "" {
|
||||
var storage PartTableStorage
|
||||
|
||||
if flash {
|
||||
storage = readStruct[Flash](input).PartitionTable
|
||||
} else {
|
||||
storage = readStruct[PartTableStorage](input)
|
||||
}
|
||||
printPartTableStorageCondensed(storage)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if output != "" {
|
||||
if flash {
|
||||
if app0 == "" {
|
||||
fmt.Printf("need -app0 path/to/app\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
genFlashFile(output, app0)
|
||||
} else {
|
||||
genPartitionFile(output, app0)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue