Yes, that's the handshake, not WMI_SYNCHRONIZE. Oh, in current gbatek version... I still do have some outdated stuff where I was speculating that it might have been WMI_SYNCHRONIZE, I'll remove that sentence (maybe that was confusing you).
WMI_READY is sent after the last handshake message. And WMI_REG_DOMAIN is sent automatically a moment later. The timing should be more or less don't care, you could probably sent them immediately after each other (ie. ready in one 80h-byte mbox block, and domain appended in the next 80h-byte mbox block).
In no$gba, I am simply writing this bunch of crap to the mbox, that are the 6 handshake messages, and the 2 wmi messages, each one 80h bytes in size, and all sent at once at the begin of the handshake (and the DSi launcher seems to be happy with that, ie. it's reading the stuff after each handshake step, despite of everything being sent at once) (EDIT: not 100% sure if my code was really working like that, maybe I had somewhere inserted some extra trickery that prevents the launcher from seeing the newer mbox blocks too early):
Code:
db 0,2,10h,0, 8,0,1,0, 0ah,0,8,6, 16h,0,2,6, 70h dup (0) ;-reply to cmd_1 ;? ;?
db 0,2,12h,0, 8,0,3,0, 0,1,0,1, 2,6,0,0, 2,6, 6eh dup (0) ;-reply to cmd_8_2_1 ;100h CONTROL_SVC ;control
db 0,2,12h,0, 8,0,3,0, 1,1,0,2, 0,6,0,0, 2,6, 6eh dup (0) ;-reply to cmd_8_2_1_1_5 ;101h DATA_BE_SVC ;best effort
db 0,2,12h,0, 8,0,3,0, 2,1,0,3, 0,6,0,0, 2,6, 6eh dup (0) ;-reply to cmd_8_2_2_1_5 ;102h DATA_BK_SVC ;background
db 0,2,12h,0, 8,0,3,0, 3,1,0,4, 0,6,0,0, 2,6, 6eh dup (0) ;-reply to cmd_8_2_3_1_5 ;103h DATA_VI_SVC ;video
db 0,2,12h,0, 8,0,3,0, 4,1,0,5, 0,6,0,0, 2,6, 6eh dup (0) ;-reply to cmd_8_2_4_1_5 ;104h DATA_VO_SVC ;voice
db 1,2,16h,0, 8,0,1,10h ;\1st reply to cmd_2_4_3_1_5's irq ;WMI_READY_EVENT
@@mod_mac_address: ; ;00:23:xx:xx:xx:xx=MAC address
db 0,23h,xxh,xxh, xxh,xxh,2,0 ;
@@mod_firmware_version: ;
db 7bh,0,0,21h, 2,6, 6ah dup (0) ;/ ;2100007Bh = firmware version (for AR6002 on DSi)
db 1,2,0eh,0, 8,0,6,10h ;\2nd reply to cmd_2_4_3_1_5's irq ;WMI_REGDOMAIN_EVENT aka WMI_REG_DOMAIN_EVENT
@@mod_reg_domain: ; ;80000188h = reg domain (188h=japan (and also same value used for europe))
db 88h,1,0,80h ;
db 2,6, 6eh dup (0), 0dh,0,0,0 ;/
That values are as logged from hardware (and include some garbage bytes at the end of some 1-2 blocks, that
should be zerofilled instead of containing the garbage, eg. the 0dh at the end of the last message). However, most of it isn't garbage. The first 6 bytes in each block are the MBOX header, and the "2,6" is part of the MBOX Trailer (or what I've called Ack List in gbatek).
---
Last some days I've looked into the CDMA/XDMA controller specs. I have some rough idea how the DMA instructions are working...
The most simple case would using DMA_MOV to set up CCR and source/dest addresses, and the issue a series of DMA_LD / DMA_ST to load/store the data from source to dest. And slightly more complex code could use loops and syncing with data requests from peripherals.
What I haven't figured out are the "conditional" opcodes (those with the S or B suffix) that execute only if the "SINGLE" or "BURST" condition is true (and execute as NOP if it's false).
If the instruction does have a peripheral number specified (eg. "DMALDPS P2"), then it does supposedly get the condition from that peripheral.?
But "DMALDS" can be also conditional, but doesn't specify "P2" or the like. So where does the condition come from in that case? From the "memory addresss"? Or from the most recently used peripheral number?
And is that a thing at all on 3DS, or do all 3DS devices support only SINGLE or only BURST transfers anyways? Or even never use any conditional opcodes at all?
Btw. here's a summary of the DMA instructions
Code:
00h DMAEND ;-done
01h DMAKILL ;-
04h DMALD ;\
05h DMALDS ; load from SAR
07h DMALDB ;/
08h DMAST ;\
09h DMASTS ; store to DAR
0Bh DMASTB ;/
0Ch DMASTZ ;-store zero to DAR
12h DMARMB ;-read memory barrier
13h DMAWMB ;-write memory barrier
18h DMANOP ;-
20h,len-1 DMALP lpc0,len ;\loop start with loop counter
22h,len-1 DMALP lpc1,len ;/
25h,periph*8 DMALDPS periph ;\load peripheral
27h,periph*8 DMALDPB periph ;/
29h,periph*8 DMASTPS periph ;\store peripheral
2Bh,periph*8 DMASTPB periph ;/
2Ch,rel_addr DMALPEND ;-loop end for DMALPFE
30h,periph*8 DMAWFP periph,single ;\
31h,periph*8 DMAWFP periph,periph ; wait for peripheral
32h,periph*8 DMAWFP periph,burst ;/
34h,event*8 DMASEV event ;-send event
35h,periph*8 DMAFLUSHP periph ;-
36h,event*8+00h DMAWFE event ;\wait for event
36h,event*8+02h DMAWFE event,invalid ;/(optional cache invalidate)
38h,rel_addr DMALPEND lpc0 ;\
39h,rel_addr DMALPENDS lpc0 ; loop end for DMALP lpc0/1
3Bh,rel_addr DMALPENDB lpc0 ;
3Ch,rel_addr DMALPEND lpc1 ;
3Dh,rel_addr DMALPENDS lpc1 ;
3Fh,rel_addr DMALPENDB lpc1 ;/
54h,imm16 DMAADDH SAR,+imm16 ;\
56h,imm16 DMAADDH DAR,+imm16 ; add halfword
5Ch,imm16 DMAADDMH SAR,-imm16 ; (or negative halfword)
5Eh,imm16 DMAADDNH DAR,-imm16 ;/
A0h,channel,imm32 DMAGO channel,imm32 ;\jump/goto entrypoint
A2h,channel,imm32 DMAGO channel,imm32,ns ;/(ns=non-secure mode)
BCh,00h,imm32 DMAMOV SAR,imm32 ;\
BCh,01h,imm32 DMAMOV CCR,imm32 ; move to register
BCh,02h,imm32 DMAMOV DAR,imm32 ;/
imm8 DCB imm8 ;\manually defined 'code'
imm32 DCD imm32 ;/
- DMALPFE ;-set loop start (no opcode)
It looks relative easy to use. Even without a dedicated assembler, one could implement all instructions as macros, or simply enter them in data lines (best with using symbolic constants for the opcode names).
The slightly uncomfortable part is that one need to "patch" the code with the actual source/dest values in the DMA_MOV SAR/DAR instructions (and needing unaligned writes for that, although one could probably insert DMA_NOP's or even place DMA_LP loop start opcodes between the DMA_MOV SAR/DAR to have the imm32 values at well aligned addresses.
On the other hand, the method that Nintendo is using looks a bit overcomplicated (dynamically creating the whole code with STRB opcodes for emitting the DMA opcodes & parameters).
And, a summary of the DMA registers:
Code:
Corelink DMA Engines
XDMA cannot access the ARM9 bootrom at all.
1000C000h ARM9 XDMA Registers
10200000h ARM11 Old3DS CDMA Registers
10206000h ARM11 New3DS CDMA Registers
DMAC Control Registers
000h DSR DMA Manager Status Register (R)
004h DPC DMA Program Counter Register (R)
008h-01Ch - Reserved
020h INTEN Interrupt Enable Register (R/W)
024h INT_EVENT_RIS Event-Interrupt Raw Status Register (R)
028h INTMIS Interrupt Status Register (R)
02Ch INTCLR Interrupt Clear Register (W)
030h FSRD Fault Status DMA Manager Register (R)
034h FSRC Fault Status DMA Channel Register (R)
038h FTRD Fault Type DMA Manager Register (R)
03Ch - Reserved
040h+n*4 FTRn DMA channel n Fault type (R)
060h-0FCh - Reserved
DMAC Channel Thread Status Registers
100h+n*8 CSRn DMA channel n Channel status (R)
104h+n*8 CPCn DMA channel n Channel PC (R)
140h-3FCh - - - - - Reserved
DMAC AXI Status and Loop Counter Registers
400h+n*20h SARn DMA channel n Source address (R)
404h+n*20h DARn DMA channel n Destination address (R)
408h+n*20h CCRn DMA channel n Channel control (R)
40Ch+n*20h LC0_n DMA channel n Loop counter 0 (R)
410h+n*20h LC1_n DMA channel n Loop counter 1 (R)
414h+n*20h Reserved
418h+n*20h Reserved
41Ch+n*20h Reserved
500h-CFCh - Reserved
DMAC Debug Registers (debugging is meant to be synonym for "start execution")
D00h DBGSTATUS Debug Status Register (R)
D04h DBGCMD Debug Command Register (W) (start INST code)
D08h DBGINST0 Debug Instruction-0 Register (W) (code[2]+ch+thread)
D0Ch DBGINST1 Debug Instruction-1 Register (W) (byte[4])
D10h-DFCh - Reserved
DMAC Configuration Registers
E00h CR0 Configuration Register 0 (R)
E04h CR1 Configuration Register 1 (R)
E08h CR2 Configuration Register 2 (R)
E0Ch CR3 Configuration Register 3 (R)
E10h CR4 Configuration Register 4 (R)
E14h CRD DMA Configuration Register (R)
E18h-E7Ch - Reserved
E80h WD Watchdog Register (R/W) (rev1 only)
E84h-FDCh - Reserved
Peripheral and component identification register summary
FE0h-FECh periph_id_n Peripheral Identification Registers (R)
FF0h-FFCh pcell_id_n Component Identification Registers 0-3 (R)
The baffling thing is that there seems to be no officially mentioned way to start transfers with those registers. Nintendo is doing that by writing a DMA_GO opcode to the "Debug Registers" (which does then jump/goto to the actual DMA code entrypoint)... and it looks as if that is actually the only working way to start transfers?
I am having problems to wrap my head around why they have called the registers "Debug Registers" instead of "Transfer Start Registers" or whatever. My best theory would be some translation error or misconception like this:
Bingo Blink, ARM developer wrote:
When I was in my early teens, I had started software by clicking on main.exe, but since I became a programmer, I got familar with typing debug main.exe at the command prompt, because that's how the devrs are doing it. I think debug means low level execution. The term is dating back to steam ships, like, when they were saying that a ship had debugged from the port. Or something like that.
What was weird is, when I designed the DMA controller for ARM, the senior devrs nodded it off, and congratulated me on even having implemented a debug feature - as if they had thought that people of my age could only start DMA transfers by mouse clicking instead of by debugging! Honestly, some of the seniors are a bit senile and out of touch with the low level things.
Hmmm, or, well, those "Debug Registers"
could be probably used to implement single-step execution for debugging purposes. But that would be a rare corner case, not their
normal use.
---
Well, anyways, reading the XDMA/CDMA config & id registers on 3DS... Two new findings are:
- ARM9 XDMA has
four channels (not two).
- New3DS CDMA uses revision
r1p1 (not r1p2) (though that should be "functionally same").
Oh, and that New3DS CDMA registers can be accessed only in New3DS mode (enabled with the same register that does also control the 3DS CPU clock and extra FCRAM). If enabled, the New3DS CDMA registers can be read (without causing data abort). And reading the Old3DS CDAM regs does still work, too. I don't know if there's further stuff needed to actually activate the New3DS CDMA registers (and to deactivate the Old3DS CDMA regs).
Some more details from those registers:
- XDMA: 4 channels, 8 peripherals, 12 events
- Old3DS CDMA: 8 channels, 18 peripherals, 16 events
- New3DS CDMA: 8 channels, 32 peripherals, 32 events
That doesn't neccessarily mean that all peripheral IDs are actually used in the 3DS. But for XDMA, it should be safe to say that it could only use id 0..7 (and leaves 8..31 unused).
Is there a way to poll all 32bit peripheral data request flags from some status register? That would be nice for testing if/which hardware is triggering them.
Only other way would be to program one channel to watch for one peripheral. The bad thing is that there are less channels than peripherals.
---
PS. With the wifi emulation. Are you just trying to get through the initialization, or are you planning to go farther, and support actual network/internet connections?
Emulating an access point is (hopefully) not too difficult. The more complicated part would be to connect the emulated access point to the real outside world. Stephen (from dswifi) mentioned...
Stephen Stair wrote:
there are some libraries that can do the hard work for you, if you get past the dislike of HLL code :) (e.g. winpcap)
To do it yourself basically means to build a NDIS lightweight filter driver and install it into the network stack, and communicate through that. Pretty complicated stuff.
If that driver thing would work... then everything else should work by itself (ie. the router handing out DHCP addresses, and taking core of routing packets to local network & internet).
I have zero experience with making windows drivers.
And, I had looked at some specs... it seems that there are a handful of different NDIS versions. I don't know if there is any backwards compatibility for old driver versions still working on newer OS versions. I am afraid that not, and that one would need to write a different driver for OS version (and add more drivers when new OS versions come out).