casaroli opened a new pull request, #19772: URL: https://github.com/apache/nuttx/pull/19772
## Summary Xtensa selected neither fork primitive. `fork()` and `vfork()` were not available on any Xtensa target. This pull request gives the architecture both, and adds the kernel-build support that `fork()` needs. `vfork()` needs no assembly entry point on this architecture. Every exception entry already runs `SPILL_ALL_WINDOWS`, so the whole context of the caller is in its exception frame. A flat build reaches that frame with `SYS_save_context`, issued inline. A build with system calls reaches it with `xcp.sregs`, which `xtensa_swint()` records. A stack copy needs more than a new stack pointer here. A windowed ABI keeps the stack pointer of the caller in the base save area below each frame, so a copy at a different address still names the parent. `xtensa_fork_rebase()` walks that chain and adds the offset. The copy starts one base save area below the stack pointer, because the frame that the child resumes into keeps the spilled a0 to a3 of its caller there. `fork()` needs per-process address environments, so the ESP32-S3 gets `BUILD_KERNEL` support. The chip has a 64 KiB MMU page, and `pgalloc.h` stopped at 16 KiB, so `mm/pgalloc` learns 32 KiB and 64 KiB pages. `up_addrenv_fork()` then duplicates an address environment into fresh pages at the same virtual addresses. The page pool is not kept mapped into the kernel address space. It is carved out of the PSRAM that user processes run from, and the external memory permissions are indexed by physical address, so a permanent kernel window onto the pool is a window onto every process. The kernel reaches a pool page through a small scratch region instead, mapped for one operation. Two slots are sufficient, because the deepest user is `up_addrenv_fork()`, which holds a source page and a destination page at once. ## Impact The change is specific to Xtensa. It adds capability and removes none. `vfork()` becomes available on Xtensa in all build modes. Code that tests `CONFIG_ARCH_HAVE_VFORK` now finds it on this architecture. `fork()` becomes available on the ESP32-S3 in a kernel build only. That is the only mode with address environments. `CONFIG_ARCH_HAVE_FORK` stays unset everywhere else. Three board configurations are new: `kernel_oct` for a WROOM-2 with octal flash, `kernel_quad` for a WROOM-1 N16R8 with quad flash, and `kernel_n8r2` for a module with 2 MB of PSRAM. No existing configuration changes. The `mm/pgalloc` commit touches shared code. It adds two cases to a preprocessor selection and changes no existing case. ## Testing Board: ESP32-S3-DevKitC. Two modules, an ESP32-S3-WROOM-2 N32R8V with 32 MB octal flash and 8 MB octal PSRAM, and an ESP32-S3-WROOM-1 N8R2 with 8 MB quad flash and 2 MB embedded PSRAM. Host: macOS 15 on Apple Silicon, `xtensa-esp32s3-elf-gcc` 12.2.0. | module | configuration | build mode | flash | result | |---|---|---|---|---| | WROOM-2 | `esp32s3-devkit:ostest` | flat | octal | `vfork()` passes, status 0 | | WROOM-2 | `esp32s3-devkit:knsh` | protected | octal | `vfork()` passes, status 0 | | WROOM-2 | `esp32s3-devkit:kernel_oct` | kernel | octal | `vfork()` and `fork()` pass, status 0 | | WROOM-1 N8R2 | `esp32s3-devkit:ostest` | flat | DIO | `vfork()` passes | | WROOM-1 N8R2 | `esp32s3-devkit:kernel_n8r2` | kernel | DIO | `vfork()` and `fork()` pass, status 0 | ``` user_main: vfork() test vfork_test: Child 6 ran and exited before the parent resumed user_main: fork() test fork_test: Child running independently (child) fork_test: Parent and child had independent memory ostest_main: Exiting with status 0 ``` `tools/checkpatch.sh -c -u -m -g` gives no errors. The protected row needs #19764, which lets a protected build boot from simple boot. It is not necessary for the flat or the kernel rows. ### Notes for a reviewer `kernel_n8r2` is sized tightly on purpose. Each of the text, data and heap regions is 2 pages of 64 KiB, so a process takes 384 KiB and a `fork()` peaks at 768 KiB. `ostest` has 115 KiB of text against a 128 KiB text region. A larger program needs a part with more PSRAM, not a larger pool. `kernel_quad` keeps the roomy defaults for a module with 8 MB. QIO flash does not boot on the N8R2 that I have, in any configuration, and the cause is outside this patch. `flash_qio_mode` is not linked into the image, so the QE bit of the flash is never set. The quad configurations therefore use DIO. I have not tested any Xtensa target other than the ESP32-S3. `vfork()` should work on the ESP32 and the ESP32-S2 without change, because the code is in `arch/xtensa/src/common`, but I have no board. A report from one would be welcome. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
