diff --git a/cli/cli.go b/cli/cli.go deleted file mode 100644 index 06ab7d0..0000000 --- a/cli/cli.go +++ /dev/null @@ -1 +0,0 @@ -package main diff --git a/cli/hid_cgo.go b/cli/hid_cgo.go index 67e3c9a..5ac5e2b 100644 --- a/cli/hid_cgo.go +++ b/cli/hid_cgo.go @@ -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) { diff --git a/cli/listhid.go b/cli/listhid.go deleted file mode 100644 index 06ab7d0..0000000 --- a/cli/listhid.go +++ /dev/null @@ -1 +0,0 @@ -package main diff --git a/cli/main.go b/cli/main.go index 3b252d1..2912a07 100644 --- a/cli/main.go +++ b/cli/main.go @@ -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() diff --git a/cli/memio.go b/cli/memio.go index 41d88f6..0bef3a8 100644 --- a/cli/memio.go +++ b/cli/memio.go @@ -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[:]) diff --git a/cli/raw.go b/cli/raw.go new file mode 100644 index 0000000..6bdbaee --- /dev/null +++ b/cli/raw.go @@ -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 +} diff --git a/mshal/hal.go b/mshal/hal.go index 8bbfa8b..e28c8de 100644 --- a/mshal/hal.go +++ b/mshal/hal.go @@ -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" diff --git a/mshal/hal_flash.go b/mshal/hal_flash.go new file mode 100644 index 0000000..9cc4da0 --- /dev/null +++ b/mshal/hal_flash.go @@ -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 +} diff --git a/mshal/hal_patch_call.go b/mshal/hal_patch_call.go index a42df08..86d6d88 100644 --- a/mshal/hal_patch_call.go +++ b/mshal/hal_patch_call.go @@ -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 diff --git a/mshal/hal_patch_eeprom.go b/mshal/hal_patch_eeprom.go index 36d24a0..00dba45 100644 --- a/mshal/hal_patch_eeprom.go +++ b/mshal/hal_patch_eeprom.go @@ -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 diff --git a/mshal/hal_patch_gpio.go b/mshal/hal_patch_gpio.go index 387d9b1..e7ee869 100644 --- a/mshal/hal_patch_gpio.go +++ b/mshal/hal_patch_gpio.go @@ -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< 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 +} diff --git a/mshal/hal_patch_install.go b/mshal/hal_patch_install.go index 1c1b705..6c8416a 100644 --- a/mshal/hal_patch_install.go +++ b/mshal/hal_patch_install.go @@ -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) diff --git a/mshal/hal_patch_movc.go b/mshal/hal_patch_movc.go index 46b76f8..2fa1d0e 100644 --- a/mshal/hal_patch_movc.go +++ b/mshal/hal_patch_movc.go @@ -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 } diff --git a/mshal/hal_patch_tvdsafe.go b/mshal/hal_patch_tvdsafe.go index 49e0ed8..9f8a174 100644 --- a/mshal/hal_patch_tvdsafe.go +++ b/mshal/hal_patch_tvdsafe.go @@ -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 diff --git a/mshal/hal_region.go b/mshal/hal_region.go index df455b8..b274555 100644 --- a/mshal/hal_region.go +++ b/mshal/hal_region.go @@ -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 } diff --git a/mshal/hal_rom.go b/mshal/hal_rom.go index 8fadf91..bf0c87d 100644 --- a/mshal/hal_rom.go +++ b/mshal/hal_rom.go @@ -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, }) } diff --git a/mshal/region.go b/mshal/region.go index 409cc59..c65388d 100644 --- a/mshal/region.go +++ b/mshal/region.go @@ -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 {