Skip to content

WIP: Implement undocument wifi registers, get AP mode working (QEMU-155) #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 56 commits into
base: esp-develop
Choose a base branch
from

Conversation

redfast00
Copy link

@redfast00 redfast00 commented Jul 4, 2023

This is a WIP PR that adds support for the ESP32 wifi peripheral. The code was ported from https://github.com/a159x36/qemu: the wifi changes were separated from the SPI changes, the code was cleaned up, and the bugs in the code that translated 802.11 packets to Ethernet packets were fixed.

At the moment, using the ESP32 in STA mode, getting an IP address via DHPC and sending HTTP requests from it works.

This PR is not ready to be merged as-is, but I'd like to get some feedback on it. The hardware registers were reverse engineered, so some registers might have a better name or different semantics than suggested in the code.

At the moment, using the ESP32 as AP is not yet supported; only using it in STA mode works. There is already some code that was copied from the a159x36/qemu repo, but this code is untested.

ESP32 as client, QEMU as AP works with the following command:

build/qemu-system-xtensa -nic user,model=misc.esp32_wifi,id=u1 -no-reboot -S -s -nographic -machine esp32 -drive file=../http_request/meshtest_http_10.0.0.8.bin,if=mtd,format=raw -object filter-dump,id=f1,file=dump.pcap,netdev=u1 -drive file=../efuse.bin,if=none,format=raw,id=efuse -global driver=nvram.esp32.efuse,property=drive,value=efuse

