Skip to content

Instantly share code, notes, and snippets.

@quarnster
Last active December 21, 2015 06:19
Show Gist options
  • Save quarnster/6263313 to your computer and use it in GitHub Desktop.
Save quarnster/6263313 to your computer and use it in GitHub Desktop.
Go code for dumping the raw nandflash data from Boxeebox's /dev/spectra
// GOOS=linux GOARCH=386 go build flash.go && ftp -u boxeebox:/tmp/flash flash
package main
import (
"fmt"
"log"
"os"
"syscall"
"unsafe"
)
type (
BLOCKNODE uint32
PAGENUMTYPE uint16
PAGESIZETYPE uint16
BLOCKSIZETYPE uint32
ADDRESSTYPE uintptr
BOOT_BLOCKTABLE_IO_CMD struct {
btEntrySizeInBits byte
btEntryNum uint16
AddrInRam ADDRESSTYPE
}
BOOT_BLOCKTABLE_INFO struct {
bt_sig [4]byte
nSpareSkipByteInZone1, nSpareSkipByteInZone0, reserve3, btEntrySizeInBits byte
btEntryNum, btOffsetInBytes, md5OffsetInBytes, md5SizeInBytes uint16
}
SPEC_IO_CMD struct {
NumPagesToTransfer uint32
AddrInRam ADDRESSTYPE
StartBlockNum BLOCKNODE
StartPageNum uint16
}
DEVICE_INFO struct {
wDeviceMaker uint16
wDeviceType uint32
wSpectraStartBlock BLOCKNODE
wSpectraEndBlock BLOCKNODE
wBlockNum BLOCKNODE
wTotalBlocks BLOCKNODE
wPagesPerBlock PAGENUMTYPE
wPageSize PAGESIZETYPE
wPageDataSize PAGESIZETYPE
wPageSpareSize PAGESIZETYPE
wNumPageSpareFlag uint16
wECCBytesPerSector uint16
wBlockSize BLOCKSIZETYPE
wBlockDataSize BLOCKSIZETYPE
wDataBlockNum BLOCKNODE
bPlaneNum byte
wDeviceMainAreaSize uint16
wDeviceSpareAreaSize uint16
wDevicesConnected uint16
wDeviceWidth uint16
wHWRevision uint16
wHWFeatures uint16
wONFIDevFeatures uint16
wONFIOptCommands uint16
wONFITimingMode uint16
wONFIPgmCacheTimingMode uint16
MLCDevice uint16
wSpareSkipBytes uint16
}
)
const (
GLOB_SBD_IOCTL_RD_MAIN = 0x8810 + iota
GLOB_SBD_IOCTL_WR_MAIN
GLOB_SBD_IOCTL_ERASE
GLOB_SBD_IOCTL_RD_ID
GLOB_SBD_IOCTL_CHK_BADBLK
GLOB_SBD_IOCTL_RD_MAIN_SPARE_RAW
GLOB_SBD_IOCTL_WR_MAIN_SPARE_RAW
)
const (
GLOB_SBD_IOCTL_ERASE_RAW = 0x9910 + iota
GLOB_SBD_IOCTL_RD_BT
GLOB_SBD_IOCTL_CREATE_BT_DUMMY
GLOB_SBD_IOCTL_CREATE_BT_BYERASE
GLOB_SBD_IOCTL_CREATE_BT_BYMARKER
GLOB_SBD_IOCTL_ERASE_BYMARKER
)
func ioctl(device int, cmd uintptr, data unsafe.Pointer) (int, error) {
a, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device), cmd, uintptr(data))
var err error
if errno != 0 {
err = errno
}
return int(a), err
}
func main() {
var (
id DEVICE_INFO
read SPEC_IO_CMD
)
device, err := syscall.Open("/dev/spectra", syscall.O_RDONLY, 0)
if err != nil || device < 0 {
log.Fatalf("Device is negative: %d, %s", device, err)
}
defer syscall.Close(device)
log.Println("device:", device)
if _, err := ioctl(device, GLOB_SBD_IOCTL_RD_ID, unsafe.Pointer(&id)); err != nil {
log.Fatalln(err)
}
log.Printf("%+v", id)
data := make([]byte, int(id.wPageSize)*int(id.wPagesPerBlock))
read.StartBlockNum = 8
read.AddrInRam = ADDRESSTYPE(unsafe.Pointer(&data[0]))
read.NumPagesToTransfer = uint32(id.wPagesPerBlock)
log.Println(ioctl(device, GLOB_SBD_IOCTL_RD_MAIN, unsafe.Pointer(&read)))
log.Printf("%+v", *(*BOOT_BLOCKTABLE_INFO)(unsafe.Pointer(&data[32])))
for read.StartBlockNum = 0; read.StartBlockNum < id.wBlockNum; read.StartBlockNum++ {
func() {
fn := fmt.Sprintf("/tmp/mnt/sdcard/dump/dump%d.dat", read.StartBlockNum)
log.Printf("dumping block %d to %s", read.StartBlockNum, fn)
f, err := os.Create(fn)
if err != nil {
log.Fatalln(err)
}
defer f.Close()
if i, err := ioctl(device, GLOB_SBD_IOCTL_RD_MAIN, unsafe.Pointer(&read)); i == -1 || err != nil {
log.Fatalf("RD_MAIN ioctl failed: %d, %s", i, err)
} else {
// log.Printf("%d %+v", i, read)
f.Write(data)
}
}()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment