Add initial MS2130 support

This commit is contained in:
Bertold Van den Bergh 2022-11-20 18:19:28 +01:00
parent 9f068704fb
commit 682b98fbbf
17 changed files with 416 additions and 37 deletions

View file

@ -1 +0,0 @@
package main

View file

@ -1,3 +1,4 @@
//go:build !puregohid
// +build !puregohid
package main
@ -13,16 +14,21 @@ import (
)
func SearchDevice(foundHandler func(info *hid.DeviceInfo) error) error {
return hid.Enumerate(uint16(CLI.VID), uint16(CLI.PID), func(info *hid.DeviceInfo) error {
if CLI.Serial != "" && info.SerialNbr != CLI.Serial {
return nil
}
if CLI.RawPath != "" && info.Path != CLI.RawPath {
return nil
}
for _, vid := range []uint16{uint16(CLI.VID), uint16(CLI.VID2)} {
if err := hid.Enumerate(vid, uint16(CLI.PID), func(info *hid.DeviceInfo) error {
if CLI.Serial != "" && info.SerialNbr != CLI.Serial {
return nil
}
if CLI.RawPath != "" && info.Path != CLI.RawPath {
return nil
}
return foundHandler(info)
})
return foundHandler(info)
}); err != nil {
return err
}
}
return nil
}
func OpenDevice() (gohid.HIDDevice, error) {

View file

@ -1 +0,0 @@
package main

View file

@ -16,6 +16,7 @@ type Context struct {
var CLI struct {
VID int `optional type:"hex" help:"The USB Vendor ID." default:534d`
VID2 int `optional type:"hex" help:"The second USB Vendor ID." default:345f`
PID int `optional type:"hex" help:"The USB Product ID."`
Serial string `optional help:"The USB Serial."`
RawPath string `optional help:"The USB Device Path."`
@ -32,6 +33,8 @@ var CLI struct {
Write MEMIOWriteCmd `cmd help:"Write value to memory."`
WriteFile MEMIOWriteFileCmd `cmd help:"Write file to memory."`
RawCmd RawCmd `cmd help:"Send raw command to device."`
DumpROM DumpROM `cmd help:"Dump ROM (code) to file by uploading custom code."`
I2CScan I2CScan `cmd name:"i2c-scan" help:"Scan I2C bus and show discovered devices."`
@ -56,9 +59,6 @@ func main() {
return
}
// hid.Init()
// defer hid.Exit()
c := &Context{}
if ctx.Command() != "list-dev" {
dev, err := OpenDevice()

View file

@ -2,6 +2,7 @@ package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io/ioutil"
@ -126,6 +127,20 @@ func (w MEMIOWriteCmd) Run(c *Context) error {
return errors.New("Invalid memory region")
}
if region.GetAlignment() == 4 {
var value [4]byte
binary.BigEndian.PutUint32(value[:], uint32(w.Value))
_, err := region.Access(true, w.Zone.Addr, value[:])
return err
}
if region.GetAlignment() == 2 {
var value [2]byte
binary.BigEndian.PutUint16(value[:], uint16(w.Value))
_, err := region.Access(true, w.Zone.Addr, value[:])
return err
}
var value [1]byte
value[0] = byte(w.Value)
_, err := region.Access(true, w.Zone.Addr, value[:])

25
cli/raw.go Normal file
View file

@ -0,0 +1,25 @@
package main
import (
"encoding/hex"
"fmt"
)
type RawCmd struct {
Data string `arg name:"value" help:"Value to write."`
}
func (w RawCmd) Run(c *Context) error {
buf, err := hex.DecodeString(w.Data)
if err != nil {
return err
}
out, err := c.hal.ROMExchangeReport(buf)
if err != nil {
return err
}
fmt.Println("Raw command results:", hex.EncodeToString(buf), "->", hex.EncodeToString(out))
return nil
}

View file

@ -17,7 +17,8 @@ type HAL struct {
patchInstalled bool
config HALConfig
config HALConfig
ms2130spiEnabled int
}
type LogFunc func(level int, format string, param ...interface{})
@ -37,6 +38,8 @@ func New(dev gohid.HIDDevice, config HALConfig) (*HAL, error) {
h := &HAL{
dev: dev,
config: config,
ms2130spiEnabled: -1,
}
xdata := h.MemoryRegionGet(MemoryRegionRAM)
@ -51,10 +54,17 @@ func New(dev gohid.HIDDevice, config HALConfig) (*HAL, error) {
h.deviceType = 2106
chipType, err = ReadByte(xdata, 0x35)
if err != nil {
return nil, err
}
h.deviceTypeExtra = int(chipType)
case 0xa7:
h.deviceType = 2109
case 0x00: /* TODO: Find a better ID register, as this will likely match many devices */
h.deviceType = 2130
config.PatchTryInstall = false
default:
return nil, ErrorUnknownDevice
}
@ -85,7 +95,11 @@ func New(dev gohid.HIDDevice, config HALConfig) (*HAL, error) {
if h.eepromSize == 0 && config.PatchProbeEEPROM {
h.eepromSize, err = h.patchEepromDetectSize()
if err != nil {
h.eepromSize = 2048
if h.deviceType != 2130 {
h.eepromSize = 2048
} else {
h.eepromSize = 64 * 1024
}
h.config.LogFunc(1, "Failed to detect EEPROM: %v", err)
}
}
@ -102,15 +116,18 @@ func New(dev gohid.HIDDevice, config HALConfig) (*HAL, error) {
type MemoryRegionNameType string
const (
MemoryRegionCODE MemoryRegionNameType = "CODE"
MemoryRegionRAM MemoryRegionNameType = "RAM"
MemoryRegionIRAM MemoryRegionNameType = "IRAM"
MemoryRegionEEPROM MemoryRegionNameType = "EEPROM"
MemoryRegionUserConfig MemoryRegionNameType = "USERCONFIG"
MemoryRegionUserRAM MemoryRegionNameType = "USERRAM"
MemoryRegionCODE MemoryRegionNameType = "CODE"
MemoryRegionRAM MemoryRegionNameType = "RAM"
MemoryRegionIRAM MemoryRegionNameType = "IRAM"
MemoryRegionSFR MemoryRegionNameType = "SFR"
MemoryRegionEEPROM MemoryRegionNameType = "EEPROM"
MemoryRegionUserConfig MemoryRegionNameType = "USERCONFIG"
MemoryRegionUserRAM MemoryRegionNameType = "USERRAM"
MemoryRegionRegisters2106TVD MemoryRegionNameType = "TVDREGS"
MemoryRegionB7_0 MemoryRegionNameType = "B7_0"
MemoryRegionB7_1 MemoryRegionNameType = "B7_1"
MemoryRegionB9 MemoryRegionNameType = "B9"
MemoryRegionFLASH MemoryRegionNameType = "FLASH"
)
type HookNameType string
@ -121,6 +138,8 @@ func (h *HAL) GetDeviceType() string {
return "MS2106s"
}
return "MS2106"
} else if h.deviceType == 2130 {
return "MS2130"
}
return "MS2109"

154
mshal/hal_flash.go Normal file
View file

@ -0,0 +1,154 @@
package mshal
import (
"encoding/binary"
)
func (h *HAL) ms2130enableSPI(enable bool) error {
value := byte(0x00)
if enable {
if h.ms2130spiEnabled == 1 {
return nil
}
/* Configure GPIO */
if _, err := h.MemoryRegionGet(MemoryRegionSFR).Access(true, 0xb0-0x80, []byte{0xe1}); err != nil {
return err
}
value = byte(0x10)
} else {
if h.ms2130spiEnabled == 0 {
return nil
}
}
/* Configure pin mux */
_, err := h.MemoryRegionGet(MemoryRegionRAM).Access(true, 0xf01f, []byte{value})
if enable {
h.ms2130spiEnabled = 1
} else {
h.ms2130spiEnabled = 0
}
return err
}
type romFlashMemoryRegion struct {
hal *HAL
flashReadBufferValid bool
flashReadBufferPage uint16
}
func (h *HAL) memoryRegionFlash() MemoryRegion {
return regionWrapCompleteIO(&romFlashMemoryRegion{
hal: h,
})
}
func (r romFlashMemoryRegion) GetLength() int {
return 0x10000
}
func (r *romFlashMemoryRegion) Access(write bool, addr int, buf []byte) (int, error) {
if err := r.hal.ms2130enableSPI(true); err != nil {
return 0, err
}
if write {
r.flashReadBufferValid = false
if addr == 0 {
/* Erase the flash first */
var out [8]byte
out[0] = 0xfe
if _, err := r.hal.ROMExchangeReport(out[:]); err != nil {
return 0, err
}
}
/* Setup flash write: f801aaaaaabbbb00 (aaaaaa=address, bbbb=blocksize) *
* Write to the buffer: f800cccccccccc (cccccccccccc=data) */
if len(buf) > 256 {
buf = buf[:256]
}
var out [8]byte
out[0] = 0xf8
out[1] = 0x01
out[2] = byte(addr >> 16)
out[3] = byte(addr >> 8)
out[4] = byte(addr >> 0)
binary.BigEndian.PutUint16(out[5:], uint16(len(buf)))
if _, err := r.hal.ROMExchangeReport(out[:]); err != nil {
return 0, err
}
written := 0
for len(buf) > 0 {
out[0] = 0xf8
out[1] = 0x00
n := copy(out[2:], buf)
if _, err := r.hal.ROMExchangeReport(out[:]); err != nil {
return written, err
}
written += n
buf = buf[n:]
}
return written, nil
}
flashPage := uint16(addr >> 8)
flashOffset := uint8(addr & 0xff)
/* Read from flash to buffer: f701aaaaaabbbb00 (aaaaaa=addr, bbbb=len to read)
* Read from buffer to hostt: f700000000aaaa00 (aaaa=offset) */
if !r.flashReadBufferValid || r.flashReadBufferPage != flashPage {
var out [8]byte
out[0] = 0xf7
out[1] = 0x01
binary.BigEndian.PutUint16(out[2:], flashPage)
binary.BigEndian.PutUint16(out[5:], 256)
if _, err := r.hal.ROMExchangeReport(out[:]); err != nil {
return 0, err
}
r.flashReadBufferValid = true
r.flashReadBufferPage = flashPage
}
var out [8]byte
out[0] = 0xf7
binary.BigEndian.PutUint16(out[5:], uint16(flashOffset))
in, err := r.hal.ROMExchangeReport(out[:])
if err != nil {
return 0, err
}
maxLen := 0x100 - int(flashOffset)
if len(buf) > maxLen {
buf = buf[:maxLen]
}
return copy(buf, in), nil
}
func (r romFlashMemoryRegion) GetParent() (MemoryRegion, int) {
return nil, 0
}
func (r romFlashMemoryRegion) GetName() MemoryRegionNameType {
return MemoryRegionFLASH
}
func (r romFlashMemoryRegion) GetAlignment() int {
return 1
}

View file

@ -65,7 +65,7 @@ func (h *HAL) PatchExecFunc(inIRQ bool, addr int, req PatchExecFuncRequest) (Pat
}
if req.DPTR != 0 && (req.R4 != 0 || req.R3 != 0) {
return response, errors.New("Can't set both DPTR and R3/R4")
return response, errors.New("can't set both DPTR and R3/R4")
}
var out [9]byte

View file

@ -124,6 +124,10 @@ func (h halPatchEEPROMMemoryRegion) write(addr int, buf []byte) (int, error) {
return len(buf), nil
}
func (h halPatchEEPROMMemoryRegion) GetAlignment() int {
return 1
}
func (h halPatchEEPROMMemoryRegion) Access(write bool, addr int, buf []byte) (int, error) {
if len(buf) == 0 {
return 0, nil

View file

@ -2,6 +2,9 @@ package mshal
func (h *HAL) GPIOUpdate(stateSet byte, stateClear byte, outputSet byte, outputClear byte) (byte, byte, error) {
if !h.patchInstalled {
if sfr := h.MemoryRegionGet(MemoryRegionSFR); sfr != nil {
return h.gpioUpdateSFR(sfr, stateSet, stateClear, outputSet, outputClear)
}
return 0, 0, ErrorMissingFunction
}
@ -36,3 +39,33 @@ func (h *HAL) GPIORead(index int) (bool, error) {
p2, _, err := h.GPIOUpdate(0, 0, 0, 1<<index)
return p2&(1<<index) > 0, err
}
func (h *HAL) gpioUpdateSFR(sfr MemoryRegion, stateSet byte, stateClear byte, outputSet byte, outputClear byte) (byte, byte, error) {
if err := h.ms2130enableSPI(false); err != nil {
return 0, 0, err
}
/* P3 = 0xB0, P2 = 0xA0 */
var P3, P2 [1]byte
if _, err := sfr.Access(false, 0xB0-0x80, P3[:]); err != nil {
return 0, 0, err
}
if _, err := sfr.Access(false, 0xA0-0x80, P2[:]); err != nil {
return 0, 0, err
}
P3[0] |= outputClear
P3[0] &= ^outputSet
P2[0] |= stateSet
P2[0] &= ^stateClear
if _, err := sfr.Access(true, 0xB0-0x80, P3[:]); err != nil {
return 0, 0, err
}
if _, err := sfr.Access(true, 0xA0-0x80, P2[:]); err != nil {
return 0, 0, err
}
return P2[0], P3[0], nil
}

View file

@ -5,6 +5,7 @@ import (
_ "embed"
"encoding/binary"
"encoding/hex"
"errors"
"hash/crc32"
)
@ -309,9 +310,13 @@ func (h *HAL) patchInitAlloc(userConfig MemoryRegion) (bool, error) {
}
func (h *HAL) patchInstall() (bool, error) {
installBlobs := installBlobs2106
var installBlobs []CodeBlob
if h.deviceType == 2109 {
installBlobs = installBlobs2109
} else if h.deviceType == 2106 {
installBlobs = installBlobs2106
} else {
return false, errors.New("this device does not support runtime patching")
}
h.patchCallAddrsExternalStart = len(installBlobs)

View file

@ -20,6 +20,10 @@ func (h halPatchCodeMemoryRegion) GetLength() int {
return 0x10000
}
func (h halPatchCodeMemoryRegion) GetAlignment() int {
return 1
}
func (h halPatchCodeMemoryRegion) GetParent() (MemoryRegion, int) {
return nil, 0
}

View file

@ -44,6 +44,10 @@ func (h halPatchTVDMemoryRegion) write(addr int, buf []byte) (int, error) {
return 1, nil
}
func (h halPatchTVDMemoryRegion) GetAlignment() int {
return 1
}
func (h halPatchTVDMemoryRegion) Access(write bool, addr int, buf []byte) (int, error) {
if len(buf) == 0 {
return 0, nil

View file

@ -4,16 +4,58 @@ import "strings"
func (h *HAL) memoryRegionXDATAIRAM(base int, len int) MemoryRegion {
read, write := romCommandMakeReadWrite(0xb5, true)
return h.romMemoryRegionMake(MemoryRegionRAM, base, len, &read, &write)
if h.deviceType == 2130 {
read.maxPayload = 4
}
return h.romMemoryRegionMake(MemoryRegionRAM, base, len, 1, &read, &write)
}
func (h *HAL) memoryRegionSFR(base int, len int) MemoryRegion {
read, write := romCommandMakeReadWrite(0xc5, false)
return h.romMemoryRegionMake(MemoryRegionSFR, base, len, 1, &read, &write)
}
func (h *HAL) memoryRegionB7(base int, len int, index byte) MemoryRegion {
indexFunc := func(h *HAL, out []byte) error {
out[2] = index
return nil
}
read, write := romCommandMakeReadWrite(0xb7, true)
read.offset = 3
read.maxPayload = 4
read.cbApplyParam = indexFunc
write.offset = 3
write.maxPayload = 4
write.cbApplyParam = indexFunc
t := MemoryRegionB7_0
if index > 0 {
t = MemoryRegionB7_1
}
return h.romMemoryRegionMake(t, base, len, 4, &read, &write)
}
func (h *HAL) memoryRegionB9(base int, len int) MemoryRegion {
// Note: If the first byte of the request is not 0, the previous address is reused
read, write := romCommandMakeReadWrite(0xb9, false)
read.offset = 3
read.addrShift = 1
read.maxPayload = 2
write.offset = 3
write.addrShift = 1
write.maxPayload = 2
return h.romMemoryRegionMake(MemoryRegionB9, base, len, 2, &read, &write)
}
func (h *HAL) memoryRegionEEPROM() MemoryRegion {
read, write := romCommandMakeReadWrite(0xe5, true)
if h.deviceType == 2109 {
if h.deviceType != 2106 {
read.maxPayload = 5
read.cbApplyParam = romEepromV2HandleTwoByteAddress
}
region := h.romMemoryRegionMake(MemoryRegionEEPROM, 0, h.eepromSize, &read, &write)
region := h.romMemoryRegionMake(MemoryRegionEEPROM, 0, h.eepromSize, 1, &read, &write)
/* The EEPROM takes time to write, so try to read again.
MS2109 has internal delay (quite long) */
@ -26,7 +68,7 @@ func (h *HAL) memoryRegionEEPROM() MemoryRegion {
func (h *HAL) memoryRegionRegisters2106TVD() MemoryRegion {
read, write := romCommandMakeReadWrite(0xa5, false)
return h.romMemoryRegionMake(MemoryRegionRegisters2106TVD, 0, 256, &read, &write)
return h.romMemoryRegionMake(MemoryRegionRegisters2106TVD, 0, 256, 1, &read, &write)
}
func (h *HAL) MemoryRegionList() []MemoryRegionNameType {
@ -34,10 +76,21 @@ func (h *HAL) MemoryRegionList() []MemoryRegionNameType {
MemoryRegionRAM,
MemoryRegionIRAM,
MemoryRegionEEPROM,
MemoryRegionUserRAM,
MemoryRegionUserConfig,
}
if h.deviceType == 2106 || h.deviceType == 2109 {
list = append(list, MemoryRegionUserRAM)
}
if h.deviceType == 2130 {
list = append(list, MemoryRegionSFR)
list = append(list, MemoryRegionB7_0)
list = append(list, MemoryRegionB7_1)
list = append(list, MemoryRegionB9)
list = append(list, MemoryRegionFLASH)
}
if h.patchInstalled {
list = append(list, MemoryRegionCODE)
}
@ -102,5 +155,27 @@ func (h *HAL) MemoryRegionGet(name MemoryRegionNameType) MemoryRegion {
}
}
if h.deviceType == 2130 {
switch t {
case MemoryRegionSFR:
return h.memoryRegionSFR(0x80, 0x80)
case MemoryRegionB7_0:
return h.memoryRegionB7(0, 65536, 0)
case MemoryRegionB7_1:
return h.memoryRegionB7(0, 65536, 1)
case MemoryRegionB9:
return h.memoryRegionB9(0, 512)
case MemoryRegionUserConfig:
return regionWrapPartial(MemoryRegionUserConfig, h.MemoryRegionGet(MemoryRegionRAM), 0x1FD0, 0x30)
case MemoryRegionFLASH:
return h.memoryRegionFlash()
}
}
return nil
}

View file

@ -3,6 +3,7 @@ package mshal
import (
"bytes"
"encoding/hex"
"errors"
"time"
)
@ -15,6 +16,8 @@ type romCommand struct {
is16bit bool
isWrite bool
maxPayload int
offset int
addrShift int
cbApplyParam cbApplyParamType
cbPostExchange cbPostExchangeType
@ -58,13 +61,25 @@ func (h *HAL) romExchangeReport(out [9]byte, checkLen int) ([9]byte, error) {
return in, nil
}
func (h *HAL) romProtocolMakeHeader(cmd byte, is16bit bool, addr int) ([9]byte, int) {
func (h *HAL) ROMExchangeReport(out []byte) ([]byte, error) {
var outb [9]byte
if len(out) > 8 {
return nil, errors.New("buffer longer than 8 bytes")
}
copy(outb[1:], out)
inb, err := h.romExchangeReport(outb, 0)
return inb[1:], err
}
func (h *HAL) romProtocolMakeHeader(cmd byte, is16bit bool, addr int, index int) ([9]byte, int) {
var out [9]byte
out[0] = 0
out[1] = byte(cmd)
index := 2
if index == 0 {
index = 2
}
if is16bit {
out[index] = byte(addr >> 8)
index++
@ -100,7 +115,9 @@ func (h *HAL) romProtocolExec(cmd romCommand, addr int, buf []byte) (int, error)
maxPayload = 1
}
out, index := h.romProtocolMakeHeader(cmd.id, cmd.is16bit, addr)
addr >>= cmd.addrShift
out, index := h.romProtocolMakeHeader(cmd.id, cmd.is16bit, addr, cmd.offset)
txrLen := 0
if cmd.isWrite {
@ -138,6 +155,7 @@ type halROMMemoryRegion struct {
baseAddr int
length int
name MemoryRegionNameType
alignment int
}
func (h halROMMemoryRegion) GetName() MemoryRegionNameType {
@ -152,6 +170,10 @@ func (h halROMMemoryRegion) GetParent() (MemoryRegion, int) {
return nil, 0
}
func (h halROMMemoryRegion) GetAlignment() int {
return h.alignment
}
func (h halROMMemoryRegion) Access(write bool, addr int, buf []byte) (int, error) {
if addr > h.length {
return 0, nil
@ -167,13 +189,13 @@ func (h halROMMemoryRegion) Access(write bool, addr int, buf []byte) (int, error
return h.hal.romProtocolExec(*h.writeCommand, h.baseAddr+addr, buf)
}
if h.writeCommand == nil {
return 0, ErrorWriteNotAllowed
if h.readCommand == nil {
return 0, ErrorReadNotAllowed
}
return h.hal.romProtocolExec(*h.readCommand, h.baseAddr+addr, buf)
}
func (h *HAL) romMemoryRegionMake(name MemoryRegionNameType, baseAddr int, length int, read *romCommand, write *romCommand) MemoryRegion {
func (h *HAL) romMemoryRegionMake(name MemoryRegionNameType, baseAddr int, length int, alignment int, read *romCommand, write *romCommand) MemoryRegion {
return regionWrapCompleteIO(halROMMemoryRegion{
hal: h,
baseAddr: baseAddr,
@ -181,6 +203,7 @@ func (h *HAL) romMemoryRegionMake(name MemoryRegionNameType, baseAddr int, lengt
readCommand: read,
writeCommand: write,
name: name,
alignment: alignment,
})
}

View file

@ -1,10 +1,13 @@
package mshal
import "errors"
type MemoryRegion interface {
GetLength() int
Access(write bool, addr int, buf []byte) (int, error)
GetParent() (MemoryRegion, int)
GetName() MemoryRegionNameType
GetAlignment() int
}
type regionCompleteIO struct {
@ -18,6 +21,13 @@ func regionWrapCompleteIO(parent MemoryRegion) MemoryRegion {
}
func (m regionCompleteIO) Access(write bool, addr int, buf []byte) (int, error) {
align := m.GetAlignment()
if addr&(align-1) != 0 {
return 0, errors.New("address alignment has been violated")
} else if write && len(buf)%align != 0 {
return 0, errors.New("data alignment has been violated")
}
total := 0
for len(buf) > 0 {
n, err := m.MemoryRegion.Access(write, addr+total, buf)
@ -71,6 +81,10 @@ func (h regionPartial) GetParent() (MemoryRegion, int) {
return h.parent, h.offset
}
func (h regionPartial) GetAlignment() int {
return h.parent.GetAlignment()
}
func (h regionPartial) Access(write bool, addr int, buf []byte) (int, error) {
if len(buf)+addr > h.length {
if addr > h.length {