feat(xteink): add ESP32-C3 Wi-Fi emulation with qemu AP

Ports the ESP32 Wi-Fi emulation (esp32c3_wifi, esp32_wifi_ap, esp32_wlan_*)
from the lcgamboa/PICSimLab QEMU fork and integrates it behind the
esp32c3_wifi NIC model, plus the supporting radio peripherals
(ANA/PHYA/FE/PWR manager).

- Exposes an open SSID 'qemu' bridged to the host via QEMU user-mode NAT
  (libslirp, now enabled in the native build).
- Adds ESP-IDF 5.5 compatibility fixes: channel resolution from the
  beacon DS Parameter Set IE / AP lookup, persistent SYSCON register
  backing (phy_module_has_clock_bits), DMA inlink/outlink descriptor
  mirroring, RX descriptor ring reset on item.next==0, and descriptor
  ownership/length semantics.
- xteink-emu now starts with -nic user,model=esp32c3_wifi and synthesizes
  an eFuse image with a fixed guest MAC.

Verified against a stock Arduino-ESP32 sketch: scans, finds 'qemu',
associates, gets DHCP 192.168.4.15, and completes an outbound TCP
connection. Unmodified CrossPoint firmware still needs the power-button
hold during boot (tracked separately).
This commit is contained in:
2026-07-24 16:21:12 -04:00
parent ee101c8698
commit fe35cb68d6
21 changed files with 2246 additions and 29 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ nix run .#xteink-emu -- screenshot --output screen.png
nix run .#xteink-emu -- stop
```
State defaults to `/tmp/xteink-emu-$UID`; pass `--state-dir` to any subcommand for parallel instances. `wait` advances a persistent log cursor after each match.
State defaults to `/tmp/xteink-emu-$UID`; pass `--state-dir` to any subcommand for parallel instances. `wait` advances a persistent log cursor after each match. The emulator exposes the open Wi-Fi network `qemu`; guest traffic uses QEMU's user-mode NAT.
### WebAssembly
+4
View File
@@ -41,6 +41,7 @@
glib
libgcrypt
libpng
libslirp
pixman
zlib
];
@@ -51,10 +52,12 @@
cp -r ${keycodemapdb} subprojects/keycodemapdb
chmod -R u+w subprojects/keycodemapdb
sed -i "/subdir('fp')/d" tests/meson.build
substituteInPlace meson.build --replace-fail "static: true" "static: false"
'';
configurePhase = ''
runHook preConfigure
export PKG_CONFIG_PATH=${pkgs.libslirp}/lib/pkgconfig''${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}
./configure \
--prefix=$out \
--target-list=riscv32-softmmu \
@@ -65,6 +68,7 @@
--enable-gcrypt \
--enable-pixman \
--enable-png \
--enable-slirp \
--disable-werror \
--disable-docs \
--disable-tools
+67
View File
@@ -0,0 +1,67 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qemu/guest-random.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/misc/esp32_fe.h"
#define DEBUG 0
static uint64_t esp32_fe_read(void *opaque, hwaddr addr, unsigned int size)
{
uint32_t r = 0;
Esp32FeState *s = ESP32_FE(opaque);
r=s->mem[addr/4];
switch(addr){
case 0x174:
case 0x7C:
r=0xffffffff;
break;
}
if(DEBUG) printf("esp32_fe_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
return r;
}
static void esp32_fe_write(void *opaque, hwaddr addr, uint64_t value,
unsigned int size) {
Esp32FeState *s = ESP32_FE(opaque);
if(DEBUG) printf("esp32_fe_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
s->mem[addr/4]=(uint32_t)value;
}
static const MemoryRegionOps esp32_fe_ops = {
.read = esp32_fe_read,
.write = esp32_fe_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void esp32_fe_init(Object *obj)
{
Esp32FeState *s = ESP32_FE(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &esp32_fe_ops, s,
TYPE_ESP32_FE, 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
memset(s->mem,0,sizeof(s->mem));
}
static const TypeInfo esp32_fe_info = {
.name = TYPE_ESP32_FE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Esp32FeState),
.instance_init = esp32_fe_init,
};
static void esp32_fe_register_types(void)
{
type_register_static(&esp32_fe_info);
}
type_init(esp32_fe_register_types)
+71
View File
@@ -0,0 +1,71 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qemu/guest-random.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/misc/esp32_phya.h"
#define DEBUG 0
static uint32_t *g_mem;
static uint64_t esp32_phya_read(void *opaque, hwaddr addr, unsigned int size)
{
uint32_t r = 0;
Esp32PhyaState *s = ESP32_PHYA(opaque);
r=s->mem[addr/4];
if(DEBUG) printf("esp32_phya_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
return r;
}
void Esp32_WLAN_Set_Packet_Status(const uint32_t state){
if(g_mem){
g_mem[0x270/4] = state; //ESP32
g_mem[0x320/4] = state; //ESP32C3
}
}
static void esp32_phya_write(void *opaque, hwaddr addr, uint64_t value,
unsigned int size) {
Esp32PhyaState *s = ESP32_PHYA(opaque);
if(DEBUG) printf("esp32_phya_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
s->mem[addr/4]=(uint32_t)value;
}
static const MemoryRegionOps esp32_phya_ops = {
.read = esp32_phya_read,
.write = esp32_phya_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void esp32_phya_init(Object *obj)
{
Esp32PhyaState *s = ESP32_PHYA(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &esp32_phya_ops, s,
TYPE_ESP32_PHYA, 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
memset(s->mem,0,sizeof(s->mem));
g_mem = s->mem;
}
static const TypeInfo esp32_phya_info = {
.name = TYPE_ESP32_PHYA,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Esp32PhyaState),
.instance_init = esp32_phya_init,
};
static void esp32_phya_register_types(void)
{
type_register_static(&esp32_phya_info);
}
type_init(esp32_phya_register_types)
+787
View File
@@ -0,0 +1,787 @@
/**
* QEMU WLAN access point emulation
*
* Copyright (c) 2008 Clemens Kolbitsch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Modifications:
* 2008-February-24 Clemens Kolbitsch :
* New implementation based on ne2000.c
* 18/01/22 Martin Johnson : Modified for esp32 wifi emulation
* 08/12/23 lcgamboa@yahoo.com : Modified for esp32c3, espnow and SoftAp wifi emulation
*/
#include "qemu/osdep.h"
#include "net/net.h"
#include "qemu/timer.h"
#include "hw/irq.h"
#include "hw/misc/esp32_wifi.h"
#include "hw/misc/esp32_phya.h"
#include "esp32_wlan.h"
#include "esp32_wlan_packet.h"
// 50ms between beacons
#define BEACON_TIME 500000000
#define INTER_FRAME_TIME 5000000
#define WAIT_ACK_TIMEOUT 10000000
#define DEBUG 0
#define ENABLE_BEACON 1
#define DEBUG_DUMPFRAMES 0
#define DEBUG_WIRESHARK_IMPORT 0
// color defines
#define BLACK 0
#define RED 1
#define GREEN 2
#define YELLOW 3
#define BLUE 4
#define MAGNETA 5
#define CYAN 6
#define WHITE 7
#define ANSI_DEFAULT() printf("\033[0m")
#define ANSI_COLOR(f, b) printf("\033[%d;%dm", (f) + 30, (b) + 40)
#define ANSI_FG_LCOLOR(f) printf("\033[0;%dm", (f) + 30)
#define ANSI_FG_HCOLOR(f) printf("\033[1;%dm", (f) + 30)
access_point_info access_points[] = {
{"qemu", 1, -25, {0x10, 0x01, 0x00, 0xc4, 0x0a, 0x51}},
};
int nb_aps=sizeof(access_points)/sizeof(access_point_info);
static void Esp32_WLAN_beacon_timer(void *opaque)
{
struct mac80211_frame *frame;
Esp32WifiState *s = (Esp32WifiState *)opaque;
// only send a beacon if we are an access point
if((ENABLE_BEACON)&&(s->mode == Esp32_Mode_Station)){
if(s->ap_state!=Esp32_WLAN__STATE_STA_ASSOCIATED) {
for(int i=0;i<nb_aps;i++){
int ap = (i + s->beacon_ap)%nb_aps;
if (access_points[ap].channel==esp32_wifi_channel) {
memcpy(s->ap_macaddr,access_points[ap].mac_address,6);
frame = Esp32_WLAN_create_beacon_frame(&access_points[ap]);
Esp32_WLAN_init_ap_frame(s, frame);
Esp32_WLAN_insert_frame(s, frame);
break;
}
}
s->beacon_ap=(s->beacon_ap+1)%nb_aps;
}
}
timer_mod(s->beacon_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + BEACON_TIME);
}
static void Esp32_WLAN_inject_timer(void *opaque)
{
Esp32WifiState *s = (Esp32WifiState *)opaque;
struct mac80211_frame *frame;
frame = s->inject_queue;
if (frame) {
// remove from queue
s->inject_queue_size--;
s->inject_queue = frame->next_frame;
Esp32_sendFrame(s, (void *)frame, frame->frame_length,frame->signal_strength);
free(frame);
}
if (s->inject_queue_size > 0) {
// there are more packets... schedule
// the timer for sending them as well
timer_mod(s->inject_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + INTER_FRAME_TIME);
} else {
// we wait until a new packet schedules
// us again
s->inject_timer_running = 0;
}
}
static void Esp32_WLAN_Wait_ACk_timer(void *opaque)
{
Esp32WifiState *s = (Esp32WifiState *)opaque;
Esp32_WLAN_frame_delivered(s);
}
static void macprint(const uint8_t *p, const char * name) {
printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n",name, p[0],p[1],p[2],p[3],p[4],p[5]);
}
static void buffer_print(uint8_t * b, unsigned size){
for(int i=0;i < size ;i++) {
if((i%16)==0) printf("%04x: ",i);
printf("%02x ",b[i]);
if((i%16)==15) printf("\n");
}
if((size%16)!=0)printf("\n");
}
static void infoprint(struct mac80211_frame *frame) {
if(DEBUG_DUMPFRAMES) {
#if (DEBUG_WIRESHARK_IMPORT == 0 )
printf("\nFrame Info type:%d subtype:%d flags:%d duration:%d length:%d\n",frame->frame_control.type,
frame->frame_control.sub_type,frame->frame_control.flags,frame->duration_id, frame->frame_length);
printf("protocol_version: %i\n",frame->frame_control.protocol_version);
printf("type: %i ",frame->frame_control.type );
switch (frame->frame_control.type)
{
case IEEE80211_TYPE_MGT:
printf("MGT\n");
break;
case IEEE80211_TYPE_CTL:
printf("CTL\n");
break;
case IEEE80211_TYPE_DATA:
printf("DATA\n");
break;
}
printf("subtype: %i ",frame->frame_control.sub_type);
switch (frame->frame_control.type)
{
case IEEE80211_TYPE_MGT:
switch (frame->frame_control.sub_type)
{
case IEEE80211_TYPE_MGT_SUBTYPE_BEACON:
printf("BEACON\n");
break;
case IEEE80211_TYPE_MGT_SUBTYPE_ACTION:
printf("ACTION\n");
break;
case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ:
printf("PROBE_REQ\n");
break;
case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP:
printf("PROBE_RESP\n");
break;
case IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION:
printf("AUTHENTICATION\n");
break;
case IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION:
printf("DEAUTHENTICATION\n");
break;
case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ:
printf("ASSOCIATION_REQ\n");
break;
case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP:
printf("ASSOCIATION_RESP\n");
break;
case IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION:
printf("DISASSOCIATION\n");
break;
default:
printf("---\n");
break;
}
break;
case IEEE80211_TYPE_CTL:
switch (frame->frame_control.sub_type)
{
case IEEE80211_TYPE_CTL_SUBTYPE_ACK:
printf("ACK\n");
break;
default:
printf("---\n");
break;
}
break;
case IEEE80211_TYPE_DATA:
switch (frame->frame_control.sub_type)
{
case IEEE80211_TYPE_DATA_SUBTYPE_DATA:
printf("DATA\n");
break;
default:
printf("---\n");
break;
}
break;
}
printf("flags: %i\n",frame->frame_control.flags);
printf("duration_id: %i\n",frame->duration_id);
macprint(frame->destination_address,"destination");
macprint(frame->source_address,"source");
macprint(frame->bssid_address,"bssid");
printf("fragment_number: %u\n",frame->sequence_control.fragment_number);
printf("sequence_number : %u\n",frame->sequence_control.sequence_number);
switch (frame->frame_control.type)
{
case IEEE80211_TYPE_MGT:
switch (frame->frame_control.sub_type)
{
case IEEE80211_TYPE_MGT_SUBTYPE_BEACON:
printf("beacon timestamp : %lu\n",(unsigned long) frame->beacon_info.timestamp);
printf("beacon interval : %u\n",frame->beacon_info.interval);
printf("beacon capability : %u\n",frame->beacon_info.capability);
break;
default:
if(frame->frame_length > IEEE80211_HEADER_SIZE)
buffer_print((uint8_t *)frame->data_and_fcs, frame->frame_length - IEEE80211_HEADER_SIZE);
break;
}
break;
case IEEE80211_TYPE_CTL:
switch (frame->frame_control.sub_type)
{
default:
if(frame->frame_length > IEEE80211_HEADER_SIZE)
buffer_print((uint8_t *)frame->data_and_fcs, frame->frame_length - IEEE80211_HEADER_SIZE);
break;
}
break;
case IEEE80211_TYPE_DATA:
switch (frame->frame_control.sub_type)
{
default:
printf("EtherType 0x%02X%02X\n",frame->data_and_fcs[6],frame->data_and_fcs[7]);
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==0x06) {
printf("ARP\n");
arp_header_t *header=(arp_header_t *)&frame->data_and_fcs[8];
printf("Operation %i\n", header->operation>>8);
}
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==0x00) {
printf("IPV4\n");
ip_header_t *header=(ip_header_t *)&frame->data_and_fcs[8];
printf("Protocol: 0x%04X\n",header->protocol);
switch (header->protocol)
{
case 0x11:
printf("UDP\n");
break;
case 0x06:
printf("TCP\n");
break;
}
}
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==0xdd) {
printf("IPV6\n");
}
if(frame->frame_length > IEEE80211_HEADER_SIZE)
buffer_print((uint8_t *)frame->data_and_fcs, frame->frame_length - IEEE80211_HEADER_SIZE);
break;
}
break;
}
printf("frame_length : %u\n", frame->frame_length);
#else
uint8_t *b=(uint8_t *)frame;
for(int i=0;i<frame->frame_length;i++) {
if((i%16)==0) printf("\n%04x: ",i);
printf("%02x ",b[i]);
}
printf("\n");
#endif
}
}
void Esp32_WLAN_insert_frame(Esp32WifiState *s, struct mac80211_frame *frame)
{
struct mac80211_frame *i_frame;
insertCRC(frame);
if(DEBUG) {
ANSI_FG_HCOLOR(GREEN);
printf("---------------\n>IN Send Frame type:%d subtype:%d channel:%d ap_state:%d time:%ld \n",frame->frame_control.type,frame->frame_control.sub_type,esp32_wifi_channel,s->ap_state,(unsigned long) qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
ANSI_DEFAULT();
}
infoprint(frame);
s->inject_queue_size++;
i_frame = s->inject_queue;
if (!i_frame) {
s->inject_queue = frame;
} else {
while (i_frame->next_frame) {
i_frame = i_frame->next_frame;
}
i_frame->next_frame = frame;
}
if (!s->inject_timer_running) {
// if the injection timer is not
// running currently, let's schedule
// one run...
s->inject_timer_running = 1;
timer_mod(s->inject_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + INTER_FRAME_TIME);
}
}
static _Bool Esp32_WLAN_can_receive(NetClientState *ncs)
{
Esp32WifiState *s = qemu_get_nic_opaque(ncs);
/*
if (s->ap_state != Esp32_WLAN__STATE_ASSOCIATED && s->ap_state != Esp32_WLAN__STATE_STA_ASSOCIATED) {
// we are currently not connected
// to the access point
return 0;
}
*/
if (s->inject_queue_size > Esp32_WLAN__MAX_INJECT_QUEUE_SIZE) {
// overload, please give me some time...
return 0;
}
return 1;
}
static ssize_t Esp32_WLAN_receive(NetClientState *ncs,
const uint8_t *buf, size_t size)
{
Esp32WifiState *s = qemu_get_nic_opaque(ncs);
struct mac80211_frame *frame;
if (!Esp32_WLAN_can_receive(ncs)) {
// this should not happen, but in
// case it does, let's simply drop
// the packet
return -1;
}
if (!s) {
return -1;
}
/*
* A 802.3 packet comes from the qemu network. The
* access points turns it into a 802.11 frame and
* forwards it to the wireless device
*/
frame = Esp32_WLAN_create_data_packet(s, buf, size);
if (frame) {
if(s->mode == Esp32_Mode_Station){
memcpy(s->ap_macaddr,s->associated_ap_macaddr,6);
if(s->ap_state==Esp32_WLAN__STATE_STA_ASSOCIATED) {
frame->frame_control.flags=1;
// if it's an arp request put the correct reply mac address in the packet
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==6) {
memcpy(frame->data_and_fcs+16,s->macaddr,6);
}
}
}
else{
memcpy(frame->destination_address, s->softap_macaddr,6);
if(s->ap_state==Esp32_WLAN__STATE_STA_ASSOCIATED) {
frame->frame_control.flags=1;
// if it's an arp request put the correct reply mac address in the packet
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==6) {
memcpy(frame->data_and_fcs+16,s->ap_macaddr,6);
}
}
}
if(((buf[12] & 0xE0) == IEEE80211_ENCAPSULATED)&&(buf[13] == ((IEEE80211_TYPE_MGT << 4)|IEEE80211_TYPE_MGT_SUBTYPE_ACTION)))
{
unsigned long ethernet_frame_size;
unsigned char ethernet_frame[1518];
struct mac80211_frame *reply = NULL;
//discard packages from others channels
if((buf[12] & 0x0F) != esp32_wifi_channel) return -1;
//discard packages originated from the same mac address
if(!memcmp(&buf[6],s->macaddr,6)) return -1;
//check destination
if((memcmp(&buf[0],BROADCAST,6))&&(memcmp(&buf[0],s->macaddr,6))) return -1;
//action frame
Esp32_WLAN_init_ap_frame(s, frame);
memcpy(frame->data_and_fcs, buf+14, size-14);
memcpy(frame->destination_address, &buf[0], 6);
memcpy(frame->source_address, &buf[6], 6);
memset(frame->bssid_address, 0xff, 6);
frame->frame_control.type= IEEE80211_TYPE_MGT;
frame->frame_control.sub_type= IEEE80211_TYPE_MGT_SUBTYPE_ACTION;
frame->frame_control.flags= ((buf[12] & 0xF0) == IEEE80211_ENCAPSULATED_PROTECTED) ? 0x40 : 00;
frame->duration_id= 0 ;
frame->frame_length-=12;
Esp32_WLAN_insert_frame(s, frame);
//if destination is broadcast, don´t send ack
if(!memcmp(&buf[0],BROADCAST,6)) return size;
//Send Ack
reply = Esp32_WLAN_create_ack();
memcpy(reply->destination_address, &buf[6], 6);
memcpy(reply->source_address, s->macaddr, 6);
memset(reply->bssid_address, 0xff, 6);
reply->duration_id=0;
if(DEBUG) {
ANSI_FG_HCOLOR(RED);
macprint(reply->destination_address,"---------------\n<OUT ACK send: dest ");
ANSI_DEFAULT();
}
infoprint(reply);
/*
* The access point uses the 802.11 frame
* and sends a 802.3 frame into the network...
* This packet is then understandable by
* qemu-slirp
*
* If we ever want the access point to offer
* some services, it can be added here!!
*/
// ethernet header type
ethernet_frame[12] = IEEE80211_ENCAPSULATED | esp32_wifi_channel;
ethernet_frame[13] = ((IEEE80211_TYPE_CTL << 4)|IEEE80211_TYPE_CTL_SUBTYPE_ACK);
memcpy(&ethernet_frame[0], reply->destination_address, 6);
memcpy(&ethernet_frame[6], reply->source_address, 6);
// add size of ethernet header
ethernet_frame_size = 14;
/*
* Send 802.3 frame
*/
qemu_send_packet(qemu_get_queue(s->nic), ethernet_frame, ethernet_frame_size);
return size;
}
if(((buf[12] & 0xF0)== IEEE80211_ENCAPSULATED)&&(buf[13] == ((IEEE80211_TYPE_CTL << 4)|IEEE80211_TYPE_CTL_SUBTYPE_ACK)))
{
//discard packages from others channels
if((buf[12] & 0x0F) != esp32_wifi_channel) return -1;
//discard packages originated from the same mac address
if(!memcmp(&buf[6],s->macaddr,6)) return -1;
//check destination
if(memcmp(&buf[0],s->macaddr,6)) return -1;
Esp32_WLAN_Set_Packet_Status(ESP32_PHYA_ACK);
timer_mod_anticipate(s->wait_ack_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
Esp32_WLAN_init_ap_frame(s, frame);
memcpy(frame->destination_address, &buf[0], 6);
memcpy(frame->source_address, &buf[6], 6);
memset(frame->bssid_address, 0xff, 6);
frame->frame_control.type= IEEE80211_TYPE_CTL;
frame->frame_control.sub_type= IEEE80211_TYPE_CTL_SUBTYPE_ACK;
frame->frame_control.flags= 0;
frame->duration_id= 0 ;
frame->frame_length = 10;
if(DEBUG) {
ANSI_FG_HCOLOR(GREEN);
macprint(&buf[6],"---------------\n>IN ACK received: source");
ANSI_DEFAULT();
}
infoprint(frame);
//ACK is not inserted in DMA
return size;
}
Esp32_WLAN_init_ap_frame(s, frame);
Esp32_WLAN_insert_frame(s, frame);
}
return size;
}
static void Esp32_WLAN_cleanup(NetClientState *ncs) { }
static NetClientInfo net_info = {
.type = NET_CLIENT_DRIVER_NIC,
.size = sizeof(NICState),
.can_receive = Esp32_WLAN_can_receive,
.receive = Esp32_WLAN_receive,
.cleanup = Esp32_WLAN_cleanup,
};
void Esp32_WLAN_reset_ap(Esp32WifiState *s) {
esp32_wifi_channel = 0;
s->ap_state = Esp32_WLAN__STATE_NOT_AUTHENTICATED;
s->beacon_ap=0;
s->mode = Esp32_Mode_Station;
memcpy(s->ap_macaddr,(uint8_t[]){0x10,0x13,0x46,0xbf,0x31,0x50},sizeof(s->ap_macaddr));
s->inject_timer_running = 0;
s->inject_sequence_number = 0;
s->inject_queue = NULL;
s->inject_queue_size = 0;
}
void Esp32_WLAN_setup_ap(DeviceState *dev,Esp32WifiState *s) {
Esp32_WLAN_reset_ap(s);
s->beacon_timer = timer_new_ns(QEMU_CLOCK_REALTIME, Esp32_WLAN_beacon_timer, s);
timer_mod(s->beacon_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME)+BEACON_TIME);
// setup the timer but only schedule
// it when necessary...
s->inject_timer = timer_new_ns(QEMU_CLOCK_REALTIME, Esp32_WLAN_inject_timer, s);
s->wait_ack_timer = timer_new_ns(QEMU_CLOCK_REALTIME, Esp32_WLAN_Wait_ACk_timer, s);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
memcpy(s->macaddr, s->conf.macaddr.a, sizeof(s->macaddr));
s->nic = qemu_new_nic(&net_info, &s->conf,
object_get_typename(OBJECT(s)), dev->id,
&dev->mem_reentrancy_guard, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->macaddr);
}
static void send_single_frame(Esp32WifiState *s, struct mac80211_frame *frame, struct mac80211_frame *reply) {
reply->sequence_control.sequence_number = s->inject_sequence_number++ +0x730;
reply->signal_strength=-10;
if(frame) {
memcpy(reply->destination_address, frame->source_address, 6);
if(s->mode == Esp32_Mode_Station){
memcpy(reply->source_address, s->macaddr, 6);
}
else{
memcpy(reply->source_address, s->ap_macaddr, 6);
}
memcpy(reply->bssid_address, frame->source_address, 6);
}
Esp32_WLAN_insert_frame(s, reply);
}
void Esp32_WLAN_handle_frame(Esp32WifiState *s, struct mac80211_frame *frame)
{
struct mac80211_frame *reply = NULL;
static access_point_info dummy_ap={0};
static char ssid[64];
unsigned long ethernet_frame_size;
unsigned char ethernet_frame[1518];
if(DEBUG){
if((ENABLE_BEACON)||!((frame->frame_control.type == IEEE80211_TYPE_MGT)&&(frame->frame_control.sub_type == IEEE80211_TYPE_MGT_SUBTYPE_BEACON))){
ANSI_FG_HCOLOR(RED);
printf("-------------------------\n<OUT Handle Frame type:%d subtype:%d channel:%d ap_state:%d time:%ld \n",frame->frame_control.type,
frame->frame_control.sub_type,esp32_wifi_channel,s->ap_state,(unsigned long) qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
ANSI_DEFAULT();
}
}
if((ENABLE_BEACON)||!((frame->frame_control.type == IEEE80211_TYPE_MGT)&&(frame->frame_control.sub_type == IEEE80211_TYPE_MGT_SUBTYPE_BEACON))){
infoprint(frame);
}
access_point_info *ap_info=0;
if(s->mode == Esp32_Mode_Station){
for(int i=0;i<nb_aps;i++)
if(access_points[i].channel==esp32_wifi_channel){
ap_info=&access_points[i];
break;
}
}
Esp32_WLAN_Set_Packet_Status(ESP32_PHYA_ACK);
if(frame->frame_control.type == IEEE80211_TYPE_MGT) {
switch(frame->frame_control.sub_type) {
case IEEE80211_TYPE_MGT_SUBTYPE_BEACON:
if(s->ap_state==Esp32_WLAN__STATE_NOT_AUTHENTICATED || s->ap_state==Esp32_WLAN__STATE_AUTHENTICATED) {
strncpy(ssid,(char *)frame->data_and_fcs+14,frame->data_and_fcs[13]);
if(DEBUG) printf("beacon from %s\n",ssid);
dummy_ap.ssid=ssid;
dummy_ap.channel = esp32_wifi_channel;
dummy_ap.sigstrength= -23;
memcpy(dummy_ap.mac_address,s->ap_macaddr,6) ;
memcpy(s->softap_macaddr,frame->bssid_address,6);
s->mode = Esp32_Mode_SoftAP;
s->ap_state=Esp32_WLAN__STATE_STA_NOT_AUTHENTICATED;
send_single_frame(s,frame,Esp32_WLAN_create_probe_request(&dummy_ap));
}
break;
case IEEE80211_TYPE_MGT_SUBTYPE_ACTION:
if(DEBUG) printf("action\n");
/*
* The access point uses the 802.11 frame
* and sends a 802.3 frame into the network...
* This packet is then understandable by
* qemu-slirp
*
* If we ever want the access point to offer
* some services, it can be added here!!
*/
// ethernet header type
ethernet_frame[12] = ((frame->frame_control.flags & 0x40) ? IEEE80211_ENCAPSULATED_PROTECTED : IEEE80211_ENCAPSULATED)| esp32_wifi_channel;
ethernet_frame[13] = ((IEEE80211_TYPE_MGT << 4)|IEEE80211_TYPE_MGT_SUBTYPE_ACTION);
memcpy(&ethernet_frame[0], frame->destination_address, 6);
memcpy(&ethernet_frame[6], s->macaddr, 6);
// add packet content
ethernet_frame_size = frame->frame_length -IEEE80211_HEADER_SIZE;
if (ethernet_frame_size > sizeof(ethernet_frame)) {
ethernet_frame_size = sizeof(ethernet_frame);
}
memcpy(&ethernet_frame[14], &frame->data_and_fcs[0], ethernet_frame_size);
// add size of ethernet header
ethernet_frame_size += 14;
/*
* Send 802.3 frame
*/
qemu_send_packet(qemu_get_queue(s->nic), ethernet_frame, ethernet_frame_size);
//if destination is not broadcast wait for ack
if(memcmp(&ethernet_frame[0],BROADCAST,6)){
Esp32_WLAN_Set_Packet_Status(ESP32_PHYA_NACK);
timer_mod(s->wait_ack_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + WAIT_ACK_TIMEOUT);
return;
}
break;
case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP:
ap_info=&dummy_ap;
strncpy(ssid,(char *)frame->data_and_fcs+14,frame->data_and_fcs[13]);
if(DEBUG) printf("probe resp from %s\n",ssid);
dummy_ap.ssid=ssid;
s->ap_state=Esp32_WLAN__STATE_STA_NOT_AUTHENTICATED;
send_single_frame(s,frame,Esp32_WLAN_create_deauthentication());
send_single_frame(s,frame,Esp32_WLAN_create_authentication_request());
break;
case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP:
if(DEBUG) printf("assoc resp\n");
mac80211_frame *frame1=Esp32_WLAN_create_dhcp_discover(s);
memcpy(frame1->bssid_address,BROADCAST,6);
memcpy(frame1->source_address,frame->destination_address,6);
memcpy(frame1->destination_address,frame->source_address,6);
send_single_frame(s,0,frame1);
s->ap_state=Esp32_WLAN__STATE_STA_DHCP;
break;
case IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION:
DEBUG_PRINT_AP(("Received disassociation!\n"));
send_single_frame(s,frame,Esp32_WLAN_create_disassociation());
if (s->ap_state == Esp32_WLAN__STATE_ASSOCIATED || s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED) {
s->ap_state = Esp32_WLAN__STATE_AUTHENTICATED;
}
break;
case IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION:
DEBUG_PRINT_AP(("Received deauthentication!\n"));
//reply = Esp32_WLAN_create_authentication_response(ap_info);
if (s->ap_state == Esp32_WLAN__STATE_AUTHENTICATED) {
s->ap_state = Esp32_WLAN__STATE_NOT_AUTHENTICATED;
}
break;
case IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION:
DEBUG_PRINT_AP(("Received authentication!\n"));
if(frame->data_and_fcs[2]==2) { // response
send_single_frame(s,frame,Esp32_WLAN_create_association_request(&dummy_ap));
}
break;
}
if(ap_info) {
memcpy(s->ap_macaddr,ap_info->mac_address,6);
switch(frame->frame_control.sub_type) {
case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ:
DEBUG_PRINT_AP(("Received probe request!\n"));
reply = Esp32_WLAN_create_probe_response(ap_info);
break;
case IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION:
DEBUG_PRINT_AP(("Received authentication req!\n"));
if(frame->data_and_fcs[2]==1) { // request
reply = Esp32_WLAN_create_authentication_response(ap_info);
if (s->ap_state == Esp32_WLAN__STATE_NOT_AUTHENTICATED) {
s->ap_state = Esp32_WLAN__STATE_AUTHENTICATED;
}
}
break;
case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ:
DEBUG_PRINT_AP(("Received association request!\n"));
reply = Esp32_WLAN_create_association_response(ap_info);
if (s->ap_state == Esp32_WLAN__STATE_AUTHENTICATED) {
s->ap_state = Esp32_WLAN__STATE_ASSOCIATED;
memcpy(s->associated_ap_macaddr,s->ap_macaddr,6);
}
break;
}
if (reply) {
reply->signal_strength=ap_info->sigstrength;
memcpy(reply->destination_address, frame->source_address, 6);
Esp32_WLAN_init_ap_frame(s, reply);
Esp32_WLAN_insert_frame(s, reply);
}
}
}
if ((frame->frame_control.type == IEEE80211_TYPE_DATA) &&
(frame->frame_control.sub_type == IEEE80211_TYPE_DATA_SUBTYPE_DATA)) {
if(s->ap_state == Esp32_WLAN__STATE_STA_DHCP) {
dhcp_request_t *req=(dhcp_request_t *)&frame->data_and_fcs[8];
// check for a dhcp offer
if(req->dhcp.bp_options[0]==0x35 && req->dhcp.bp_options[2]==0x2) {
mac80211_frame *frame1=Esp32_WLAN_create_dhcp_request(s,req->dhcp.yiaddr);
memcpy(frame1->bssid_address,BROADCAST,6);
memcpy(frame1->source_address,s->ap_macaddr,6);
memcpy(frame1->destination_address,frame->source_address,6);
send_single_frame(s,0,frame1);
//memcpy(s->ap_macaddr,(uint8_t[]){0x10,0x01,0x00,0xc4,0x0a,0x25},sizeof(s->ap_macaddr));
//memcpy(s->associated_ap_macaddr,s->ap_macaddr,sizeof(s->ap_macaddr));
memcpy(s->associated_ap_macaddr,s->macaddr,sizeof(s->macaddr));
s->ap_state=Esp32_WLAN__STATE_STA_ASSOCIATED;
if(DEBUG) printf("Dhcp received addr %d.%d.%d.%d\n",req->dhcp.yiaddr[0],req->dhcp.yiaddr[1],req->dhcp.yiaddr[2],req->dhcp.yiaddr[3]);
}
} else if (s->ap_state == Esp32_WLAN__STATE_ASSOCIATED || s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED) {
/*
* The access point uses the 802.11 frame
* and sends a 802.3 frame into the network...
* This packet is then understandable by
* qemu-slirp
*
* If we ever want the access point to offer
* some services, it can be added here!!
*/
// ethernet header type
ethernet_frame[12] = frame->data_and_fcs[6];
ethernet_frame[13] = frame->data_and_fcs[7];
// the new originator of the packet is
// the access point
if(s->ap_state == Esp32_WLAN__STATE_ASSOCIATED)
memcpy(&ethernet_frame[6], s->ap_macaddr, 6);
else
memcpy(&ethernet_frame[6], s->macaddr, 6);
if (ethernet_frame[12] == 0x08 && ethernet_frame[13] == 0x06) {
// for arp request, we use a broadcast
memset(&ethernet_frame[0], 0xff, 6);
} else {
// otherwise we forward the packet to
// where it really belongs
memcpy(&ethernet_frame[0], frame->destination_address, 6);
}
// add packet content
ethernet_frame_size = frame->frame_length - IEEE80211_HEADER_SIZE - 4 - 8;
// for some reason, the packet is 22 bytes too small (??)
ethernet_frame_size += 22;
if (ethernet_frame_size > sizeof(ethernet_frame)) {
ethernet_frame_size = sizeof(ethernet_frame);
}
memcpy(&ethernet_frame[14], &frame->data_and_fcs[8], ethernet_frame_size);
// add size of ethernet header
ethernet_frame_size += 14;
/*
* Send 802.3 frame
*/
qemu_send_packet(qemu_get_queue(s->nic), ethernet_frame, ethernet_frame_size);
}
}
Esp32_WLAN_frame_delivered(s);
}
+280
View File
@@ -0,0 +1,280 @@
/**
* QEMU WLAN device emulation
*
* Copyright (c) 2008 Clemens Kolbitsch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Modifications:
* 2008-February-24 Clemens Kolbitsch :
* New implementation based on ne2000.c
* 18/1/22 Martin Johnson : Modified for esp32 wifi emulation
*
*/
#ifndef esp32_wlan_h
#define esp32_wlan_h 1
//#define DEBUG_Esp32_WLAN
#ifdef DEBUG_Esp32_WLAN
#define DEBUG_PRINT_AP(x) \
do { \
struct timeval __tt; \
gettimeofday(&__tt, NULL); \
printf("%u:%u ", (unsigned)__tt.tv_sec, (unsigned)__tt.tv_usec); \
printf x ;\
} while (0)
#else
#define DEBUG_PRINT_AP(x)
#endif
#define IEEE80211_IDLE 0xff
#define IEEE80211_TYPE_MGT 0x00
#define IEEE80211_TYPE_CTL 0x01
#define IEEE80211_TYPE_DATA 0x02
#define IEEE80211_ENCAPSULATED 0xA0
#define IEEE80211_ENCAPSULATED_PROTECTED 0xB0
#define IEEE80211_TYPE_MGT_SUBTYPE_BEACON 0x08
#define IEEE80211_TYPE_MGT_SUBTYPE_ACTION 0x0d
#define IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ 0x04
#define IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP 0x05
#define IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION 0x0b
#define IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION 0x0c
#define IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ 0x00
#define IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP 0x01
#define IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION 0x0a
#define IEEE80211_TYPE_CTL_SUBTYPE_ACK 0x0d
#define IEEE80211_TYPE_DATA_SUBTYPE_DATA 0x00
#define IEEE80211_BEACON_PARAM_SSID 0x00
#define IEEE80211_BEACON_PARAM_RATES 0x01
#define IEEE80211_BEACON_PARAM_CHANNEL 0x03
#define IEEE80211_BEACON_PARAM_EXTENDED_RATES 0x32
#define IEEE80211_BEACON_PARAM_TIM 0x05
#define IEEE80211_HEADER_SIZE 24
typedef struct beacon_info_t {
uint64_t timestamp;
uint16_t interval;
uint16_t capability;
} QEMU_PACKED beacon_info_t;
typedef uint8_t macaddr_t[6];
#define BROADCAST (uint8_t[]){0xff,0xff,0xff,0xff,0xff,0xff}
typedef struct mac80211_frame {
struct mac80211_frame_control {
unsigned protocol_version : 2;
unsigned type : 2;
unsigned sub_type : 4;
unsigned flags:8;
} QEMU_PACKED frame_control;
uint16_t duration_id;
macaddr_t destination_address;
macaddr_t source_address;
macaddr_t bssid_address;
struct mac80211_sequence_control {
unsigned fragment_number : 4;
unsigned sequence_number : 12;
} QEMU_PACKED sequence_control;
// variable length, 2312 byte plus 4 byte frame-checksum
union {
uint8_t data_and_fcs[2316];
beacon_info_t beacon_info;
};
unsigned int frame_length;
int signal_strength;
int pos;
struct mac80211_frame *next_frame;
} QEMU_PACKED mac80211_frame;
typedef struct access_point_info {
const char *ssid;
int channel;
int sigstrength;
macaddr_t mac_address;
} access_point_info;
enum esp32_ap_state {
Esp32_WLAN__STATE_NOT_AUTHENTICATED,
Esp32_WLAN__STATE_AUTHENTICATED,
Esp32_WLAN__STATE_ASSOCIATED,
Esp32_WLAN__STATE_STA_NOT_AUTHENTICATED,
Esp32_WLAN__STATE_STA_AUTHENTICATED,
Esp32_WLAN__STATE_STA_ASSOCIATED,
Esp32_WLAN__STATE_STA_DHCP,
};
#define Esp32_WLAN__MAX_INJECT_QUEUE_SIZE 20
typedef struct {
signed rssi:8; /**< Received Signal Strength Indicator(RSSI) of packet. unit: dBm */
unsigned rate:5; /**< PHY rate encoding of the packet. Only valid for non HT(11bg) packet */
unsigned :1; /**< reserved */
unsigned sig_mode:2; /**< 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet */
unsigned legacy_length:12; /**< copy of the length */
unsigned damatch0:1; /* destination matches address0 */
unsigned damatch1:1; /* destination matches address1 */
unsigned bssidmatch0:1; /* bssid matches address0 */
unsigned bssidmatch1:1; /* bssid matches address1 */
unsigned mcs:7; /**< Modulation Coding Scheme. If is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76) */
unsigned cwb:1; /**< Channel Bandwidth of the packet. 0: 20MHz; 1: 40MHz */
unsigned :16; /**< reserved */
unsigned smoothing:1; /**< reserved */
unsigned not_sounding:1; /**< reserved */
unsigned :1; /**< reserved */
unsigned aggregation:1; /**< Aggregation. 0: MPDU packet; 1: AMPDU packet */
unsigned stbc:2; /**< Space Time Block Code(STBC). 0: non STBC packet; 1: STBC packet */
unsigned fec_coding:1; /**< Flag is set for 11n packets which are LDPC */
unsigned sgi:1; /**< Short Guide Interval(SGI). 0: Long GI; 1: Short GI */
signed noise_floor:8; /**< noise floor of Radio Frequency Module(RF). unit: 0.25dBm*/
unsigned ampdu_cnt:8; /**< ampdu cnt */
unsigned channel:4; /**< primary channel on which this packet is received */
unsigned secondary_channel:4; /**< secondary channel on which this packet is received. 0: none; 1: above; 2: below */
unsigned :8; /**< reserved */
unsigned timestamp:32; /**< timestamp. The local time when this packet is received. It is precise only if modem sleep or light sleep is not enabled. unit: microsecond */
unsigned :32; /**< reserved */
unsigned :31; /**< reserved */
unsigned ant:1; /**< antenna number from which this packet is received. 0: WiFi antenna 0; 1: WiFi antenna 1 */
unsigned sig_len:12; /**< length of packet including Frame Check Sequence(FCS) */
unsigned sig_len_copy:12; /**< another copy of the length */
unsigned rx_state:8; /**< state of the packet. 0: no error; others: error numbers which are not public */
} QEMU_PACKED wifi_pkt_rx_ctrl_t;
typedef struct {
signed rssi:8; /**< Received Signal Strength Indicator(RSSI) of packet. unit: dBm */
unsigned rate:5; /**< PHY rate encoding of the packet. Only valid for non HT(11bg) packet */
unsigned :1; /**< reserved */
unsigned sig_mode:2; /**< 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet */
unsigned legacy_length:12; /**< copy of the length */
unsigned damatch0:1; /* destination matches address0 */
unsigned damatch1:1; /* destination matches address1 */
unsigned bssidmatch0:1; /* bssid matches address0 */
unsigned bssidmatch1:1; /* bssid matches address1 */
unsigned mcs:7; /**< Modulation Coding Scheme. If is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76) */
unsigned cwb:1; /**< Channel Bandwidth of the packet. 0: 20MHz; 1: 40MHz */
unsigned :16; /**< reserved */
unsigned smoothing:1; /**< reserved */
unsigned not_sounding:1; /**< reserved */
unsigned :1; /**< reserved */
unsigned aggregation:1; /**< Aggregation. 0: MPDU packet; 1: AMPDU packet */
unsigned stbc:2; /**< Space Time Block Code(STBC). 0: non STBC packet; 1: STBC packet */
unsigned fec_coding:1; /**< Flag is set for 11n packets which are LDPC */
unsigned sgi:1; /**< Short Guide Interval(SGI). 0: Long GI; 1: Short GI */
unsigned :8; /**< reserved */
unsigned ampdu_cnt:8; /**< ampdu cnt */
unsigned channel:4; /**< primary channel on which this packet is received */
unsigned secondary_channel:4; /**< secondary channel on which this packet is received. 0: none; 1: above; 2: below */
unsigned :8; /**< reserved */
unsigned timestamp:32; /**< timestamp. The local time when this packet is received. It is precise only if modem sleep or light sleep is not enabled. unit: microsecond */
unsigned :32; /**< reserved */
signed noise_floor:8; /**< noise floor of Radio Frequency Module(RF). unit: dBm*/
unsigned :24; /**< reserved */
unsigned :32; /**< reserved */
unsigned :31; /**< reserved */
unsigned ant:1; /**< antenna number from which this packet is received. 0: WiFi antenna 0; 1: WiFi antenna 1 */
unsigned :32; /**< reserved */
unsigned :32; /**< reserved */
unsigned :32; /**< reserved */
unsigned sig_len:12; /**< length of packet including Frame Check Sequence(FCS) */
unsigned sig_len_copy:12; /**< another copy of the length */
unsigned rx_state:8; /**< state of the packet. 0: no error; others: error numbers which are not public */
} QEMU_PACKED wifi_pkt_rx_ctrl_c3_t;
extern int esp32_wifi_channel;
typedef uint8_t ip4_t[4];
#define DHCP_CHADDR_LEN 16
#define DHCP_SNAME_LEN 64
#define DHCP_FILE_LEN 128
typedef struct ip_header_t {
uint8_t version_size;
uint8_t dscp_ecn;
uint8_t len_h;
uint8_t len_l;
uint32_t z;
uint8_t ttl;
uint8_t protocol;
uint16_t checksum;
ip4_t source_ip;
ip4_t dest_ip;
}ip_header_t ;
typedef struct udp_header_t {
uint8_t src_port_h;
uint8_t src_port_l;
uint8_t dest_port_h;
uint8_t dest_port_l;
uint8_t len_h;
uint8_t len_l;
uint16_t checksum;
} udp_header_t;
typedef struct dhcp_t {
uint8_t opcode;
uint8_t htype;
uint8_t hlen;
uint8_t hops;
uint32_t xid;
uint16_t secs;
uint16_t flags;
ip4_t ciaddr;
ip4_t yiaddr;
ip4_t siaddr;
ip4_t giaddr;
uint8_t chaddr[DHCP_CHADDR_LEN];
char bp_sname[DHCP_SNAME_LEN];
char bp_file[DHCP_FILE_LEN];
uint32_t magic_cookie;
uint8_t bp_options[0];
} dhcp_t;
typedef struct dhcp_request_t {
ip_header_t ipheader;
udp_header_t udpheader;
dhcp_t dhcp;
} dhcp_request_t;
typedef struct arp_header_t {
uint16_t htype;
uint16_t ptype;
uint8_t hlen;
uint8_t plen;
uint16_t operation;
uint8_t sender_mac[6];
uint8_t sender_ip[4];
uint8_t target_mac[6];
uint8_t target_ip[4];
}arp_header_t;
#endif // esp32_wlan_h
+306
View File
@@ -0,0 +1,306 @@
/**
* QEMU WLAN access point emulation
*
* Copyright (c) 2008 Clemens Kolbitsch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Modifications:
* 2008-February-24 Clemens Kolbitsch :
* New implementation based on ne2000.c
* 18/1/22 Martin Johnson : Modified for esp32 wifi emulation
*/
#include "qemu/osdep.h"
#include "net/net.h"
#include "esp32_wlan.h"
#include "esp32_wlan_packet.h"
// the frame checksum isn't used so just put zero in there.
void insertCRC(mac80211_frame *frame) {
unsigned long crc;
unsigned char *fcs = (unsigned char *)frame;
crc = 0;
memcpy(fcs+frame->frame_length, &crc, 4);
frame->frame_length += 4;
}
static void add_byte(mac80211_frame *frame, uint8_t data) {
frame->data_and_fcs[frame->pos++]=data;
frame->frame_length=IEEE80211_HEADER_SIZE+frame->pos;
}
static void add_data(mac80211_frame *frame, int len,uint8_t *data) {
for(int i=0;i<len;i++)
add_byte(frame,data[i]);
}
static void add_tag(mac80211_frame *frame, int tag, int len, unsigned char bytes[]) {
add_byte(frame,tag);
add_byte(frame,len);
add_data(frame,len,bytes);
}
void Esp32_WLAN_init_ap_frame(Esp32WifiState *s, mac80211_frame *frame) {
frame->sequence_control.sequence_number = s->inject_sequence_number++;
if(s->mode == Esp32_Mode_Station){
if(s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED)
memcpy(frame->source_address, s->macaddr, 6);
else
memcpy(frame->source_address, s->ap_macaddr, 6);
memcpy(frame->bssid_address, s->ap_macaddr, 6);
}
else{
if(s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED)
memcpy(frame->source_address, s->ap_macaddr, 6);
else
memcpy(frame->source_address, s->softap_macaddr, 6);
memcpy(frame->bssid_address, s->softap_macaddr, 6);
}
}
static mac80211_frame *new_frame(unsigned type, unsigned subtype) {
mac80211_frame *frame = (mac80211_frame *)malloc(sizeof(mac80211_frame));
frame->next_frame = NULL;
frame->frame_control.protocol_version = 0;
frame->frame_control.type = type;
frame->frame_control.sub_type = subtype;
frame->frame_control.flags = 0;
frame->duration_id = 314;
frame->sequence_control.fragment_number = 0;
frame->pos=0;
return frame;
}
static void add_rates(mac80211_frame *frame) {
add_tag(frame,IEEE80211_BEACON_PARAM_RATES,8,(uint8_t[]){0x8b,0x96,0x82,0x84,0x0c,0x18,0x30,0x60});
add_tag(frame,IEEE80211_BEACON_PARAM_EXTENDED_RATES,4,(uint8_t[]){0x6c,0x12,0x24,0x48});
}
static void add_ssid(mac80211_frame *frame, const char *ssid) {
add_tag(frame,IEEE80211_BEACON_PARAM_SSID,strlen(ssid),(uint8_t *)ssid);
}
mac80211_frame *Esp32_WLAN_create_beacon_frame(access_point_info *ap) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_BEACON);
frame->signal_strength=ap->sigstrength;
memcpy(frame->destination_address,BROADCAST,6);
frame->beacon_info.timestamp=qemu_clock_get_ns(QEMU_CLOCK_REALTIME)/1000;
frame->beacon_info.interval=1000;
frame->beacon_info.capability=1;
frame->pos=12;
add_ssid(frame,ap->ssid);
add_rates(frame);
add_tag(frame,IEEE80211_BEACON_PARAM_CHANNEL,1,(uint8_t[]){ap->channel});
add_tag(frame,IEEE80211_BEACON_PARAM_TIM,4,(uint8_t[]){4,1,3,0,0});
return frame;
}
static uint16_t in_cksum(uint16_t *addr, int len) {
int sum = 0;
uint16_t answer = 0;
uint16_t *w = addr;
int nleft = len;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(uint8_t *)(&answer) = *(uint8_t *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}
static mac80211_frame *Esp32_WLAN_create_dhcp_frame(Esp32WifiState *s, int cmd_size, uint8_t dhcp_commands[]) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_DATA,IEEE80211_TYPE_DATA_SUBTYPE_DATA);
frame->frame_control.flags=1;
add_data(frame,8,(uint8_t[]){ 0xaa, 0xaa ,0x03 ,00 ,00 ,00 ,8 ,00});
dhcp_request_t req={
{.version_size=0x45,.ttl=0xff,.protocol=0x11,.dest_ip={0xff,0xff,0xff,0xff}},
{.src_port_l=0x44,.dest_port_l=0x43},
{.htype=1,.hlen=6,.xid=0x1d3d00,.chaddr={0,0,0,0,0,0},
.magic_cookie=0x63538263}
};
memcpy(req.dhcp.chaddr, s->macaddr, 6);
int len=sizeof(req)+cmd_size;
req.ipheader.len_h=len>>8;
req.ipheader.len_l=len&0xff;
len=len-sizeof(ip_header_t);
req.udpheader.len_h=len>>8;
req.udpheader.len_l=len&0xff;
req.ipheader.checksum=in_cksum((void *)&req.ipheader,sizeof(ip_header_t));
add_data(frame,sizeof(req),(uint8_t *)&req);
add_data(frame,cmd_size,dhcp_commands);
return frame;
}
mac80211_frame *Esp32_WLAN_create_dhcp_request(Esp32WifiState *s, uint8_t *ip) {
uint8_t dhcp_commands[]={
0x35, 1, 3,
0x39, 2 ,5 ,0xdc ,
0x32, 4, ip[0],ip[1],ip[2],ip[3],
0x3d, 0x07, 0x01, 0x3c, 0x61, 0x05, 0x0d, 0x99, 0x24,
0x37, 0x04, 0x01, 0x03, 0x1c, 0x06,
0xff, 0, 0
};
return Esp32_WLAN_create_dhcp_frame(s, sizeof(dhcp_commands),dhcp_commands);
}
mac80211_frame *Esp32_WLAN_create_dhcp_discover(Esp32WifiState *s) {
uint8_t dhcp_commands[]={
0x35, 1, 1,
0x39, 2 ,5 ,0xdc ,
0x0c ,0x09 ,0x65 ,0x73 ,0x70 ,0x72 ,0x65 ,0x73 ,0x73 ,0x69 ,0x66 ,
0x3d ,0x07, 0x01 ,0x3c ,0x61 ,0x05 ,0x0d ,0x99 ,0x24 ,
0x37 ,0x04 ,0x01 ,0x03 ,0x1c ,0x06 ,
0xff, 0,0
};
return Esp32_WLAN_create_dhcp_frame(s,sizeof(dhcp_commands),dhcp_commands);
}
mac80211_frame *Esp32_WLAN_create_association_request(access_point_info *ap) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ);
add_data(frame,4,(uint8_t []){0x21,4,3,0});
add_ssid(frame,ap->ssid);
add_rates(frame);
return frame;
}
mac80211_frame *Esp32_WLAN_create_ack(void) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_CTL,IEEE80211_TYPE_CTL_SUBTYPE_ACK);
frame->frame_length=10;
return frame;
}
mac80211_frame *Esp32_WLAN_create_probe_response(access_point_info *ap) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP);
frame->beacon_info.timestamp=qemu_clock_get_ns(QEMU_CLOCK_REALTIME)/1000;
frame->beacon_info.interval=1000;
frame->beacon_info.capability=1;
frame->pos=12;
add_ssid(frame,ap->ssid);
add_rates(frame);
add_tag(frame,IEEE80211_BEACON_PARAM_CHANNEL,1,(uint8_t[]){ap->channel});
return frame;
}
mac80211_frame *Esp32_WLAN_create_probe_request(access_point_info *ap) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ);
memcpy(frame->destination_address,BROADCAST,6);
memcpy(frame->bssid_address,BROADCAST,6);
add_ssid(frame,ap->ssid);
add_tag(frame,IEEE80211_BEACON_PARAM_CHANNEL,1,(uint8_t[]){ap->channel});
add_rates(frame);
return frame;
}
mac80211_frame *Esp32_WLAN_create_authentication_response(access_point_info *ap) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION);
/*
* Fixed params... typical AP params (6 byte)
*
* They include
* - Authentication Algorithm (here: Open System)
* - Authentication SEQ
* - Status code (successful 0x0)
*/
add_data(frame,6,(uint8_t []){0,0,2,0,0,0});
add_ssid(frame,ap->ssid);
return frame;
}
mac80211_frame *Esp32_WLAN_create_authentication_request(void) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION);
/*
* Fixed params... typical AP params (6 byte)
*
* They include
* - Authentication Algorithm (here: Open System)
* - Authentication SEQ
* - Status code (successful 0x0)
*/
//frame->duration_id=0x13a;
add_data(frame,6,(uint8_t []){0,0,1,0,0,0});
//add_data(frame,11,(uint8_t []){0,0,0,0,0,0,0,0,0,0,0});
//add_ssid(frame,ap->ssid);
return frame;
}
mac80211_frame *Esp32_WLAN_create_deauthentication(void) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION);
/*
* Insert reason code:
* "Deauthentication because sending STA is leaving"
*/
add_data(frame,2,(uint8_t []){3,0});
return frame;
}
mac80211_frame *Esp32_WLAN_create_association_response(access_point_info *ap) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP);
/*
* Fixed params... typical AP params (6 byte)
*
* They include
* - Capability Information
* - Status code (successful 0x0)
* - Association ID
*/
add_data(frame,6,(uint8_t []){33,4,0,0,1,0xc0});
add_ssid(frame,ap->ssid);
add_rates(frame);
return frame;
}
mac80211_frame *Esp32_WLAN_create_disassociation(void) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION);
/*
* Insert reason code:
* "Disassociation because sending STA is leaving"
*/
add_data(frame,2,(uint8_t []){3,0});
return frame;
}
mac80211_frame *Esp32_WLAN_create_data_packet(Esp32WifiState *s, const uint8_t *buf, int size) {
mac80211_frame *frame=new_frame(IEEE80211_TYPE_DATA,IEEE80211_TYPE_DATA_SUBTYPE_DATA);
frame->frame_control.flags = 0x2; /* from station back to station via AP */
frame->duration_id = 44;
/* send message to wlan-device */
if(s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED) {
memcpy(frame->destination_address, s->ap_macaddr, 6);
frame->frame_control.flags = 0x2;
}
else
memcpy(frame->destination_address, s->macaddr, 6);
/* LLC */
add_data(frame,6,(uint8_t[]){ 0xaa, 0xaa ,0x03 ,0 ,0 ,0});
memcpy(frame->data_and_fcs+6, buf+12, size-12);
frame->frame_length = IEEE80211_HEADER_SIZE + size-6;
return frame;
}
+56
View File
@@ -0,0 +1,56 @@
/**
* QEMU WLAN access point emulation
*
* Copyright (c) 2008 Clemens Kolbitsch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Modifications:
* 2008-February-24 Clemens Kolbitsch :
* New implementation based on ne2000.c
* 18/1/22 Martin Johnson : Modified for esp32 wifi emulation
*
*/
#ifndef esp32_wlan_packet_h
#define esp32_wlan_packet_h 1
#include "esp32_wlan.h"
#include "hw/misc/esp32_wifi.h"
void Esp32_WLAN_init_ap_frame(Esp32WifiState *s, struct mac80211_frame *frame);
int Esp32_WLAN_dumpFrame(struct mac80211_frame *frame, int frame_len, char *filename);
void Esp32_WLAN_insert_frame(Esp32WifiState *s, struct mac80211_frame *frame);
struct mac80211_frame *Esp32_WLAN_create_beacon_frame(access_point_info *ap);
struct mac80211_frame *Esp32_WLAN_create_probe_response(access_point_info *ap);
struct mac80211_frame *Esp32_WLAN_create_probe_request(access_point_info *ap);
struct mac80211_frame *Esp32_WLAN_create_authentication_request(void);
struct mac80211_frame *Esp32_WLAN_create_authentication_response(access_point_info *ap);
struct mac80211_frame *Esp32_WLAN_create_deauthentication(void);
struct mac80211_frame *Esp32_WLAN_create_association_request(access_point_info *ap);
struct mac80211_frame *Esp32_WLAN_create_association_response(access_point_info *ap);
struct mac80211_frame *Esp32_WLAN_create_disassociation(void);
struct mac80211_frame *Esp32_WLAN_create_data_reply(Esp32WifiState *s, struct mac80211_frame *incoming);
struct mac80211_frame *Esp32_WLAN_create_data_packet(Esp32WifiState *s, const uint8_t *buf, int size);
struct mac80211_frame *Esp32_WLAN_create_ack(void);
struct mac80211_frame *Esp32_WLAN_create_dhcp_discover(Esp32WifiState *s);
struct mac80211_frame *Esp32_WLAN_create_dhcp_request(Esp32WifiState *s, uint8_t *ip);
void insertCRC(mac80211_frame *frame);
#endif // esp32_wlan_packet_h
+87
View File
@@ -0,0 +1,87 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qemu/guest-random.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/misc/esp32c3_ana.h"
#define DEBUG 0
int esp32_wifi_channel = 0;
static uint64_t esp32c3_ana_read(void *opaque, hwaddr addr, unsigned int size)
{
Esp32C3AnaState *s = ESP32C3_ANA(opaque);
uint32_t r = s->mem[addr/4];
switch(addr) {
case 0x00:
case 0x48:
r= 0x00FFFFFF;
break;
case 0x50:
r=0x07000000 | s->mem[addr/4];
break;
case 0x04:
r= 0xFDFFFFFF;
break;
case 0x44:
case 0x4C:
case 0xC4:
r=0xFFFFFFFF;
break;
}
if(DEBUG) printf("esp32c3_ana_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
return r;
}
static void esp32c3_ana_write(void *opaque, hwaddr addr, uint64_t value,
unsigned int size) {
Esp32C3AnaState *s = ESP32C3_ANA(opaque);
if(DEBUG) printf("esp32c3_ana_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
if(addr == 0x150) {
int v= (value & 0x0FF00000) >> 0x14;
esp32_wifi_channel=(v-7)/5;
if(esp32_wifi_channel > 14) esp32_wifi_channel = 14;
//printf("wifi channel:0x%08x ",(int)value);
//printf("===========> esp32_wifi_channel %i \n", esp32_wifi_channel);
}
s->mem[addr/4]=value;
}
static const MemoryRegionOps esp32c3_ana_ops = {
.read = esp32c3_ana_read,
.write = esp32c3_ana_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void esp32c3_ana_init(Object *obj)
{
Esp32C3AnaState *s = ESP32C3_ANA(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &esp32c3_ana_ops, s,
TYPE_ESP32C3_ANA, 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
memset(s->mem,0,sizeof(s->mem));
}
static const TypeInfo esp32c3_ana_info = {
.name = TYPE_ESP32C3_ANA,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Esp32C3AnaState),
.instance_init = esp32c3_ana_init,
};
static void esp32c3_ana_register_types(void)
{
type_register_static(&esp32c3_ana_info);
}
type_init(esp32c3_ana_register_types)
+84
View File
@@ -0,0 +1,84 @@
/* ESP32C3 unimp/dummy peripheral handler
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/registerfields.h"
#include "hw/boards.h"
#include "hw/misc/esp32c3_pwrmng.h"
#include "hw/misc/esp32c3_reg.h"
#define DEBUG 0
static uint64_t esp32c3_pwrmng_read(void *opaque, hwaddr addr, unsigned int size)
{
static bool init = false;
Esp32c3PwrMngState *s = ESP32C3_PWR_MANAGER(opaque);
uint32_t r = s->mem[addr/4];
switch(addr){
case 0x07C:
/* Return a random 32-bit value */
if (!init) {
srand(time(NULL));
init = true;
}
r = rand();
break;
case 0x128: //DMA enabled
r = 0 ;
break;
case 0x118: //PWR int events
r = 0 ;
break;
}
if(DEBUG) printf("esp32_pwrmng_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
return r;
}
static void esp32c3_pwrmng_write(void *opaque, hwaddr addr,
uint64_t value, unsigned int size)
{
Esp32c3PwrMngState *s = ESP32C3_PWR_MANAGER(opaque);
if(DEBUG) printf("esp32_pwrmng_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
s->mem[addr/4]=value;
}
static const MemoryRegionOps esp32c3_pwrmng_ops = {
.read = esp32c3_pwrmng_read,
.write = esp32c3_pwrmng_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void esp32c3_pwrmng_init(Object *obj)
{
Esp32c3PwrMngState *s = ESP32C3_PWR_MANAGER(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &esp32c3_pwrmng_ops, s, TYPE_ESP32C3_PWR_MANAGER, 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
}
static const TypeInfo esp32c3_pwrmng_info = {
.name = TYPE_ESP32C3_PWR_MANAGER,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Esp32c3PwrMngState),
.instance_init = esp32c3_pwrmng_init,
};
static void esp32c3_pwrmng_register_types(void)
{
type_register_static(&esp32c3_pwrmng_info);
}
type_init(esp32c3_pwrmng_register_types)
+245
View File
@@ -0,0 +1,245 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qemu/guest-random.h"
#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "hw/hw.h"
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/misc/esp32c3_wifi.h"
#include "exec/address-spaces.h"
#include "esp32_wlan_packet.h"
#include "hw/qdev-properties.h"
#include "hw/misc/esp32c3_reg.h"
#define DEBUG 0
extern access_point_info access_points[];
extern int nb_aps;
static uint64_t esp32C3_wifi_read(void *opaque, hwaddr addr, unsigned int size)
{
Esp32WifiState *s = ESP32_WIFI(opaque);
uint32_t r = s->mem[addr/4];
switch(addr) {
case A_C3_WIFI_DMA_IN_STATUS:
r = 0;
break;
case A_C3_WIFI_DMA_INT_STATUS:
case A_C3_WIFI_DMA_INT_CLR:
r = s->raw_interrupt;
break;
case A_C3_WIFI_STATUS:
case A_C3_WIFI_DMA_OUT_STATUS:
r = 1;
break;
default:
break;
}
if (DEBUG) printf("esp32C3_wifi_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
return r;
}
static void set_interrupt(Esp32WifiState *s,int e) {
s->raw_interrupt |= e;
qemu_set_irq(s->irq, 1);
}
void Esp32_WLAN_frame_delivered(Esp32WifiState *s){
s->raw_interrupt |= 0x80;
qemu_set_irq(s->irq, 1);
}
static void esp32C3_wifi_write(void *opaque, hwaddr addr, uint64_t value,
unsigned int size) {
Esp32WifiState *s = ESP32_WIFI(opaque);
if(DEBUG) printf("esp32C3_wifi_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
switch (addr) {
case A_C3_WIFI_DMA_INLINK: {
uint32_t offset = value & 0xfffff;
s->dma_inlink_address = offset ? 0x3fc00000 | offset : 0;
s->mem[0x90 / sizeof(uint32_t)] = s->dma_inlink_address;
break;
}
case A_C3_WIFI_DMA_INT_CLR:
s->raw_interrupt &= ~value;
if (s->raw_interrupt == 0) {
qemu_set_irq(s->irq, 0);
}
break;
case A_C3_WIFI_DMA_OUTLINK:
if ((value & 0xc0000000) && (value & 0xfffff)) {
mac80211_frame frame;
dma_list_item item;
unsigned memaddr = 0x3fc00000 | (value & 0xfffff);
address_space_read(&address_space_memory, memaddr,
MEMTXATTRS_UNSPECIFIED, &item, sizeof(item));
if (item.length > sizeof(frame)) {
break;
}
address_space_read(&address_space_memory, item.address,
MEMTXATTRS_UNSPECIFIED, &frame, item.length);
frame.frame_length = item.length;
frame.next_frame = NULL;
Esp32_WLAN_handle_frame(s, &frame);
}
break;
default:
break;
}
s->mem[addr/4]=value;
}
static int match_mac_address(uint8_t *a1,uint8_t *a2) {
if(!memcmp(a1,a2,6)) return 1;
if(!memcmp(a1,BROADCAST,6)) return 1;
return 0;
}
// frame from ap to esp32
void Esp32_sendFrame(Esp32WifiState *s, mac80211_frame *frame,int length, int signal_strength) {
int packet_channel = esp32_wifi_channel;
if (s->dma_inlink_address == 0) {
return;
}
if (frame->frame_control.type == IEEE80211_TYPE_MGT &&
frame->frame_control.sub_type == IEEE80211_TYPE_MGT_SUBTYPE_BEACON) {
int pos = 12;
int data_length = length - IEEE80211_HEADER_SIZE;
while (pos + 2 <= data_length) {
uint8_t tag = frame->data_and_fcs[pos];
uint8_t tag_length = frame->data_and_fcs[pos + 1];
if (tag == IEEE80211_BEACON_PARAM_CHANNEL && tag_length) {
packet_channel = frame->data_and_fcs[pos + 2];
break;
}
pos += 2 + tag_length;
}
}
if (packet_channel == 0) {
const uint8_t *address = frame->frame_control.type == IEEE80211_TYPE_DATA
? frame->bssid_address : frame->source_address;
for (int i = 0; i < nb_aps; i++) {
if (memcmp(access_points[i].mac_address, address, 6) == 0) {
packet_channel = access_points[i].channel;
break;
}
}
}
uint8_t header[sizeof(wifi_pkt_rx_ctrl_c3_t)+length];
memset(header,0,sizeof(header));
wifi_pkt_rx_ctrl_c3_t *pkt=(wifi_pkt_rx_ctrl_c3_t *)header;
*pkt=(wifi_pkt_rx_ctrl_c3_t){
.rssi=(signal_strength+(rand()%10)+96),
.rate=11,
.sig_len=length,
.sig_len_copy=length,
.legacy_length=length,
.noise_floor=-97,
.channel=packet_channel,
.timestamp=qemu_clock_get_ns(QEMU_CLOCK_REALTIME)/1000,
};
// These 4 bits are set if the mac addresses previously stored at 0x40 and 0x48
// match the destination or bssid addresses in the frame
if(match_mac_address(frame->destination_address,(uint8_t *)s->mem+0x40))
pkt->damatch0=1;
if(match_mac_address(frame->destination_address,(uint8_t *)s->mem+0x48))
pkt->damatch1=1;
if(match_mac_address(frame->bssid_address,(uint8_t *)s->mem+0x40))
pkt->bssidmatch0=1;
if(match_mac_address(frame->bssid_address,(uint8_t *)s->mem+0x48))
pkt->bssidmatch1=1;
pkt->damatch0 = 1;
pkt->bssidmatch0 = 1;
memcpy(header+sizeof(wifi_pkt_rx_ctrl_c3_t),frame,length);
length+=sizeof(wifi_pkt_rx_ctrl_c3_t);
// do a DMA transfer from the hardware to esp32 memory
dma_list_item item;
address_space_read(&address_space_memory, s->dma_inlink_address,
MEMTXATTRS_UNSPECIFIED, &item, sizeof(item));
address_space_write(&address_space_memory, item.address,
MEMTXATTRS_UNSPECIFIED, header, length);
item.length = length;
item.eof = 1;
address_space_write(&address_space_memory, s->dma_inlink_address,
MEMTXATTRS_UNSPECIFIED, &item, sizeof(uint32_t));
s->mem[0x8c / sizeof(uint32_t)] = item.next;
s->mem[0x90 / sizeof(uint32_t)] = s->dma_inlink_address;
if (item.next) {
s->dma_inlink_address = item.next;
} else {
uint32_t base = s->mem[A_C3_WIFI_DMA_INLINK / sizeof(uint32_t)];
uint32_t offset = base & 0xfffff;
s->dma_inlink_address = offset ? 0x3fc00000 | offset : 0;
}
set_interrupt(s, 0x1004024);
}
static const MemoryRegionOps esp32C3_wifi_ops = {
.read = esp32C3_wifi_read,
.write = esp32C3_wifi_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void esp32c3_wifi_reset(DeviceState *dev)
{
Esp32WifiState *s = ESP32_WIFI(dev);
s->dma_inlink_address=0;
memset(s->mem,0,sizeof(s->mem));
Esp32_WLAN_reset_ap(s);
}
static void esp32C3_wifi_realize(DeviceState *dev, Error **errp)
{
Esp32WifiState *s = ESP32_WIFI(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
s->dma_inlink_address=0;
memory_region_init_io(&s->iomem, OBJECT(dev), &esp32C3_wifi_ops, s,
TYPE_ESP32_WIFI, 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
memset(s->mem,0,sizeof(s->mem));
Esp32_WLAN_setup_ap(dev, s);
}
static Property esp32C3_wifi_properties[] = {
DEFINE_NIC_PROPERTIES(Esp32WifiState, conf),
DEFINE_PROP_END_OF_LIST(),
};
static void esp32C3_wifi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = esp32C3_wifi_realize;
device_class_set_legacy_reset(dc, esp32c3_wifi_reset);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "Esp32C3 WiFi";
device_class_set_props(dc, esp32C3_wifi_properties);
}
static const TypeInfo esp32C3_wifi_info = {
.name = TYPE_ESP32_WIFI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Esp32WifiState),
.class_init = esp32C3_wifi_class_init,
};
static void esp32C3_wifi_register_types(void)
{
type_register_static(&esp32C3_wifi_info);
}
type_init(esp32C3_wifi_register_types)
+8 -1
View File
@@ -155,7 +155,14 @@ system_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files(
'esp32c3_jtag.c',
'esp32c3_rtc_cntl.c',
'esp_hmac.c',
'esp32c3_hmac.c'
'esp32c3_hmac.c',
'esp32c3_wifi.c',
'esp32_wifi_ap.c',
'esp32_wlan_packet.c',
'esp32c3_ana.c',
'esp32_phya.c',
'esp32_fe.c',
'esp32c3_pwrmng.c'
))
system_ss.add(when: 'CONFIG_XTENSA_ESP32S3', if_true: files(
+77 -26
View File
@@ -51,6 +51,11 @@
#include "hw/misc/esp32c3_ds.h"
#include "hw/misc/esp32c3_xts_aes.h"
#include "hw/misc/esp32c3_jtag.h"
#include "hw/misc/esp32c3_wifi.h"
#include "hw/misc/esp32c3_ana.h"
#include "hw/misc/esp32_phya.h"
#include "hw/misc/esp32_fe.h"
#include "hw/misc/esp32c3_pwrmng.h"
#include "hw/dma/esp32c3_gdma.h"
#include "hw/display/esp_rgb.h"
#include "hw/display/xteink_x3_eink.h"
@@ -76,6 +81,7 @@ struct Esp32C3MachineState {
EspRISCVCPU soc;
BusState periph_bus;
MemoryRegion iomem;
uint32_t syscon[0x1000 / sizeof(uint32_t)];
bool xteink;
bool x4;
@@ -183,12 +189,19 @@ static bool addr_in_range(hwaddr addr, hwaddr start, hwaddr end)
static uint64_t esp32c3_io_read(void *opaque, hwaddr addr, unsigned int size)
{
if (addr_in_range(addr + ESP32C3_IO_START_ADDR, DR_REG_RTC_I2C_BASE, DR_REG_RTC_I2C_BASE + 0x100)) {
return (uint32_t) 0xffffff;
} else if (addr + ESP32C3_IO_START_ADDR == DR_REG_SYSCON_BASE + A_SYSCON_ORIGIN_REG) {
Esp32C3MachineState *ms = opaque;
hwaddr absolute = addr + ESP32C3_IO_START_ADDR;
if (addr_in_range(absolute, DR_REG_NRX_BASE - 0xc00,
DR_REG_BB_BASE + 0x1000)) {
return UINT32_MAX;
} else if (addr_in_range(absolute, DR_REG_RTC_I2C_BASE,
DR_REG_RTC_I2C_BASE + 0x100)) {
return 0xffffff;
} else if (absolute == DR_REG_SYSCON_BASE + A_SYSCON_ORIGIN_REG) {
/* Return "QEMU" as a 32-bit value */
return 0x51454d55;
} else if (addr + ESP32C3_IO_START_ADDR == DR_REG_SYSCON_BASE + A_SYSCON_RND_DATA_REG) {
} else if (absolute == DR_REG_SYSCON_BASE + A_SYSCON_RND_DATA_REG) {
/* Return a random 32-bit value */
static bool init = false;
if (!init) {
@@ -196,8 +209,11 @@ static uint64_t esp32c3_io_read(void *opaque, hwaddr addr, unsigned int size)
init = true;
}
return rand();
} else if (addr + ESP32C3_IO_START_ADDR == DR_REG_ASSIST_DEBUG_BASE + A_ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG) {
} else if (absolute == DR_REG_ASSIST_DEBUG_BASE + A_ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG) {
return 0;
} else if (addr_in_range(absolute, DR_REG_SYSCON_BASE,
DR_REG_SYSCON_BASE + sizeof(ms->syscon))) {
return ms->syscon[(absolute - DR_REG_SYSCON_BASE) / sizeof(uint32_t)];
} else {
#if ESP32C3_IO_WARNING
warn_report("[ESP32-C3] Unsupported read to $%08lx\n", ESP32C3_IO_START_ADDR + addr);
@@ -208,8 +224,16 @@ static uint64_t esp32c3_io_read(void *opaque, hwaddr addr, unsigned int size)
static void esp32c3_io_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size)
{
Esp32C3MachineState *ms = opaque;
hwaddr absolute = addr + ESP32C3_IO_START_ADDR;
if (addr_in_range(absolute, DR_REG_SYSCON_BASE,
DR_REG_SYSCON_BASE + sizeof(ms->syscon))) {
ms->syscon[(absolute - DR_REG_SYSCON_BASE) / sizeof(uint32_t)] = value;
return;
}
#if ESP32C3_IO_WARNING
warn_report("[ESP32-C3] Unsupported write $%08lx = %08lx\n", ESP32C3_IO_START_ADDR + addr, value);
warn_report("[ESP32-C3] Unsupported write $%08lx = %08lx\n", absolute, value);
#endif
}
@@ -271,34 +295,60 @@ static void esp32c3_init_spi_flash(Esp32C3MachineState *ms, BlockBackend* blk)
}
static void esp32c3_map_radio_device(const char *type, hwaddr address)
{
DeviceState *device = qdev_new(type);
SysBusDevice *sbd = SYS_BUS_DEVICE(device);
sysbus_realize_and_unref(sbd, &error_fatal);
memory_region_add_subregion_overlap(get_system_memory(), address,
sysbus_mmio_get_region(sbd, 0), 0);
}
static bool esp32c3_init_wifi(Esp32C3MachineState *ms)
{
DeviceState *wifi = qemu_create_nic_device(TYPE_ESP32C3_WIFI, false, NULL);
SysBusDevice *sbd;
if (!wifi) {
return false;
}
esp32c3_map_radio_device(TYPE_ESP32C3_ANA, DR_REG_RTC_I2C_BASE);
esp32c3_map_radio_device(TYPE_ESP32_PHYA, DR_REG_PHYA_BASE);
esp32c3_map_radio_device(TYPE_ESP32_FE, DR_REG_FE_BASE);
esp32c3_map_radio_device(TYPE_ESP32C3_PWR_MANAGER, DR_REG_PWR_MANAGER_BASE);
sbd = SYS_BUS_DEVICE(wifi);
sysbus_realize_and_unref(sbd, &error_fatal);
memory_region_add_subregion_overlap(get_system_memory(), DR_REG_WIFI_BASE,
sysbus_mmio_get_region(sbd, 0), 0);
sysbus_connect_irq(sbd, 0,
qdev_get_gpio_in(DEVICE(&ms->intmatrix),
ETS_WIFI_MAC_INTR_SOURCE));
return true;
}
static void esp32c3_init_openeth(Esp32C3MachineState *ms)
{
MemoryRegion* mr = NULL;
SysBusDevice* sbd = NULL;
DeviceState *open_eth_dev = qemu_create_nic_device("open_eth", true, NULL);
SysBusDevice *sbd;
MemoryRegion* sys_mem = get_system_memory();
/* Create a new OpenCores Ethernet component */
DeviceState* open_eth_dev = qemu_create_nic_device("open_eth", true, NULL);
if (!open_eth_dev) {
return;
}
ms->eth = open_eth_dev;
sbd = SYS_BUS_DEVICE(open_eth_dev);
sysbus_realize(sbd, &error_fatal);
/* OpenCores Ethernet has two memory regions: one for registers and one for descriptors,
* we need to provide one I/O range for each of them */
mr = sysbus_mmio_get_region(sbd, 0);
memory_region_add_subregion_overlap(sys_mem, DR_REG_EMAC_BASE, mr, 0);
mr = sysbus_mmio_get_region(sbd, 1);
memory_region_add_subregion_overlap(sys_mem, DR_REG_EMAC_BASE + 0x400, mr, 0);
memory_region_add_subregion_overlap(get_system_memory(), DR_REG_EMAC_BASE,
sysbus_mmio_get_region(sbd, 0), 0);
memory_region_add_subregion_overlap(get_system_memory(),
DR_REG_EMAC_BASE + 0x400,
sysbus_mmio_get_region(sbd, 1), 0);
sysbus_connect_irq(sbd, 0,
qdev_get_gpio_in(DEVICE(&ms->intmatrix), ETS_ETH_MAC_INTR_SOURCE));
qdev_get_gpio_in(DEVICE(&ms->intmatrix),
ETS_ETH_MAC_INTR_SOURCE));
}
@@ -420,7 +470,7 @@ static void esp32c3_machine_init(MachineState *machine)
qdev_realize(DEVICE(&ms->soc), NULL, &error_fatal);
memory_region_init_io(&ms->iomem, OBJECT(&ms->soc), &esp32c3_io_ops,
NULL, "esp32c3.iomem", 0xd1000);
ms, "esp32c3.iomem", 0xd1000);
memory_region_add_subregion(sys_mem, ESP32C3_IO_START_ADDR, &ms->iomem);
@@ -495,8 +545,9 @@ static void esp32c3_machine_init(MachineState *machine)
}
}
/* Initialize OpenCores Ethernet controller now sicne it requires the interrupt matrix */
esp32c3_init_openeth(ms);
if (!esp32c3_init_wifi(ms)) {
esp32c3_init_openeth(ms);
}
/* USB Serial JTAG realization */
{
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include "hw/hw.h"
#include "hw/sysbus.h"
#define TYPE_ESP32_FE "misc.esp32.fe"
#define ESP32_FE(obj) OBJECT_CHECK(Esp32FeState, (obj), TYPE_ESP32_FE)
//OBJECT_CHECK(Esp32FeState, (obj), TYPE_ESP32_FE)
//(Esp32FeState *)(obj)
typedef struct Esp32FeState {
SysBusDevice parent_obj;
MemoryRegion iomem;
uint32_t mem[1024];
} Esp32FeState;
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "hw/hw.h"
#include "hw/sysbus.h"
#define TYPE_ESP32_PHYA "misc.esp32.phya"
#define ESP32_PHYA(obj) OBJECT_CHECK(Esp32PhyaState, (obj), TYPE_ESP32_PHYA)
typedef struct Esp32PhyaState {
SysBusDevice parent_obj;
MemoryRegion iomem;
uint32_t mem[1024];
} Esp32PhyaState;
#define ESP32_PHYA_NACK 0x00002300
#define ESP32_PHYA_ACK 0x0
void Esp32_WLAN_Set_Packet_Status(const uint32_t state);
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#include "hw/hw.h"
#include "hw/registerfields.h"
#include "hw/sysbus.h"
//#include "hw/misc/esp32_reg.h"
#include "sysemu/sysemu.h"
#include "net/net.h"
#define TYPE_ESP32_WIFI "esp32c3_wifi"
#define ESP32_WIFI(obj) OBJECT_CHECK(Esp32WifiState, (obj), TYPE_ESP32_WIFI)
typedef struct dma_list_item {
unsigned size:12;
unsigned length:12;
unsigned :6;
unsigned eof:1;
unsigned owner:1;
uint32_t address;
uint32_t next;
} QEMU_PACKED dma_list_item;
typedef struct Esp32WifiState {
SysBusDevice parent_obj;
MemoryRegion iomem;
int raw_interrupt;
qemu_irq irq;
uint32_t mem[1024];
int dma_inlink_address;
uint32_t ap_state;
int inject_queue_size;
struct mac80211_frame *inject_queue;
int inject_timer_running;
unsigned int inject_sequence_number;
int beacon_ap;
hwaddr receive_queue_address;
uint32_t receive_queue_count;
NICConf conf;
NICState *nic;
// various timers
QEMUTimer *beacon_timer;
QEMUTimer *inject_timer;
QEMUTimer *wait_ack_timer;
uint8_t ipaddr[4];
uint8_t macaddr[6];
uint8_t ap_ipaddr[4];
uint8_t ap_macaddr[6];
uint8_t associated_ap_macaddr[6];
uint8_t softap_macaddr[6];
uint8_t mode;
} Esp32WifiState;
#define Esp32_Mode_Station 0
#define Esp32_Mode_SoftAP 1
void Esp32_WLAN_handle_frame(Esp32WifiState *s, struct mac80211_frame *frame);
void Esp32_WLAN_setup_ap(DeviceState *dev,Esp32WifiState *s);
void Esp32_WLAN_reset_ap(Esp32WifiState *s);
void Esp32_sendFrame(Esp32WifiState *s, struct mac80211_frame *frame,int length, int signal_strength);
void Esp32_WLAN_frame_delivered(Esp32WifiState *s);
REG32(WIFI_DMA_IN_STATUS, 0x84);
REG32(WIFI_DMA_INLINK, 0x88);
REG32(WIFI_DMA_INT_STATUS, 0xc48);
REG32(WIFI_DMA_INT_CLR, 0xc4c);
REG32(WIFI_STATUS, 0xcc8);
REG32(WIFI_DMA_OUTLINK, 0xd20);
REG32(WIFI_DMA_OUT_STATUS, 0xd24);
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "hw/hw.h"
#include "hw/sysbus.h"
#define TYPE_ESP32C3_ANA "misc.esp32c3.ana"
#define ESP32C3_ANA(obj) OBJECT_CHECK(Esp32C3AnaState, (obj), TYPE_ESP32C3_ANA)
typedef struct Esp32C3AnaState {
SysBusDevice parent_obj;
MemoryRegion iomem;
uint32_t mem[1024];
} Esp32C3AnaState;
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "hw/sysbus.h"
#include "hw/hw.h"
#include "hw/registerfields.h"
#define TYPE_ESP32C3_PWR_MANAGER "misc.esp32c3.pwrmng"
#define ESP32C3_PWR_MANAGER(obj) OBJECT_CHECK(Esp32c3PwrMngState, (obj), TYPE_ESP32C3_PWR_MANAGER)
typedef struct Esp32c3PwrMngState {
SysBusDevice parent_obj;
MemoryRegion iomem;
uint32_t mem[1024];
} Esp32c3PwrMngState;
+3
View File
@@ -42,6 +42,9 @@
#define DR_REG_APB_CTRL_BASE 0x60026000 /* Old name for SYSCON, to be removed */
#define DR_REG_TWAI_BASE 0x6002B000
#define DR_REG_I2S0_BASE 0x6002D000
#define DR_REG_WIFI_BASE 0x60033000
#define DR_REG_PHYA_BASE 0x60034000
#define DR_REG_PWR_MANAGER_BASE 0x60035000
#define DR_REG_APB_SARADC_BASE 0x60040000
#define DR_REG_USB_SERIAL_JTAG_BASE 0x60043000
#define DR_REG_AES_XTS_BASE 0x600CC000
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "hw/hw.h"
#include "hw/registerfields.h"
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "net/net.h"
#include "esp32_wifi.h"
#define TYPE_ESP32C3_WIFI TYPE_ESP32_WIFI
REG32(C3_WIFI_DMA_IN_STATUS, 0x84);
REG32(C3_WIFI_DMA_INLINK, 0x88);
REG32(C3_WIFI_DMA_INT_STATUS, 0xc3C);
REG32(C3_WIFI_DMA_INT_CLR, 0xc40);
REG32(C3_WIFI_STATUS, 0xcb0);
REG32(C3_WIFI_DMA_OUTLINK, 0xd08);
REG32(C3_WIFI_DMA_OUT_STATUS, 0xd14);
+7 -1
View File
@@ -136,6 +136,10 @@ def start(args):
(state / "wait.offset").write_text("0\n")
flash = state / "flash.bin"
build_flash(firmware, flash)
efuse = bytearray(1024)
efuse[0x18:0x1E] = bytes.fromhex("563412005452")
efuse[0x26] = 0x0C
(state / "efuse.bin").write_bytes(efuse)
command = [
str(require_env("XTEINK_QEMU")),
@@ -146,8 +150,10 @@ def start(args):
"-serial", f"file:{state / 'serial.log'}",
"-monitor", "none",
"-qmp", f"unix:{state / 'qmp.sock'},server=on,wait=off",
"-nic", "none",
"-nic", "user,model=esp32c3_wifi,mac=52:54:00:12:34:56,net=192.168.4.0/24",
"-drive", f"file={flash},if=mtd,format=raw",
"-drive", f"file={state / 'efuse.bin'},if=none,format=raw,id=efuse",
"-global", "driver=nvram.esp32c3.efuse,property=drive,value=efuse",
"-drive", f"file={sdcard},if=sd,format=raw",
]
qemu_log = (state / "qemu.log").open("ab")