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]

Reply via email to