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: Select all
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 ;/
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: Select all
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)
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: Select all
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+ch+thread) D0Ch DBGINST1 Debug Instruction-1 Register (W) (byte) 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)
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:
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.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.
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...
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).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.
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).