The driver kept a character device, a ring buffer, a poll waiter list
and an encoder of its own, in parallel with everything the keyboard
upper half already provides. A USB keyboard was therefore the one
keyboard an application could not read like any other.
Register with keyboard_register() and report with keyboard_event(),
which removes the private character device and the four hundred lines
that served it. Special keys are reported with the SPEC event types
carrying a keycode, so an application no longer has to guess whether a
value in the character range is a character or an arrow key.
HIDKBD_ENCODED and HIDKBD_NODEBOUNCE go away with the code they guarded.
Encoding is now inherent to the event, and the previous report is no
longer an optimisation: a HID keyboard reports the keys that are down
rather than the transitions, so it is what tells a new press from a key
still held, and what tells that a key has been released.
Reporting the modifiers as keys is new, so it is behind
HIDKBD_REPORT_MODIFIERS and off by default.
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
Both switches end with a bare default label and no statement after it,
which a compiler is entitled to reject: a label has to label something.
GCC for MIPS does, and the file is new enough that no configuration had
compiled it yet.
The next commit makes USBHOST_HIDKBD select INPUT_KEYBOARD, which pulls
this file into twenty five configurations for the first time, ci20:jumbo
among them, so fix it here rather than let that commit break them.
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
The USB HID keyboard driver is about to report through the upper half
rather than through a character device of its own, which changes what
read() returns from a byte stream to struct keyboard_event_s. Ten
in-tree configurations have an application that consumes the byte
stream.
Add INPUT_KEYBOARD_BYTESTREAM, which renders each event with the
keyboard codec instead of copying the event structure, so those
applications keep working while they are converted.
Only the press events are rendered. A byte stream has no way to say
that a key came up, which is exactly what a keyboard reporting through a
character device has always delivered, so this reproduces the previous
behaviour rather than adding to it.
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
keyboard.h declares KEYBOARD_PRESS and KEYBOARD_RELEASE only, but the
type field of struct keyboard_event_s has four values: the two special
key types live in kbd_codec.h, under a different prefix.
Somebody writing a keyboard driver reads keyboard.h, sees two types, and
implements two types. Six of the nine drivers that register a keyboard
never report a special key at all, and the failure is silent: the build
is clean and the symptom is a key that does nothing.
Define all four here, as aliases of the kbd_decode() return values so
that a driver can feed both this interface and the byte stream codec
from a single source.
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
A keyboard driver that tracks modifier state has no way to report it.
Folding the modifier into the character that it produces loses the fact
that the key is down, so an application cannot bind an action to Ctrl or
Shift, and cannot tell that one is being held.
Add the eight modifiers to enum kbd_keycode_e and move LAST_KEYCODE to
the new end of the enumeration. Leaving LAST_KEYCODE behind would make
kbd_specpress() assert and kbd_decode() reject the new keycodes, since
both range check against it.
The keycodes are appended, so the values of the existing ones do not
change.
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
Wire the shared Ameba GPIO driver into the RTL8721F (amebagreen2) build and
add the EVB board glue:
- arch/arm/src/rtl8721f: build ameba_gpio.c (CMake/Make.defs), source the
common Ameba Kconfig, and add ameba_gpio_chip.h describing the chip's
three GPIO ports (A/B/C), their IRQs and the APBPeriph clock bit.
- arch/arm/src/common/ameba: teach the driver that amebagreen2's ROM
GPIO_Init does not call PAD_PullCtrl or GPIO_INTMode, so call both
explicitly after GPIO_Init; on RTL8721Dx (ram_common) these are harmless
redundant writes. Add the AMEBA_PORT_C / AMEBA_PC() helpers.
- boards/arm/rtl8721f/rtl8721f_evb: register output/input/interrupt demo
pins, add the bringup hook, and provide a minimal 'gpio' NSH defconfig.
- Documentation: add a GPIO section for the RTL8721F EVB and fix a
rising/falling typo in the PKE8721DAF page.
Hardware-verified on the RTL8721F EVB: output, input, and all interrupt
trigger/polarity combinations (rising/falling edge, level high/low).
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Assisted-by: Claude <noreply@anthropic.com>
The shared port ISR clears interrupt status with GPIO_INTStatusClearEdge(),
which only clears edge latches. For a level-triggered pin the status stays
asserted as long as the level is active, so the ISR re-enters forever once
the level fires -- the system hangs before the application can even service
the event.
Remember at configure time whether a pin is level-triggered, and in the ISR
mask such a pin (GPIO_INTConfig DISABLE) before invoking the callback. The
application re-enables it via go_enable() after servicing. Edge pins are
left unmasked, so their behaviour is unchanged.
This fixes a hang reproducible on RTL8721Dx and RTL8721F when a
level-high/level-low interrupt pin is used.
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Assisted-by: Claude <noreply@anthropic.com>
The fix was ported from the STM32G0 to all the STM32 platforms,
as the code is mostly the same hence presents the same failure
Signed-off-by: Javier Alonso <javieralonso@geotab.com>
When the interrupts get disabled, the callback(s) are still attached.
That structure is never cleared, causing several calls to attach/detach
to eventually fail as the callback queue gets full.
When the error occurs, the registration fails with error 12 (ENOMEM).
By detaching the IRQ and clearing the callbacks, this error doesn't
happen again
Signed-off-by: Javier Alonso <javieralonso@geotab.com>
Remove CONFIG_FSUTILS_PASSWD from 31 sim configs that do not use NSH
login or other passwd features. These configs lacked a cryptodev
backend required by FSUTILS_PASSWD after the PBKDF2 Kconfig tightening,
causing olddefconfig normalization failures in CI.
Fixes#19573
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
Restore the explicit signed conversion and parenthesize the sign-bit test
so it is evaluated before the bitwise AND. Without this, operator
precedence makes the decoder test bit zero instead of the sign bit and
negative inline operands are reported as large positive values.
Build the width mask without shifting by the full width of uint64_t.
This avoids recursively invoking UBSan while decoding a 64-bit inline
operand.
Signed-off-by: hanzhijian <hanzhijian@zepp.com>
Add platform documentation for the Realtek RTL8721F: a chip overview
page and the rtl8721f_evb board page, modelled on the existing RTL8720F
/ RTL8721Dx docs. The platform index picks them up automatically via
its */index glob.
The pages cover the vendor-SDK/toolchain dependency, the make and CMake
build/flash flow, and the hardware-verified features: NSH over the
LOG-UART console, littlefs at /data on the on-chip NOR flash, Wi-Fi
station and SoftAP via the wapi tool, and the DHCP client/server.
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Co-Authored-By: Claude <noreply@anthropic.com>
Bring up the last two RTL8721F feature blocks and wire them into the
nsh board configuration:
- littlefs on the on-chip flash MTD region (P2).
- WHC/INIC WiFi with the on-chip IPC control plane, NuttX net stack,
DHCP client and the wapi command tool (P3).
Two porting fixes were required for the WiFi control plane:
- ameba_ipc.c: the AP IPC device base (IPCAP_DEV) was carried over
verbatim from the RTL8720F template (0x40804000). On this SoC IPC0
lives at 0x40815000; using the wrong base makes ipc_table_init()
program the RX-full mask in the wrong register block, so the NP->AP
interrupt never fires and WiFi bring-up hangs waiting for the device
to answer. Point IPCAP_DEV at the correct 0x40815000 base.
- ameba_board.mk: the EVB silicon is B-cut, so link against the
ameba_rom_symbol_bcut*.ld ROM symbol tables (the A-cut tables resolve
the WiFi ROM helpers to the wrong addresses and fault at run time).
Validated on hardware: NSH comes up, wapi scan lists real APs, a WPA2
connect succeeds, the DHCP client obtains a lease and ICMP to the
public internet round-trips.
The board defconfig keeps SSID/passphrase as placeholders; real
credentials are supplied at run time via the wapi commands.
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Wire the RTL8721F km4tz core up to a working NuttShell:
- irq.h: renumber the KM4TZ external vector table to the RTL8721F
APIRQn map (UART_LOG=24, IPC=5, +GPIOB/C, TIMER7/8, ...).
- ameba_loguart.c: fix the LOG-UART base to 0x40810000. The former
0x401C6000 belongs to a different Ameba part; the wrong base bus-
faulted on the RX interrupt-enable write while TX still worked
(LOGUART_PutChar uses its own ROM-internal base).
- ameba_app_start.c: adjust the MPU read-only / RAM regions for the
RTL8721F memory map and seed the RTC on first power-on so the
SDM32K-clocked SYSTIMER comes up (mirrors the SDK app_rtc_init).
- ameba_ipc.c: move the km4tz<->km4ns IPC to APIRQn 5 (IPC_CPU0).
- ameba_board.mk: pull in fwlib ameba_rtc.c for the RTC_* symbols.
- defconfig: RTL8721F RAM map, enable TIMER/TIMER_ARCH/ARMV8M_SYSTICK
for a live system tick, and drop the WiFi/NET stack for now.
- scripts/Make.defs: use the RTL8721F_NOR flash profile.
Boots cleanly to nsh> on hardware; tick, RX and builtin apps verified.
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Add a P0 skeleton port for the Realtek RTL8721F (SDK codename Green2 /
amebagreen2). Structurally the RTL8721F is a twin of the RTL8720F -- the
AP/host core is km4tz (ARMv8-M.main, TrustZone secure) and the WiFi MAC/PHY
runs on the km4ns network-processor core -- so this port is modelled on the
RTL8720F one and shares the IC-agnostic ameba glue in
arch/arm/src/common/ameba.
This is the "configures and links" skeleton (rtl8721f_evb:nsh builds an
image end to end). Four differences from the RTL8720F template were needed
to make the empty shell link against amebagreen2:
* km4tz has no FPU (cmsis_cpu.h defines __FPU_PRESENT 0), so the chip does
not select ARCH_HAVE_FPU and the image is built soft-float.
* ameba_app_start.c matches amebagreen2's ram_km4tz silicon init: the
nocache MPU map, the non-secure ROM BSS clear, OSC4M (not OSC2M)
calibration gated on EFUSE cut >= B and CHIP_TYPE_ASIC_POSTSIM.
* amebagreen2 ships no lib_rom.a, so the ROM archive whole-archive link is
dropped; the WiFi/OS/non-secure ROM symbols come from the SDK
ameba_rom_symbol_acut{,_wifi,_os}.ld maps appended to the image2 linker
script, exactly as green2's own image2 link does.
* the AP WiFi security lib is lib_wifi_common.a (was lib_wifi_com_sec.a).
The per-chip IRQ vector table (irq.h) and the RAM_START/RAM_SIZE layout
still carry RTL8720F values and are refined in the follow-up bring-up work.
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BOARD_ETC_ROMFS_PASSWD_ENABLE now depends on FSUTILS_PASSWD and a
cryptodev backend so PBKDF2 passwd autogen cannot be enabled without
the runtime login stack. Fixes#19573.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
Enable BOARD_ETC_ROMFS_PASSWD_ENABLE and software cryptodev options on
all sim configs with CONFIG_NSH_CONSOLE_LOGIN so PBKDF2 login works on
NuttX 13.0+. Fixes#19573.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
As analyzed, the NuttX initial keyboard API design uses event
type KBD_SPECPRESS/KBD_SPECREL to deliver special keys
and KBD_PRESS/KBD_RELEASE to deliver ASCII codes.
But it seems that this design choice has not been followed
in virtio-input, goldfish_events and sim_keyboard designs
and result is that external keyboard special keys events
are mapped to KEYCODE_xxx values which start from 0 and
overlaps with ASCII keys.
The issue is tracked under #19527 number.
This set of changes correct events reporting for mentioned
keyboards to report right event type for special keys.
The solution is only partial at this phase.
Virtual and more complex keyboards usually deliver
key pressures as scancodes (key position on keyboard)
and mapping to ASCII for keys which corresponds to letter
and other similar keys lacks mapping of national alphabets,
second row symbols and switch to capital letter according
to modifiers.
Signed-off-by: Pavel Pisa <pisa@fel.cvut.cz>
When CONFIG_TESTING_OSTEST_MULTIUSER is enabled, default
CONFIG_LIBC_PASSWD_FILEPATH to a writable tmpfs path used by the
ostest multiuser passwd sub-test.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
Document setreuid/setregid, getresuid/getresgid, and how inode_reserve
assigns owner and group for pseudo-filesystem objects.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
Accept user#️⃣uid:gid:home lines produced by mkpasswd in addition
to the six-field gecos form, and raise the default line buffer to 256.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
Use inode_checkopenperm() for message queues, named semaphores, and
shm, and reallocate mqueue state when reopening after the last close.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
Set i_owner and i_group from the caller's effective credentials in
inode_reserve(), covering IPC objects, FIFOs, and pseudo-files.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
Implement POSIX real/effective/saved credential getters and paired
setters in the task group layer, with libc stubs and syscalls.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
The USB device controller drivers invoke CLASS_DISCONNECT() on every
USB bus reset, and a bus reset is the first step of normal host
enumeration. Every other class driver (cdcacm, usbmsc, rndis)
re-asserts DEV_CONNECT() at the end of its disconnect() handler so
that the device remains attached; cdcecm and cdcncm did not, so on
controllers that soft-disconnect around bus reset (e.g. rp2040, which
drops the pull-up in its bus-reset handler) a standalone CDC-ECM or
CDC-NCM device is left soft-disconnected by the first bus reset and
never enumerates on the host.
Mirror the cdcacm behavior and perform the soft connect in the
disconnect() methods, unless part of a composite device (composite.c
already re-connects in its own disconnect handler).
Fixes the standalone CDC-ECM case of issue #15880.
Validated on raspberrypi-pico (RP2040): with this change a standalone
CONFIG_NET_CDCECM device that previously never appeared on the host
enumerates via cdc_ether and pings with 0% loss. cdcncm has the
identical defect and receives the identical fix.
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
Co-authored-by: Xiang Xiao <xiaoxiang781216@gmail.com>
Assisted-by: Claude (Anthropic Claude Code)
rp2040_update_buffer_control()/rp23xx_update_buffer_control() re-arm an
endpoint buffer by setting the AVAILABLE bit in the buffer-control word,
which lives in DPSRAM. When a buffer is re-armed from the completion
path (rp2040_usbintr_buffstat/rp23xx_usbintr_buffstat), that runs after
the handler has cleared the endpoint's bit in BUFF_STATUS, which lives in
the USB controller register block -- a different peripheral region.
The bus fabric may reorder those two stores. If the controller observes
the AVAILABLE re-arm before the BUFF_STATUS clear lands, it can transmit
the next IN packet and latch its completion in BUFF_STATUS before the
clear arrives; the late clear then wipes that just-set completion bit.
The lost completion edge stops all further buffer interrupts for the
endpoint, so the class driver's write-complete callback never runs and
TX wedges permanently.
This is most visible on RP2350 (Cortex-M33) under dense/bursty IN traffic
such as CDC-NCM with TCP write buffers. Add a UP_DMB() at the top of the
AVAILABLE re-arm so the preceding BUFF_STATUS clear is ordered ahead of
it. (Non-SMP builds reduce spin_lock_irqsave to a barrier-free
up_irq_save, so nothing else orders these two stores.)
Assisted-by: Claude (Anthropic Claude Code)
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
Adds both xipfs configurations to the board configuration list, and notes
that xipfs-nxflat needs the NXFLAT tools (mknxflat and ldnxflat), which a
standard toolchain installation does not provide.
Impact: documentation only.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
The xipfs configuration enabled CONFIG_NXFLAT and the nxflatxip example,
whose build runs mknxflat to generate the module thunk. The NXFLAT tools
are not installed in the CI container, so every CI build of this
configuration failed with "mknxflat: command not found".
* xipfs keeps the file system, the xipfs command and the test suite. It
builds with a plain toolchain, so CI still covers the file system code.
* xipfs-nxflat adds CONFIG_NXFLAT and CONFIG_EXAMPLES_NXFLATXIP and is
excluded from the CI build list, the same treatment the other NXFLAT
configurations already get (eagle100:nxflat, lm3s6965-ek:qemu-nxflat,
olimex-lpc1766stk:thttpd-nxflat).
Impact: CI and board configurations only. No source or runtime change.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Pages for the three applications that come with xipfs: the command that
compacts a volume and prints its block map, the test suite and what each of
its sections covers, and the demo that downloads an NXFLAT module into a
volume and runs two instances of it in place.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
A configuration for the Pimoroni Pico Plus 2 that mounts xipfs on the flash
MTD and builds everything that exercises it: the test suite with fault
injection, the xipfs command, and the NXFLAT execute-in-place demo.
Building an NXFLAT module needs mknxflat and ldnxflat, so name them in the
rp23xx board Make.defs files, which already carry the rest of the NXFLAT
flags but not these.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Describe the write-once usage model, the strict in-place mmap and what
MAP_XIP_STRICT is for, extent pinning, manual defragmentation and how to read
its result, the power-loss ordering, the on-media layout, and the
limitations.
The NXFLAT page said ROMFS was the only file system able to serve the XIP
mappings its loader needs. That is now one of two, so point at both, and at
what the writable one adds: a module can arrive at run time instead of being
baked into a host-built image.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Give the QEMU boards the same directly addressable media the sim
configuration has: rammtd answers BIOC_XIPBASE with the base of its buffer,
so xipfs layered on it hands out real pointers and the in-place mmap path
can be exercised on an ARM target with no flash present. Registered as
/dev/rammtd and mounted at /mnt/xipfs when xipfs is configured.
Both mps2-an500 (Cortex-M7, armv7e-m) and mps2-an521 (Cortex-M33, armv8-m)
get it, which is what makes the filesystem testable on two different core
generations without either one needing flash.
Each board also gets a xipfs configuration that runs the test suite, so the
bringup above is exercised rather than only compiled. Both run the suite to
completion under QEMU 10.1, 90 checks apiece, the power loss sweeps included.
The an521 configuration carries CONFIG_CMSDK_UART0_RX_IRQ=48 and _TX_IRQ=49
rather than the reversed pair the an521 nsh configuration uses. That is the
SSE-200 order, receive first, and the one consistent both with the overflow
interrupt at 63 that nsh already has and with mps2-an500, which puts RX at 16
and TX at 17. With the pair reversed the TX interrupt reaches
uart_cmsdk_rx_interrupt, which acknowledges only UART_INTSTATUS_RX, so the
board live-locks on its first console write. Correcting nsh is left to a
separate change.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
rammtd answers BIOC_XIPBASE with the base of its RAM buffer, so it is a
usable stand-in for memory mapped NOR: extents are directly addressable and
the in-place mmap path can be exercised end to end without any flash. Mount
xipfs on it when it is the configured file system, and add a configuration
that runs the xipfs test suite, fault injection included.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
The flash MTD device answers BIOC_XIPBASE, which is what xipfs needs to
serve mappings straight out of the memory mapped QSPI flash. Mount it at
/mnt/xipfs when both are configured, formatting on first boot, so a board
comes up with somewhere to download and run a module from.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
A file system that answers statfs with a magic nothing maps to shows up as
"Unrecognized" in df. Give xipfs its constant alongside the others in
sys/statfs.h and the case in fs_gettype that turns it into a name.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
ROMFS is the usual way to carry executables on a NOMMU target with memory
mapped NOR flash: it can hand out a real flash pointer from mmap(), so the
NXFLAT loader maps a module's text in place instead of copying it into RAM.
But a ROMFS image is built on the host and is read only, so a module cannot
be downloaded onto the board at run time.
xipfs is a writable file system with the same in-place property. Each file
is stored as one physically contiguous, erase-block aligned extent, so an
mmap() of it resolves to flash_base + extent_offset and a loader can execute
the file where it already lies. This needs the underlying MTD driver to
answer BIOC_XIPBASE; on the RP2350 rp23xx_flash_mtd.c does.
Files are write once. A file is created, its size is declared, it is
written sequentially, closed, and is thereafter immutable until it is
deleted. That is the whole life cycle of a downloaded module, and it is
what licenses the design: the exact extent is reserved at create time, so
no file ever grows, moves, or fragments internally. Random writes, appends
and truncation of a written file are not supported and are refused.
The only source of fragmentation is therefore free space holes left by
deletes. Allocation fails with -ENOSPC when no single contiguous run is
large enough, and never defragments on its own; the caller decides whether
to compact and retry, through XIPFSIOC_DEFRAG. Defragmentation is manual,
best effort and interruptible: it is a loop of atomic single-extent
relocations, each one copy, commit, erase, so every stop point -- a time
budget, a pinned extent, an erase error -- leaves a consistent layout that
is simply less compact. It reports the largest contiguous run it achieved,
which is what tells the caller whether the retry will fit.
Metadata is committed power safely. Two metadata block sets are used in
ping-pong, each generation carrying a sequence number and a CRC, and every
state change is ordered as write the new data, flip the metadata reference,
then erase what the old one referenced. Mount scans both sets and selects
the last fully valid generation, so a torn write costs the interrupted
operation and nothing else.
A mapping takes a pin on the extent, and the pin lives on the extent rather
than on the file descriptor, so three running instances of one module hold
three pins and the extent becomes movable only when the last one goes.
Defragmentation skips pinned extents, which is what stops it relocating
code that is executing. The pin is released by munmap() or by the task
teardown walk, so a task that dies without unmapping does not leak it.
Directories are records in that same generation, carrying their own identity
and the identity of the directory holding them; the root is implicit and owns
identity zero. They are deliberately NOT objects in the data region, which
is what keeps the commit story in one piece: mkdir and rmdir add or remove a
record and commit one generation, exactly as create and unlink do, so there
is never a multi-object update to journal or an orphan to collect at mount.
An empty directory therefore exists, survives a remount, and costs one entry
out of the volume's fixed supply and no flash blocks at all.
A name is one path component; depth comes from the parent, so XIPFS_NAME_MAX
bounds a component, which is what statfs reports it as. Mount rebuilds the
tree and checks that it is one: identities unique, names unique within a
directory, every parent a live directory, and following parents reaching the
root -- a cycle on the medium would otherwise hang a path walk rather than
merely answering wrongly. '.' and '..' are refused as components, since an
entry stored under either could never be reached again.
The commands that act on the volume rather than on one file --
XIPFSIOC_DEFRAG and XIPFSIOC_LISTPINNED -- are reached through the ioctldir
method, on a descriptor for the mountpoint directory. They are accepted on
a descriptor for a file inside the volume too, but that route holds the file
open for the duration and an open extent cannot be relocated, so a pass
asked for that way is obstructed by the act of asking.
mmap() falls back to the generic RAM copy for ordinary readers when the
media cannot be addressed directly. A module loader must not silently get
a RAM copy, so MAP_XIP_STRICT is added: with it the mapping either resolves
in place or fails with -ENXIO, which the caller can turn into defragment
and retry.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
syslog_write_foreach() compares an unsigned count against a signed
accumulator:
size_t nwritten = 0;
ssize_t nwritten_max = -EIO;
...
if (nwritten > nwritten_max)
{
nwritten_max = nwritten;
}
return nwritten_max;
The usual arithmetic conversions promote nwritten_max to size_t, so -EIO
becomes 4294967291 on a 32-bit target, and the comparison is never true.
nwritten_max keeps its initial value and the function returns -EIO no
matter how many bytes actually went out. Observed under gdb on a running
target: nwritten == 64, nwritten_max == -5, (nwritten > nwritten_max) == 0.
Most callers discard the result -- syslog() itself returns void -- so this
is normally invisible. It becomes fatal when /dev/console is backed by
syslog_console_write(), because then stdio acts on it.
lib_fflush_unlocked() sees a negative return, sets __FS_FLAG_ERROR and
returns early, before resetting fs_bufpos. The bytes have already been
emitted, but the buffer is never cleared, so every subsequent stdio call
re-flushes the same CONFIG_STDIO_BUFFER_SIZE bytes. The console fills
with one repeated fragment and the system makes no further progress.
Reaching that state needs CONFIG_CONSOLE_SYSLOG=y together with no driver
claiming /dev/console ahead of syslog_console_init(). Three in-tree
defconfigs qualify: x86/qemu-i486:ostest, renesas/skp16c26:ostest and
x86_64/qemu-intel64:earlyfb. The other 56 CONSOLE_SYSLOG configurations
have a serial console that registers /dev/console first, which is why this
has gone unnoticed.
Introduced by 1685e8ff7b ("syslog: avoid an infinite loop if one channel
fails"), which changed nwritten_max from size_t to ssize_t = -EIO so that
an all-channels-failed case could be reported. Give nwritten the same type
so the comparison is signed, which preserves that intent: nwritten_max
stays -EIO only when no channel wrote anything. nwritten is never negative,
so the remaining comparisons against buflen are unaffected.
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
During the Toybox port to NuttX, Claude noticed that changes in the
menuconfig weren't taking affect. This issue exists for a long time on
NuttX, in fact BayLibre's presentation from 2017 make jokes about our
building system not been reliable:
https://www.youtube.com/watch?v=XUJK2htXxKw&t=320s
Stale archive members from $(AR)'s additive-only behavior can linger
after Kconfig toggles change which files provide a symbol, causing dead
weight or "multiple definition" link errors on incremental builds.
Fixed by splitting ARCHIVE into two macros: ARCHIVE keeps the original
additive behavior for apps/libapps.a, which many independent
subdirectories contribute to across a build, while the new
ARCHIVE_REBUILD deletes then archives for the far more common case
of a single Makefile building its own self-contained $(OBJS)
- all 39 such call sites now use it.
Assisted-By: Claude Sonnet 5
Signed-off-by: Alan C. Assis <acassis@gmail.com>
The reference manual (section 3.2.1) states the user has to
read GLERR and INTERR registers to clear their bits and release
ERR pin after the startup sequence. Error bits are set to 1 after
the startup if external power supply is used.
Not clearing the bits leads to subsequent read call errors if VBB
errors are checked.
Signed-off-by: Michal Lenc <michallenc@seznam.cz>
tcp_start_monitor() is called from accept() (net/inet/inet_sockif.c) for
each newly accepted connection. When the peer had already closed the
connection before accept() ran, the monitor takes an early-return path so
that any read-ahead data buffered on the connection can still be drained;
it returns OK in that case. accept() (net/socket/accept.c) then marks the
new socket _SF_CONNECTED unconditionally.
If the peer aborts the connection with an RST immediately after the
three-way handshake completes (for example any close with SO_LINGER
{1, 0}), the connection is moved to TCP_CLOSED with no buffered data, yet
accept() still hands back a socket that reports _SS_ISCONNECTED. A
subsequent blocking send() on that socket passes the connected check,
registers a send callback and waits on its semaphore forever: the only
TCP_ABORT event was delivered before the callback existed, and no further
ACK, POLL or disconnect event is generated for a closed connection, so the
waiter is never woken.
Any server that writes before reading can hit this; the telnet daemon
(netutils/telnetd) is one example, where the accepted session task blocks
in send() and never completes.
Only return OK from the already-closed path when there is actually
read-ahead data to drain. Otherwise the connection is dead, so fall
through to the -ENOTCONN return: accept() then fails cleanly instead of
handing back a socket wedged on a connection that will never make progress.
The graceful-close-with-pending-data case (the reason the OK path exists)
is preserved by the conn->readahead check.
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
Assisted-by: Claude (Anthropic Claude Code)
mkallsyms.py prints "Please execute the following command to install
dependencies: pip install pyelftools cxxfilt" and then calls
os._exit(errno.EINVAL). os._exit() terminates without flushing stdio, so
when stdout is a pipe -- which it always is under make -- the message sits in
the buffer and is discarded. What the developer sees is:
make[1]: *** [Makefile:65: nuttx] Error 22
with no indication of the cause anywhere in the build output. Error 22 is
just errno.EINVAL leaking out as an exit status. The same applies to
usage(), which exits ENOENT the same way.
Use sys.exit() in both places, which raises SystemExit and lets the
interpreter flush on the way out. Nothing else changes: the exit statuses
are the same, and os is no longer referenced, so the import goes too.
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
In a protected build arm_svcall.c treats the caller's CONTROL as part of
the saved system call state: it stores it in xcp.syscall[].ctrlreturn on
entry and restores it from there on SYS_syscall_return. All three
Cortex-M profiles do this -- armv6-m, armv7-m and armv8-m each define the
field in arch/arm/include/<arch>/irq.h and use it symmetrically.
arm_fork_direct() copied sysreturn and excreturn to the child but not
ctrlreturn. The child's TCB comes from kmm_zalloc(), so the field was
zero, and CONTROL == 0 is nPRIV clear: the child returned to user space
privileged while its parent returned unprivileged. The child ran out its
life with the MPU restrictions its parent is under silently lifted, which
is the isolation BUILD_PROTECTED exists to provide.
Nothing faults, and that is why this survived. CONTROL == 0 also selects
MSP, which sounds like it should crash immediately, but NuttX already
runs Cortex-M threads on MSP -- the parent's saved value is 0x1, nPRIV
set and SPSEL clear -- so the two differ only in the privilege bit and
there is no stack change to trip over. Privileged code then passes every
test unprivileged code passes, so ostest cannot see it either.
Measured on an RP2350 (Cortex-M33) in BUILD_PROTECTED, breaking at the
nxtask_start_fork() call in arm_fork_direct() during task_fork_test:
parent ctrlreturn 0x00000001, child ctrlreturn 0x00000000. With this
change both read 0x00000001.
BUILD_FLAT is unaffected: without CONFIG_LIB_SYSCALL, nsyscalls is 0 and
the whole block is skipped. armv7-a and armv7-r are unaffected too; they
carry cpsr instead, and that is already copied.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Two device-controller defects that break standard host error recovery,
found while root-causing why macOS never mounts a NuttX mass-storage
function (full analysis and host traces in apache/nuttx#19435):
1. epsubmit() aborted (-EBUSY) any IN request submitted while the
endpoint was halted. The mass storage class halts bulk-IN for a
failed device-to-host command (BOT-legal) and then submits the CSW;
the CSW was dropped on the floor, so after the host's Clear-Halt the
endpoint NAKed forever and the host timed out (macOS: 30 s, then a
Bulk-Only-reset/device-reset spiral until it disables the port).
This is exactly the race documented for years in the usbmsc_scsi.c
header (David Hewson's analysis); the USBMSC_STALL_RACEWAR sleep
workaround only survives hosts that clear the halt within 100 ms --
Linux does, macOS does not, which is why Linux testing never saw it.
Implement the stall-queueing contract instead: requests submitted
while an endpoint is halted are queued without arming the hardware
(arming rewrites the buffer control word and would silently clear
the STALL bit); a halt terminates any in-flight IN transfer (its
hardware buffer is disarmed by the STALL write and would never
complete); clearing the halt resets the data toggle and re-arms the
head of the queue; stale buffer completions latched for transfers
aborted by a halt are ignored. RP2040/RP23XX now select
ARCH_USBDEV_STALLQUEUE, which also retires the RACEWAR's two 100 ms
sleeps per failed command.
2. The USB_REQ_GETSTATUS handler in ep0setup() validated the request
but never queued the two-byte response, for all three recipients
(device/interface/endpoint), so EP0 NAKed the host's data stage
forever and every GET STATUS timed out. macOS issues GetPipeStatus
= GET STATUS(endpoint) on a halted pipe before running Bulk-Only
reset recovery and hit this on every probe; lsusb -v's device-status
query hangs on it as well. Send the response: endpoint recipient
reports the halt bit, device recipient reports self-powered,
interface reports zeros; the status stage is armed by handle_zlp()
exactly as for class-dispatched IN transfers.
Validated on RP2350 silicon (Raspberry Pi Pico 2 W, composite
CDC-ACM + CDC-NCM + USBMSC): pre-fix, a raw-usbfs replay of macOS's
sequence and timing reproduced both defects deterministically (CSW read
ETIMEDOUT after a delayed clear-halt; all GET STATUS variants
ETIMEDOUT). Post-fix: the CSW survives the halt and is delivered after
Clear-Halt with correct tag/status/residue across a post-stall delay
sweep of 0-1000 ms; all GET STATUS variants answer immediately with
correct halt reporting; no regressions in the exact-length SCSI suite,
Bulk-Only reset, FAT mount and full reads, CDC-NCM/ACM, or warm
reboots; and macOS now mounts the volume (together with the companion
usbmsc fixes). The rp2040 driver shares the code and receives the
identical fix (build-tested).
Assisted-by: Claude (Anthropic Claude Code)
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
cdcncm_send() defers each transmit with MSEC2TICK(CDCNCM_DGRAM_COMBINE_PERIOD)
(1 ms). MSEC2TICK() rounds up to the system tick, so at the default 100 Hz tick
the "1 ms" coalescing window becomes a full 10 ms tick (10-20 ms with phase),
adding that latency to every single-datagram reply (ICMP echo, TCP ACK, one-MSS
HTTP segment) and dominating the CDC-NCM round-trip time.
The window only coalesces datagrams appended within the same synchronous TX
burst (already queued before the worker runs), so an inter-burst delay adds
latency without batching benefit in the common case. Fire the transmit worker
immediately (delay 0); within-burst coalescing is preserved.
On RP2350 (Pico 2 W) USB-NIC at 100 Hz tick: ping RTT 21.7 -> 2.8 ms, a 257 KB
HTTP download 5.79 -> 0.92 s (44.5 -> 279 KB/s).
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
Assisted-by: Claude (Anthropic Claude Code)
Signed-off-by: Ricard Rosson <ricard@groundbits.com>