Compare commits

..

11 Commits

Author SHA1 Message Date
Nia Waldvogel 80c89809a9 machine: fix usb truncation?
Remove the sendUSBPacket maxLen param because this greatly confused the compiler.
It also fixes a bug where the length provided to the hardware may not match the length of the packet.
sendUSBPacket now panics if the sent packet is too big.

I also fixed some of the string descriptor logic where we could create a packet without fully populating it.

RP2* systems might require some more work since they are implemented very differently?
I don't have any of those to test with yet, so maybe someone can deal with them in a seperate PR?
2025-12-30 15:51:27 -05:00
Nia Waldvogel 266d70816f compiler/runtime: add element layout to sliceAppend
Attach the memory layout of the element type to newly created slices via append when using the precise collector.
2025-12-26 21:27:24 -05:00
Damian Gryski 27cedf09e8 testdata: more corpus repos 2025-12-22 13:15:06 +00:00
deadprogram db9f1182f5 Release 0.40.1
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-12-18 21:59:18 +00:00
MakKi (makki_d) f7fd5cf2d8 runtime: use rand_hwrng hardwareRand for RP2040/RP2350 (#5135)
* runtime: use rand_hwrng hardwareRand for RP2040/RP2350

* add a comment

* insert 'implementations'
2025-12-18 20:52:12 +01:00
deadprogram 8d9c9a16e3 picolibc: use updated location for git repo
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-12-18 18:20:22 +00:00
deadprogram 82deccac40 runtime: call initRand() before initHeap() during initialization.
The reason is that allocating without a heap is usually more visible
than using an uninitialized random generator which is subtle and may
lead to security vulnerabilities.

Based on suggestion from @eliasnaur

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-12-18 16:42:46 +00:00
deadprogram 0e540dc3da runtime: add calls to initRand() during run() for all schedulers.
Intended to ensure that the random number seed used is always initialized on startup.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-12-18 16:42:46 +00:00
MakKi (makki_d) 897f2bc5fd runtime: avoid fixed math/rand sequence on RP2040/RP2350 (#5124)
* runtime: avoid fixed math/rand sequence on RP2040/RP2350

* fix typo
2025-12-17 20:05:43 +01:00
Ayke van Laethem 750b0e5c18 nrf: fix flash writes when SoftDevice is enabled
The data to write is specififed in words, not in bytes.

This fix is needed for correctness. Without it, a
`machine.Flash.WriteAt` call can result in **data loss** since it will
overwrite more data than it should.
2025-12-17 14:58:40 +00:00
deadprogram a65ac105cc build: remove post-build triggers for associated repos like drivers.
Now that the drivers repo and friends are intended to target the most
recent release version of TinyGo instead of the development version,
this trigger does not serve any puppose to trigger a build that will have
already been tested.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-12-17 13:34:19 +00:00
25 changed files with 180 additions and 167 deletions
-42
View File
@@ -66,45 +66,3 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Trigger Drivers repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/drivers/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger Bluetooth repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/bluetooth/actions/workflows/linux.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyFS repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinyfs/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyFont repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinyfont/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyDraw repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinydraw/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyTerm repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinyterm/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
+1 -1
View File
@@ -16,7 +16,7 @@
url = https://github.com/WebAssembly/wasi-libc
[submodule "lib/picolibc"]
path = lib/picolibc
url = https://github.com/keith-packard/picolibc.git
url = https://github.com/picolibc/picolibc.git
[submodule "lib/stm32-svd"]
path = lib/stm32-svd
url = https://github.com/tinygo-org/stm32-svd
+12
View File
@@ -1,3 +1,15 @@
0.40.1
---
* **machine**
- nrf: fix flash writes when SoftDevice is enabled
* **runtime**
- runtime: avoid fixed math/rand sequence on RP2040/RP2350 (#5124)
- runtime: add calls to initRand() during run() for all schedulers
- runtime: call initRand() before initHeap() during initialization
- runtime: use rand_hwrng hardwareRand for RP2040/RP2350 (#5135)
* **libs**
- picolibc: use updated location for git repo
0.40.0
---
* **general**
+1 -1
View File
@@ -44,7 +44,7 @@ func TestBinarySize(t *testing.T) {
// microcontrollers
{"hifive1b", "examples/echo", 3668, 280, 0, 2244},
{"microbit", "examples/serial", 2694, 342, 8, 2248},
{"wioterminal", "examples/pininterrupt", 7187, 1489, 116, 6888},
{"wioterminal", "examples/pininterrupt", 6833, 1491, 120, 6888},
// TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the
+2 -1
View File
@@ -1599,7 +1599,8 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen")
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize}, "append.new")
elemLayout := b.createObjectLayout(elemType, pos)
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize, elemLayout}, "append.new")
newPtr := b.CreateExtractValue(result, 0, "append.newPtr")
newLen := b.CreateExtractValue(result, 1, "append.newLen")
newCap := b.CreateExtractValue(result, 2, "append.newCap")
+3 -3
View File
@@ -55,7 +55,7 @@ entry:
store i32 2, ptr %0, align 4
%1 = getelementptr inbounds nuw i8, ptr %varargs, i32 8
store i32 3, ptr %1, align 4
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr undef) #3
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
@@ -66,13 +66,13 @@ entry:
ret { ptr, i32, i32 } %4
}
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #1
declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr, ptr) #1
; Function Attrs: nounwind
define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #2 {
entry:
%stackalloc = alloca i8, align 1
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr undef) #3
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
%append.newLen = extractvalue { ptr, i32, i32 } %append.new, 1
%append.newCap = extractvalue { ptr, i32, i32 } %append.new, 2
+1 -1
View File
@@ -10,7 +10,7 @@ import (
// Version of TinyGo.
// Update this value before release of new version of software.
const version = "0.40.0"
const version = "0.40.1"
// Return TinyGo version, either in the form 0.30.0 or as a development version
// (like 0.30.0-dev-abcd012).
+10 -5
View File
@@ -1745,7 +1745,7 @@ func memzero(ptr unsafe.Pointer, size uintptr)
func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
//go:linkname sliceAppend runtime.sliceAppend
func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen uintptr, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr)
func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen uintptr, elemSize uintptr, layout unsafe.Pointer) (unsafe.Pointer, uintptr, uintptr)
//go:linkname sliceCopy runtime.sliceCopy
func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen uintptr, elemSize uintptr) int
@@ -1810,7 +1810,7 @@ func buflen(v Value) (unsafe.Pointer, uintptr) {
}
//go:linkname sliceGrow runtime.sliceGrow
func sliceGrow(buf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr)
func sliceGrow(buf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr, layout unsafe.Pointer) (unsafe.Pointer, uintptr, uintptr)
// extend slice to hold n new elements
func extendSlice(v Value, n int) sliceHeader {
@@ -1823,7 +1823,10 @@ func extendSlice(v Value, n int) sliceHeader {
old = *(*sliceHeader)(v.value)
}
nbuf, nlen, ncap := sliceGrow(old.data, old.len, old.cap, old.len+uintptr(n), v.typecode.elem().Size())
elem := v.typecode.elem()
elemSize := elem.Size()
elemLayout := elem.gcLayout()
nbuf, nlen, ncap := sliceGrow(old.data, old.len, old.cap, old.len+uintptr(n), elemSize, elemLayout)
return sliceHeader{
data: nbuf,
@@ -1862,8 +1865,10 @@ func AppendSlice(s, t Value) Value {
}
sSlice := (*sliceHeader)(s.value)
tSlice := (*sliceHeader)(t.value)
elemSize := s.typecode.elem().Size()
ptr, len, cap := sliceAppend(sSlice.data, tSlice.data, sSlice.len, sSlice.cap, tSlice.len, elemSize)
elem := s.typecode.elem()
elemSize := elem.Size()
elemLayout := elem.gcLayout()
ptr, len, cap := sliceAppend(sSlice.data, tSlice.data, sSlice.len, sSlice.cap, tSlice.len, elemSize, elemLayout)
result := &sliceHeader{
data: ptr,
len: len,
+17 -16
View File
@@ -337,7 +337,7 @@ func handleUSBSetAddress(setup usb.Setup) bool {
// SendUSBInPacket sends a packet for USB (interrupt in / bulk in).
func SendUSBInPacket(ep uint32, data []byte) bool {
sendUSBPacket(ep, data, 0)
sendUSBPacket(ep, data)
// clear transfer complete flag
setEPINTFLAG(ep, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
@@ -351,27 +351,28 @@ func SendUSBInPacket(ep uint32, data []byte) bool {
// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998
//
//go:noinline
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
l := uint16(len(data))
if 0 < maxsize && maxsize < l {
l = maxsize
func sendUSBPacket(ep uint32, data []byte) {
// Select the corresponding buffer.
buffer := udd_ep_control_cache_buffer[:]
if ep != 0 {
buffer = udd_ep_in_cache_buffer[ep][:]
}
// Set endpoint address for sending data
if ep == 0 {
copy(udd_ep_control_cache_buffer[:], data[:l])
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_control_cache_buffer))))
} else {
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
}
// Copy the packet to the buffer.
copy(buffer[:len(data)], data)
// Select the corresponding endpoint descriptor.
endpoint := &usbEndpointDescriptors[ep].DeviceDescBank[1]
// Set the endpoint address.
endpoint.ADDR.Set(uint32(uintptr(unsafe.Pointer(unsafe.SliceData(buffer)))))
// clear multi-packet size which is total bytes already sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
endpoint.PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
// set byte count, which is total number of bytes to be sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
endpoint.PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
endpoint.PCKSIZE.SetBits((uint32(len(data)) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
}
func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
+17 -16
View File
@@ -340,7 +340,7 @@ func handleUSBSetAddress(setup usb.Setup) bool {
// SendUSBInPacket sends a packet for USB (interrupt in / bulk in).
func SendUSBInPacket(ep uint32, data []byte) bool {
sendUSBPacket(ep, data, 0)
sendUSBPacket(ep, data)
// clear transfer complete flag
setEPINTFLAG(ep, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
@@ -354,27 +354,28 @@ func SendUSBInPacket(ep uint32, data []byte) bool {
// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998
//
//go:noinline
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
l := uint16(len(data))
if 0 < maxsize && maxsize < l {
l = maxsize
func sendUSBPacket(ep uint32, data []byte) {
// Select the corresponding buffer.
buffer := udd_ep_control_cache_buffer[:]
if ep != 0 {
buffer = udd_ep_in_cache_buffer[ep][:]
}
// Set endpoint address for sending data
if ep == 0 {
copy(udd_ep_control_cache_buffer[:], data[:l])
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_control_cache_buffer))))
} else {
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
}
// Copy the packet to the buffer.
copy(buffer[:len(data)], data)
// Select the corresponding endpoint descriptor.
endpoint := &usbEndpointDescriptors[ep].DeviceDescBank[1]
// Set the endpoint address.
endpoint.ADDR.Set(uint32(uintptr(unsafe.Pointer(unsafe.SliceData(buffer)))))
// clear multi-packet size which is total bytes already sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
endpoint.PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
// set byte count, which is total number of bytes to be sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
endpoint.PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
endpoint.PCKSIZE.SetBits((uint32(len(data)) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
}
func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
+2 -1
View File
@@ -400,7 +400,8 @@ func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
// SoftDevices I've checked.
// Documentation:
// https://docs.nordicsemi.com/bundle/s140_v6.0.0_api/page/group_n_r_f_s_o_c_f_u_n_c_t_i_o_n_s.html
result := arm.SVCall3(0x20+9, address, &p[0], uint32(len(p)))
numberOfWords := len(padded) / 4 // flash access goes in 32-bit words
result := arm.SVCall3(0x20+9, address, &padded[0], uint32(numberOfWords))
if result != 0 {
// Could not queue flash operation? Not sure when this can
// happen.
+18 -19
View File
@@ -256,7 +256,7 @@ func initEndpoint(ep, config uint32) {
// SendUSBInPacket sends a packet for USBHID (interrupt in / bulk in).
func SendUSBInPacket(ep uint32, data []byte) bool {
sendUSBPacket(ep, data, 0)
sendUSBPacket(ep, data)
// clear transfer complete flag
nrf.USBD.INTENCLR.Set(nrf.USBD_INTENCLR_ENDEPOUT0 << 4)
@@ -267,33 +267,32 @@ func SendUSBInPacket(ep uint32, data []byte) bool {
// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998
//
//go:noinline
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
func sendUSBPacket(ep uint32, data []byte) {
// Select the corresponding buffer.
count := len(data)
if 0 < int(maxsize) && int(maxsize) < count {
count = int(maxsize)
}
var buffer []byte
if ep == 0 {
copy(udd_ep_control_cache_buffer[:], data[:count])
buffer = udd_ep_control_cache_buffer[:]
if count > usb.EndpointPacketSize {
// The packet must be sent in chunks.
sendOnEP0DATADONE.offset = usb.EndpointPacketSize
sendOnEP0DATADONE.ptr = &udd_ep_control_cache_buffer[sendOnEP0DATADONE.offset]
sendOnEP0DATADONE.ptr = &udd_ep_control_cache_buffer[usb.EndpointPacketSize]
sendOnEP0DATADONE.count = count - usb.EndpointPacketSize
count = usb.EndpointPacketSize
}
sendViaEPIn(
ep,
&udd_ep_control_cache_buffer[0],
count,
)
} else {
copy(udd_ep_in_cache_buffer[ep][:], data[:count])
sendViaEPIn(
ep,
&udd_ep_in_cache_buffer[ep][0],
count,
)
buffer = udd_ep_in_cache_buffer[ep][:]
}
// Copy the packet to the buffer.
copy(buffer[:len(data)], data)
// Send the first chunk of the packet.
sendViaEPIn(
ep,
&buffer[0],
count,
)
}
func handleEndpointRx(ep uint32) []byte {
+1 -1
View File
@@ -128,7 +128,7 @@ func handleUSBSetAddress(setup usb.Setup) bool {
const ackTimeout = 570
rp.USBCTRL_REGS.SIE_STATUS.Set(rp.USBCTRL_REGS_SIE_STATUS_ACK_REC)
sendUSBPacket(0, []byte{}, 0)
sendUSBPacket(0, []byte{})
// Wait for transfer to complete with a timeout.
t := timer.timeElapsed()
+1 -1
View File
@@ -131,7 +131,7 @@ func handleUSBSetAddress(setup usb.Setup) bool {
const ackTimeout = 570
rp.USB.SIE_STATUS.Set(rp.USB_SIE_STATUS_ACK_REC)
sendUSBPacket(0, []byte{}, 0)
sendUSBPacket(0, []byte{})
// Wait for transfer to complete with a timeout.
t := timer.timeElapsed()
+3 -7
View File
@@ -72,19 +72,15 @@ func initEndpoint(ep, config uint32) {
// SendUSBInPacket sends a packet for USB (interrupt in / bulk in).
func SendUSBInPacket(ep uint32, data []byte) bool {
sendUSBPacket(ep, data, 0)
sendUSBPacket(ep, data)
return true
}
// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998
//
//go:noinline
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
func sendUSBPacket(ep uint32, data []byte) {
count := len(data)
if 0 < int(maxsize) && int(maxsize) < count {
count = int(maxsize)
}
if ep == 0 {
if count > usb.EndpointPacketSize {
count = usb.EndpointPacketSize
@@ -145,7 +141,7 @@ func setEPDataPID(ep uint32, dataOne bool) {
}
func SendZlp() {
sendUSBPacket(0, []byte{}, 0)
sendUSBPacket(0, []byte{})
}
func sendViaEPIn(ep uint32, data []byte, count int) {
+72 -37
View File
@@ -81,21 +81,6 @@ func usbSerial() string {
return ""
}
// strToUTF16LEDescriptor converts a utf8 string into a string descriptor
// note: the following code only converts ascii characters to UTF16LE. In order
// to do a "proper" conversion, we would need to pull in the 'unicode/utf16'
// package, which at the time this was written added 512 bytes to the compiled
// binary.
func strToUTF16LEDescriptor(in string, out []byte) {
out[0] = byte(len(out))
out[1] = descriptor.TypeString
for i, rune := range in {
out[(i<<1)+2] = byte(rune)
out[(i<<1)+3] = 0
}
return
}
const cdcLineInfoSize = 7
var (
@@ -137,51 +122,53 @@ var (
usbStallHandler [NumberOfUSBEndpoints]func(usb.Setup) bool
)
var usbLangInfo = [4]byte{
// length = 4 bytes
0x04,
// descriptor type = string
0x03,
// language codes
// 0x0409 = English (United States)
0x09, 0x04,
}
// sendDescriptor creates and sends the various USB descriptor types that
// can be requested by the host.
func sendDescriptor(setup usb.Setup) {
switch setup.WValueH {
case descriptor.TypeConfiguration:
sendUSBPacket(0, usbDescriptor.Configuration, setup.WLength)
sendDescriptorData(usbDescriptor.Configuration, setup.WLength)
return
case descriptor.TypeDevice:
usbDescriptor.Configure(usbVendorID(), usbProductID())
sendUSBPacket(0, usbDescriptor.Device, setup.WLength)
sendDescriptorData(usbDescriptor.Device, setup.WLength)
return
case descriptor.TypeString:
switch setup.WValueL {
case 0:
usb_trans_buffer[0] = 0x04
usb_trans_buffer[1] = 0x03
usb_trans_buffer[2] = 0x09
usb_trans_buffer[3] = 0x04
sendUSBPacket(0, usb_trans_buffer[:4], setup.WLength)
sendDescriptorData(usbLangInfo[:], setup.WLength)
case usb.IPRODUCT:
b := usb_trans_buffer[:(len(usbProduct())<<1)+2]
strToUTF16LEDescriptor(usbProduct(), b)
sendUSBPacket(0, b, setup.WLength)
sendDescriptorString(usbProduct(), setup.WLength)
case usb.IMANUFACTURER:
b := usb_trans_buffer[:(len(usbManufacturer())<<1)+2]
strToUTF16LEDescriptor(usbManufacturer(), b)
sendUSBPacket(0, b, setup.WLength)
sendDescriptorString(usbManufacturer(), setup.WLength)
case usb.ISERIAL:
sz := len(usbSerial())
if sz == 0 {
serial := usbSerial()
if len(serial) == 0 {
SendZlp()
} else {
b := usb_trans_buffer[:(sz<<1)+2]
strToUTF16LEDescriptor(usbSerial(), b)
sendUSBPacket(0, b, setup.WLength)
sendDescriptorString(serial, setup.WLength)
}
}
// TODO: why do we do this when WValueL is unknown?
return
case descriptor.TypeHIDReport:
if h, ok := usbDescriptor.HID[setup.WIndex]; ok {
sendUSBPacket(0, h, setup.WLength)
sendDescriptorData(h, setup.WLength)
return
}
case descriptor.TypeDeviceQualifier:
@@ -194,6 +181,39 @@ func sendDescriptor(setup usb.Setup) {
return
}
// sendDescriptorString sends a string descriptor, truncating it to fit maxLen or the buffer size.
// note: the following code only converts ascii characters to UTF16LE. In order
// to do a "proper" conversion, we would need to pull in the 'unicode/utf16'
// package, which at the time this was written added 512 bytes to the compiled
// binary.
// TODO: old comment, re-evaluate
func sendDescriptorString(data string, maxLen uint16) {
if maxLen < 2 {
// Something has gone horribly wrong.
SendZlp()
return
}
// Clamp the length.
maxEncBytes := min(len(usb_trans_buffer), len(udd_ep_control_cache_buffer), int(maxLen))
data = data[:min(len(data), (maxEncBytes-2)/2)]
// Write the header.
buf := usb_trans_buffer[:2*len(data)+2]
hdr, body := buf[:2], buf[2:]
hdr[0] = byte(len(buf))
hdr[1] = descriptor.TypeString
// Convert the string to UTF16.
// NOTE: Using range here would cause the length to disagree when multibyte codepoints are present.
for i := 0; i < len(data); i++ {
body[2*i] = byte(data[i])
body[2*i+1] = 0
}
sendUSBPacket(0, buf)
}
func handleStandardSetup(setup usb.Setup) bool {
switch setup.BRequest {
case usb.GET_STATUS:
@@ -206,7 +226,7 @@ func handleStandardSetup(setup usb.Setup) bool {
}
}
sendUSBPacket(0, usb_trans_buffer[:2], setup.WLength)
sendDescriptorData(usb_trans_buffer[:2], setup.WLength)
return true
case usb.CLEAR_FEATURE:
@@ -251,7 +271,7 @@ func handleStandardSetup(setup usb.Setup) bool {
case usb.GET_CONFIGURATION:
usb_trans_buffer[0] = usbConfiguration
sendUSBPacket(0, usb_trans_buffer[:1], setup.WLength)
sendDescriptorData(usb_trans_buffer[:1], setup.WLength)
return true
case usb.SET_CONFIGURATION:
@@ -271,7 +291,7 @@ func handleStandardSetup(setup usb.Setup) bool {
case usb.GET_INTERFACE:
usb_trans_buffer[0] = usbSetInterface
sendUSBPacket(0, usb_trans_buffer[:1], setup.WLength)
sendDescriptorData(usb_trans_buffer[:1], setup.WLength)
return true
case usb.SET_INTERFACE:
@@ -285,6 +305,21 @@ func handleStandardSetup(setup usb.Setup) bool {
}
}
// sendDescriptorData sends a descriptor, truncating it to fit maxLen or the buffer size.
func sendDescriptorData(data []byte, maxLen uint16) {
data = lenToCap(data)
data = data[:min(len(data), len(udd_ep_control_cache_buffer), int(maxLen))]
sendUSBPacket(0, data)
}
// Set the cap of the slice to the length.
// This is safe, but cannot be proven by the compiler.
//
//go:nobounds
func lenToCap(b []byte) []byte {
return b[:len(b):len(b)]
}
func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
if len(usbDescriptor.Device) == 0 {
usbDescriptor = descriptor.CDC
+6 -1
View File
@@ -1,7 +1,12 @@
//go:build baremetal && (nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey || (tinygo.riscv32 && virt))
//go:build baremetal && (nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey || (tinygo.riscv32 && virt) || rp2040 || rp2350)
// If you update the above build constraint, you'll probably also need to update
// src/crypto/rand/rand_baremetal.go.
//
// The rp2040 and rp2350 implementations are not included in src/crypto/rand/rand_baremetal.go
// due to not being sufficiently random for the Go crypto libs.
// However since the randomness here does not provide those same guarantees,
// they are included in the list for hardwareRand() implementations.
package runtime
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build baremetal && !(nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey || (tinygo.riscv32 && virt))
//go:build baremetal && !(nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey || (tinygo.riscv32 && virt) || rp2040 || rp2350)
package runtime
+1 -1
View File
@@ -34,8 +34,8 @@ func wasmEntryReactor() {
// Initialize the heap.
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
initHeap()
initRand()
initHeap()
if hasScheduler {
// A package initializer might do funky stuff like start a goroutine and
+1 -1
View File
@@ -243,8 +243,8 @@ func sleep(duration int64) {
// run is called by the program entry point to execute the go program.
// With a scheduler, init and the main function are invoked in a goroutine before starting the scheduler.
func run() {
initHeap()
initRand()
initHeap()
go func() {
initAll()
callMain()
+1
View File
@@ -135,6 +135,7 @@ func sleep(duration int64) {
// This function is called on the first core in the system. It will wake up the
// other cores when ready.
func run() {
initRand()
initHeap()
go func() {
+1 -1
View File
@@ -21,8 +21,8 @@ var schedulerExit bool
// run is called by the program entry point to execute the go program.
// With the "none" scheduler, init and the main function are invoked directly.
func run() {
initHeap()
initRand()
initHeap()
initAll()
callMain()
mainExited = true
+1
View File
@@ -21,6 +21,7 @@ var (
// Because we just use OS threads, we don't need to do anything special here. We
// can just initialize everything and run main.main on the main thread.
func run() {
initRand()
initHeap()
task.Init(stackTop)
initAll()
+3 -10
View File
@@ -3,19 +3,18 @@ package runtime
// This file implements compiler builtins for slices: append() and copy().
import (
"internal/gclayout"
"math/bits"
"unsafe"
)
// Builtin append(src, elements...) function: append elements to src and return
// the modified (possibly expanded) slice.
func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr) {
func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen, elemSize uintptr, layout unsafe.Pointer) (unsafe.Pointer, uintptr, uintptr) {
newLen := srcLen + elemsLen
if elemsLen > 0 {
// Allocate a new slice with capacity for elemsLen more elements, if necessary;
// otherwise, reuse the passed slice.
srcBuf, _, srcCap = sliceGrow(srcBuf, srcLen, srcCap, newLen, elemSize)
srcBuf, _, srcCap = sliceGrow(srcBuf, srcLen, srcCap, newLen, elemSize, layout)
// Append the new elements in-place.
memmove(unsafe.Add(srcBuf, srcLen*elemSize), elemsBuf, elemsLen*elemSize)
@@ -36,7 +35,7 @@ func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen uintptr, elemSize uintptr
}
// sliceGrow returns a new slice with space for at least newCap elements
func sliceGrow(oldBuf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr) {
func sliceGrow(oldBuf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr, layout unsafe.Pointer) (unsafe.Pointer, uintptr, uintptr) {
if oldCap >= newCap {
// No need to grow, return the input slice.
return oldBuf, oldLen, oldCap
@@ -48,12 +47,6 @@ func sliceGrow(oldBuf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr)
// memory allocators, this causes some difficult to debug issues.
newCap = 1 << bits.Len(uint(newCap))
var layout unsafe.Pointer
// less type info here; can only go off element size
if elemSize < unsafe.Sizeof(uintptr(0)) {
layout = gclayout.NoPtrs.AsPtr()
}
buf := alloc(newCap*elemSize, layout)
if oldLen > 0 {
// copy any data to new slice
+4
View File
@@ -190,6 +190,7 @@
- pkg: tiff
- repo: github.com/golang/geo
subdirs:
- pkg: earth
- pkg: r1
- pkg: r2
- pkg: r3
@@ -285,3 +286,6 @@
- repo: github.com/julienschmidt/httprouter
- repo: github.com/openhistogram/circonusllhist
skipwasi: true # math.MaxInt64 (untyped int constant 9223372036854775807) overflows int
- repo: github.com/philhofer/fwd
- repo: github.com/blevesearch/sear
- repo: github.com/steveyen/gtreap