(this starts QEMU paused, so you'll need to resume it with gdb: ~/.espressif/tools/xtensa-esp-elf-gdb/11.2_20220823/xtensa-esp-elf-gdb/bin/xtensa-esp32-elf-gdb ../http_request/build/meshtest_http_10.0.0.8.elf -ex "target remote :1234" -ex "c")

The efuse file was dumped from a real ESP32 with espefuse.py dump; the separate files are then concatenated into a single file.

The meshtest_http_... file was built from
esp-idf/examples/protocols/http_request, configured to connect to one of the APs hardcoded in hw/misc/esp32_wifi_ap.c

dump.pcap will contain the Ethernet packets as seen on the QEMU network bus.

igrr and others added 30 commits May 22, 2023 14:17
Co-authored-by: Anton Maklakov <[email protected]>
Co-authored-by: Omar Chebib <[email protected]>
GDB considers window registers as pseudo registers, meaning that they
are calculated by GDB using the values of AR registers and windowbase.
This patch removes the window registers from the total number of
registers that QEMU will send to GDB, making the number of registers
match the one that GDB expects to see.
This commit introduces two environment variables which can be used
to adjust the list of registers sent from QEMU to GDB:
* If QEMU_XTENSA_CORE_REGS_ONLY is set, only non-privileged registers
  will be sent to GDB. This behavior is compatible with Espressif
  builds of GDB up to esp-2021r1.
* If QEMU_XTENSA_COUNT_WINDOW_REGS is set, QEMU will send window
  registers (a0-a15) to GDB. Enable this if you don't have a build of
  GDB which considers a0-a15 to be "raw" registers.
DP83848C PHY emulated by opencores_eth has several vendor-specific
MII registers at 0x10-0x1d. Reading these registers resulted in an
out-of-bounds access to the regs array.
Part of this commit adds bounds checking.
Since the PHYSTS vendor-specific register is accessed by some of the
embedded DP83848C drivers, the rest of the commit adds simple
emulation of this register, setting the bits depending on the link
status.
Co-authored-by: Maksim Naumenko <[email protected]>
This is an SSIPeripheral instance that knows how to respond to read_id
command. It doesn't store any data. It is sufficient for the IDF
driver to decide to turn on the PSRAM cache. Actual data storage in
PSRAM is emulated in DPORT.
Espressif RISC-V CPU has a different has way of treating interrupts, which is
not standard. Thus, this class will override the default RISC-V CPU behavior
to have 31 interrupt lines.
C3 UART overrides ESP32's UART
o-marshmallow and others added 8 commits June 27, 2023 14:21
Implement a first interface for Peripheral-to-Memory and Memory-to-Peripheral
transfers.
Cache entries where incorrectly described, which resulted in wrong values
being returned to the guest programs.
ESP32 as client, QEMU as AP works with the following command:

build/qemu-system-xtensa -nic user,model=misc.esp32_wifi,id=u1 -no-reboot -S -s -nographic -machine esp32 -drive file=../http_request/meshtest_http_10.0.0.8.bin,if=mtd,format=raw -object filter-dump,id=f1,file=dump.pcap,netdev=u1 -drive file=../efuse.bin,if=none,format=raw,id=efuse -global driver=nvram.esp32.efuse,property=drive,value=efuse

The efuse file was dumped from a real ESP32 with espefuse.py dump

The meshtest_http_... file was built from
esp-idf/examples/protocols/http_request, configured to connect to
one of the APs hardcoded in hw/misc/esp32_wifi_ap.c

Co-authored-by: Martin Johnson <[email protected]>
@github-actions github-actions bot changed the title WIP: Implement undocument wifi registers, get AP mode working WIP: Implement undocument wifi registers, get AP mode working (QEMU-155) Jul 4, 2023
@lcgamboa
Copy link

lcgamboa commented Jul 4, 2023

Hi @redfast00,

I use as a basis for Wifi support this same fork in Qemu that I use in the PICSimLab simulator. In the original code the MAC address is not read from the efuse file (it is hardwired to 0x10,0x01,0x00,0xc4,0x0a,0x24), I made some modifications to add this support. Take a look at the commits 60937cc and 912c7a9 .
As soon as I have time available I will look at your improvements.

@lcgamboa
Copy link

Hi @redfast00 ,

do you have made any progress on mapping the registers?
I made some modifications to my repository to use action frames with the ESP-NOW protocol.
It partially worked. I can send and receive data using ESP-NOW functions between some Qemu but the ACK frame is never generated. When sending a unicast packet, even unsuccessfully (without receiving the ACK) the callback function registered with esp_now_register_send_cb always reports that the packet was received.
I've already looked in the wifi simulation code where the information that the packet was sent successfully is passed to the esp32 and I haven't found it yet. If you have any tips I would be grateful.
I believe that the implementation of the confirmation of receipt part has to be added to the wifi simulation code, but to start I need to know where to pass the information to the esp32.
To put all Qemu on the same network I used the option below (each one must have a different mac address).
-nic socket,model=esp32_wifi,id=u1,mcast=230.0.0.1:1234

@redfast00
Copy link
Author

@lcgamboa I hope I'll be able to share something soon, but I haven't mapped out the ACK registers yet

@lcgamboa
Copy link

@redfast00 I managed to find out that device address 0x270 of esp32_phya returns the transmission status. It returns 0x00000000 when successful and 0x00002300 when not receiving the ACK. When I have time I will try to implement the communication synchronization part so that the ESPNOW examples work 100% in Qemu.

@redfast00
Copy link
Author

@lcgamboa I've since started reverse engineering the ESP32 MAC and PHY, see https://zeus.gent/blog/23-24/open-source-esp32-wifi-mac/

@lcgamboa
Copy link

lcgamboa commented Dec 9, 2023

@lcgamboa I've since started reverse engineering the ESP32 MAC and PHY, see https://zeus.gent/blog/23-24/open-source-esp32-wifi-mac/

Very cool work! In the meantime, I added WIFI support to Qemu ESP32C3 on my fork. I think it is better in your case to use a RISCV than Xtensa for your research.

@lcgamboa
Copy link

lcgamboa commented Dec 9, 2023

I made some modifications to my fork and managed to get SoftAp mode to work too. The only thing that still doesn't work is if a reset is applied. It is working for ESP32 and ESP32C3.

@ConDai
Copy link

ConDai commented Feb 27, 2025

Will this feature eventually be merged?

@redfast00
Copy link
Author

@ConDai unlikely, since this is based on reverse engineering

@igrr
Copy link
Member

igrr commented Feb 27, 2025

Hi, I generally don't mind merging this, we just need to have somebody at Espressif who has read and understood the code and can keep maintaining it in the subsequent releases. I think we will get to it at some point, however I can't give a definite timeline.

@redfast00
Copy link
Author

@igrr that's nice to hear :) some notes:

  • we implemented/reverse engineered registers until emulation of a wifi client worked. So this is not complete emulation of the wifi registers by any means
  • only one TX slot is implemented
  • the code that determines what channel the ESP32 is sending on, is very hacky
  • this is only for the esp32 (without suffix). The wifi hardware for other esp32 variants appears to be very similar, so it's likely that code could be ported.
  • (personal opinion) I think it might be better to rewrite the wifi register emulation part of this pull request with the actual hardware documentation in hand, instead of using our limited understanding of the hardware obtained through reverse engineering (which is incomplete and almost certainly also not entirely correct). The AP emulation should be usable though.
  • (personal opinion) it would be very nice if some documentation about the wifi registers/hardware were released; does not even have to be source code, register names/addresses and a very basic description of what they do would already be very useful. Even if it's in Chinese, we can translate it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants