Skip to content

Commit

Permalink
add block generation routines and fix itemtype and size bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed Sep 22, 2024
1 parent e0dd898 commit a0ab175
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 4 deletions.
61 changes: 59 additions & 2 deletions boot/picobin/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const (
BlockMarkerStart = 0xffffded3
BlockMarkerEnd = 0xab123579
minBlockSize = 4 + 4 + 4 + 4 // Header + last_item + Link + Footer
maskByteSize2 = 1
maskByteSize2 = 1 << 7
)

var (
Expand Down Expand Up @@ -43,7 +43,7 @@ func (b Block) Validate() error {
expectSz := minBlockSize
for i := range b.Items {
if b.Items[i].ItemType() == ItemTypeLast {
return errors.New("block contains last item type")
return errors.New("picobin.Block cannot contain last item type")
}
err := b.Items[i].Validate()
if err != nil {
Expand Down Expand Up @@ -167,6 +167,52 @@ func DecodeNextItem(blockText []byte) (Item, int, error) {
return item, size, nil
}

// AppendBlockFromItems creates a new [Block] and appends its binary representation to dst and returns the result
// as well as the newly created block. It's link points to the next point in memory after appending data and padding with zeros.
// Concatenating various calls of AppendBlockFromItems to the same buffer will concatenate the blocks correctly.
func AppendBlockFromItems(dst []byte, blockItems []Item, data []byte, padZeros int) ([]byte, Block, error) {
if padZeros < 0 {
return nil, Block{}, errors.New("negative padZeros")
}
itemsSize := 0
for i := range blockItems {
itemsSize += blockItems[i].Size()
}
blk := Block{
Items: blockItems,
Link: itemsSize + minBlockSize + len(data) + padZeros,
}
err := blk.Validate()
if err != nil {
return dst, Block{}, err
}
dst = blk.AppendTo(dst)
dst = append(dst, data...)
if padZeros != 0 {
dst = grow(dst, padZeros)
dst = dst[:len(dst)+padZeros]
}
return dst, blk, nil
}

var lastBlockItemList = []Item{makeIgnoredItem()}

// AppendFinalBlock appends a block with Ignore item and a link to the first block.
func AppendFinalBlock(dst []byte, link int) ([]byte, Block, error) {
if link > -minBlockSize {
return nil, Block{}, errors.New("link should point to first block and be negative")
}
blk := Block{
Items: lastBlockItemList,
Link: link,
}
err := blk.Validate()
if err != nil {
return nil, Block{}, err
}
return blk.AppendTo(dst), blk, nil
}

// AppendTo appends block to dst without checking data. Call [Block.Validate] before
// AppendTo to ensure data being appended is sane.
func (b Block) AppendTo(dst []byte) []byte {
Expand Down Expand Up @@ -211,3 +257,14 @@ func b2u8(b bool) uint8 {
}
return 0
}

// grow copied from slices package.
func grow[S ~[]E, E any](s S, n int) S {
if n < 0 {
panic("cannot be negative")
}
if n -= cap(s) - len(s); n > 0 {
s = append(s[:cap(s)], make([]E, n)...)[:len(s)]
}
return s
}
16 changes: 14 additions & 2 deletions boot/picobin/items.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,18 @@ func (imgdef ImageDef) String() string {
imgdef.ImageType().String(), imgdef.ExeSec().String(), imgdef.ExeCPU().String(), imgdef.ExeChip().String())
}

func rawMakeItem(head ItemType, szMod, szDivOrData, tpdata uint8, data []byte) Item {
func rawMakeItem(itemtype ItemType, szMod, szDivOrData, tpdata uint8, data []byte) Item {
var szmask uint8
if itemtype == ItemTypeIgnored || itemtype == ItemTypeLast || len(data) > 255 {
szmask = maskByteSize2
}
sizeAndSpecial := uint16(szMod) | uint16(szDivOrData)<<8
item := Item{
Head: uint8(head), SizeAndSpecial: sizeAndSpecial, TypeData: tpdata, Data: data,
Head: uint8(itemtype) | szmask, SizeAndSpecial: sizeAndSpecial, TypeData: tpdata, Data: data,
}
err := item.Validate()
if err != nil {
panic(err.Error())
}
if item.Size() != len(data)+4 {
panic("bad rawMakeItem size data")
Expand Down Expand Up @@ -197,3 +205,7 @@ type LoadMapEntry struct {
RuntimeStartAbs uint32 // Absolute runtime start address.
SizeOrEndAbs uint32 // Size in bytes if not absolute, storage end address if absolute.
}

func makeIgnoredItem() Item {
return rawMakeItem(ItemTypeIgnored, 1, 0, 0, nil)
}

0 comments on commit a0ab175

Please sign in to comment.