3DS reverse engineering

Discussion of development of software for any "obsolete" computer or video game system.
profi200
Posts: 28
Joined: Fri May 10, 2019 4:48 am

Re: 3DS reverse engineering

Post by profi200 » Wed Jan 08, 2020 5:43 am

Regarding SHA:
I have tested DMA a good while ago and came to the conclusion it's double(!) as slow as copying the data with the CPU and that even doing only in FIFO DMA. I don't know why. I left the test code in: https://github.com/derrekr/fastboot3DS/ ... pto.c#L553

nocash
Posts: 1113
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Wed Jan 08, 2020 8:54 pm

Oh, I had misremembered that (I was thinking that it happened only on SHA_OUT readback, instead of SHA_IN).
Hmmm, there are various ways to DMA (via NDMA, XDMA, CDMA) and various ways to do CPU transfers...
I have tested ARM9 CPU and ARM9 NDMA, both just writing 64Kbytes of "filldata" to the SHA unit, without reading any source data from RAM:

Code: Select all

  SHA2xx  SHA1
  10000h  10000h  bytes transfer length...
  2213Ah  220E1h  clks when writing SHA blocks via ARM9 2x STMIA r0-r7
  112BFh  15781h  clks when writing SHA blocks via ARM9 NDMA fill mode
With that tests, NDMA is faster than CPU. Timings are measured in 67MHz units.
NDMA timings are about 1 cycle per byte for SHA256/SHA224, and about 1.25 cycles for SHA1.
Or more accurate: 1.07 clks and 1.34 clks, that would be 62Mbyte/s or 50Mbyte/s.

I don't know why CPU was faster for you. But here are some ideas...
- CPU could use data cache (if data is cached, or if PLD opcode was used, or if some kind of cache-read-ahead had occurred).
- CPU could read-ahead source data (before waiting for the FIFO full flag, at least if the code is programmed that way)
- NDMA might bug when reading from memory (unlike the NDMA-fill-mode that I had used)
- Without cache, main RAM may work faster if the source blocks are aligned to main RAM line size (I think it can then do burst reads)
- With cache it might be vice-versa (if the mis-alignment is causing cache-read-ahead)

For the NDMA, I have used 40h bytes as logical & physical block size. The FIFO full flag in SHA_CNT gets set after 40h bytes, too.
The SHA vs Source Data timings would have probably worked more smoothly if they had used a 80h-byte FIFO, with data request when FIFO is at least half-empty.

profi200
Posts: 28
Joined: Fri May 10, 2019 4:48 am

Re: 3DS reverse engineering

Post by profi200 » Thu Jan 09, 2020 9:52 am

I did the test again and this time i used a 32 bit timer (prescaler 1, cascade), a big buffer (256 KiB) and made sure the ARM9 is waiting for IRQs instead of polling. ARM9 memory --> SHA. This time the result is different:

CPU: 459633 timer cycles
NDMA: 344354 timer cycles

The code on the CPU side is generated by gcc:

Code: Select all

.text:08004DBC ; void __fastcall SHA_update(const u32 *data, u32 size)
.text:08004DBC SHA_update                              ; CODE XREF: loadVerifyFirm+398↓p
.text:08004DBC                                         ; sdmmc_dnand_init_0+1B8↓p ...
.text:08004DBC data = R0                               ; const u32 *
.text:08004DBC size = R1                               ; u32
.text:08004DBC                 CMP     size, #0x3F
.text:08004DC0                 STMFD   SP!, {R4-R7,LR}
.text:08004DC4                 MOV     R7, size
.text:08004DC8                 MOV     R5, data
.text:08004DCC                 BLS     loc_8004E44
.text:08004DD0                 SUB     R6, size, #0x40
.text:08004DD4                 BIC     R6, R6, #0x3F
.text:08004DD8                 ADD     R6, R6, #0x40
.text:08004DDC                 LDR     R4, =0x1000A000
.text:08004DE0                 ADD     R6, data, R6
.text:08004DE4
.text:08004DE4 loc_8004DE4                             ; CODE XREF: SHA_update+64↓j
.text:08004DE4 data = R5                               ; const u32 *
.text:08004DE4                 MOV     LR, data
.text:08004DE8                 LDR     R12, =0x1000A080
.text:08004DEC                 LDMIA   LR!, {R0-R3}
.text:08004DF0                 STMIA   R12!, {R0-R3}
.text:08004DF4                 LDMIA   LR!, {R0-R3}
.text:08004DF8                 STMIA   R12!, {R0-R3}
.text:08004DFC                 LDMIA   LR!, {R0-R3}
.text:08004E00                 STMIA   R12!, {R0-R3}
.text:08004E04                 LDMIA   LR, {R0-R3}
.text:08004E08                 STMIA   R12, {R0-R3}
.text:08004E0C                 ADD     data, data, #0x40
.text:08004E10
.text:08004E10 loc_8004E10                             ; CODE XREF: SHA_update+5C↓j
.text:08004E10                 LDR     R3, [R4]
.text:08004E14                 TST     R3, #1
.text:08004E18                 BNE     loc_8004E10
.text:08004E1C                 CMP     data, R6
.text:08004E20                 BNE     loc_8004DE4
.text:08004E24                 AND     R7, R7, #0x3F
.text:08004E28                 CMP     R7, #0
.text:08004E2C                 LDMEQFD SP!, {R4-R7,PC}
.text:08004E30
.text:08004E30 loc_8004E30                             ; CODE XREF: SHA_update+94↓j
.text:08004E30                 MOV     R2, R7
.text:08004E34                 MOV     R1, R6
.text:08004E38                 LDMFD   SP!, {R4-R7,LR}
.text:08004E3C                 LDR     R0, =0x1000A080
.text:08004E40                 B       iomemcpy
.text:08004E44 ; ---------------------------------------------------------------------------
.text:08004E44
.text:08004E44 loc_8004E44                             ; CODE XREF: SHA_update+10↑j
.text:08004E44 data = R0                               ; const u32 *
.text:08004E44 size = R1                               ; u32
.text:08004E44                 CMP     R7, #0
.text:08004E48                 MOV     R6, data
.text:08004E4C                 LDMEQFD SP!, {R4-R7,PC}
.text:08004E50                 B       loc_8004E30
.text:08004E50 ; End of function SHA_update
.text:08004E50
.text:08004E50 ; ---------------------------------------------------------------------------
.text:08004E54 off_8004E54     DCD 0x1000A000          ; DATA XREF: SHA_update+20↑r
.text:08004E58 dword_8004E58   DCD 0x1000A080          ; DATA XREF: SHA_update+2C↑r
.text:08004E58                                         ; SHA_update+80↑r
The code is not the best it could be but i think that is plenty fast.

nocash
Posts: 1113
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Thu Jan 09, 2020 11:46 pm

Time for Battery/Power related stuff...

First of, while messing with the battery pins, I've blown the fuse near the external supply connector, and melted the 4pin coils next to it. After removing/briding that components... the damn thing does still work... destroying the power supply would have been a good excuse to get rid of the half-broken console : /

---

Anyways, some other/older battery related problems are:

1) Some months ago I noticed that the battery does fully discharge after about 10 hours - even when the console is switched off (unless the charger is connected). In the discharged state, it won't even power-on for a brief moment (until/unless connecting the charger). Is that a known problem? I don't know if it might be a bug in my power-off function, somehow leaving the console in half powered state.

2) Some months later the console stopped working completely without charger connected, it powers down instantly when removing the charger, and won't power-on without charger. With charger, the orange charger LED never goes off, and the power LED is always red (when switched on). It behaves as if the battery is completely "empty". But despite of that, the battery does have 3.7 volts, so it seems to be quite well charged.

---

Measuring Amperes on the charger input, I see...
About 50mA when switched on.
About 17mA anytime else (when switched off, even when switched-off with battery removed).
I guess the 17mA might be because it is trying to charge the battery (or maybe Nintendo does always draw 17mA even if the battery is full?)
The 17mA don't seem to be related to my power-off function (they are drawn even after a "hard power-down" ie. after temporarily removing both charger+battery).

---

For the fuel gauge, I've searched for device 6Ch and fuel gauge... that looks like being a MAX17xxx chip... the Old3DS does have an 8pin chip marked "17040", so it's apparently a MAX17040.
The MCU in New3DS does also contain code for device 6Ch... but I haven't spotted a "17040" chip or anything similar on the New3DS mainboard, so I don't know if or where that chip does exist in New3DS (or maybe it is the 6pin chip... with marking "9D" or "06" or so).
The MCU code reads from MAX17040 registers 02h:03h (VCELL voltage as 12bit value) , 04h:05h (SOC StateOfCharge as 16bit value in percent/256), and 08h:09h (VERSION with undocumented value; returned in byte [03h,04h] of MCU command 7Fh).

---

And a general thing about DSi/New3DS batteries... I would love to know how to use the consoles without battery - but they refuse to work when attaching only the external supply without battery.
Both DSi and New3DS have 3pin batteries, BT+, BT-, and some unknown "middle pin", which migt be a resistor, thermistor, or 1-wire bus?

- On DSi, the middle pin is called "DET", and it seems to have no connection to BT- (and connects to PowerMan chip).
- On New3DS, there's no name/text layer, and it seems to have 0 ohm resistance to BT- (and connects wherever).

Hmmm, that looks as if the middle pins have different functions in DSi and New3DS.

For the thermistor theory:
The DSi seems to have a thermistor on the PCB (close to the battery, but NOT INSIDE of the battery... unless there are two different thermistors).
The datasheet for the New3DS charger chip BQ24072 suggests a thermistor on the TS pin (which, too, might be on the PCB... or in the battery).

That BQ24072 datasheet does also say that one could disable battery detection via TD pin (or SYSOFF pin in other BQ2407x chips). I haven't yet checked how far that pin could be rewired on the PCB, but it might require to change tiny wires underneath of the chip.
Other than that, one could probably fool it by replacing the battery with a large capacitor on BT+ and BT- (and whatever on the middle pin... if it's a digital 1-wire signal (?) then it might require something alike a CIC-clone).

Did anybody ever manage to power those consoles without battery?

lidnariq
Posts: 8902
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: 3DS reverse engineering

Post by lidnariq » Fri Jan 10, 2020 12:49 am

nocash wrote:
Thu Jan 09, 2020 11:46 pm
1) Some months ago I noticed that the battery does fully discharge after about 10 hours - even when the console is switched off (unless the charger is connected).
In isolation, it's hard to say whether this a mistake on your part or just a end-of-life battery ... but your other comments strongly imply this is an almost-dead battery. Not only does LiIon/LiPoly capacity decrease drastically at end of life, but its self-discharge rate also seems to increase.
In the discharged state, it won't even power-on for a brief moment (until/unless connecting the charger). Is that a known problem?
I've seen this behavior in a lot of other devices that use LiPoly cells.
But despite of that, the battery does have 3.7 volts, so it seems to be quite well charged.
A LiIon/LiPoly cell that's reading 3.7V doesn't have much power left in it.

The voltage read off a LiIon/LiPoly cell starts showing hysteresis as it wears down, where some increasing amount of voltage swing is unrelated to actual remaining capacity. (For example, removing it from the charger and it will immediately drop from 4.2V to 3.9V, then if it discharges to 3.7V and it's plugged back in it immediately starts reading 4.0V)
some unknown "middle pin", which migt be a resistor, thermistor, or 1-wire bus?
Thermistor is extremely likely. Most have a "room temperature" resistance somewhere around 10-50kΩ, and most often between battery- and the extra pin.
Did anybody ever manage to power those consoles without battery?
I only have a GBASP and a old DS, but they don't work without the battery. Not even putting in a capacitor in lieu works.

I have managed to power the GBASP using a bench power supply providing 4V via the battery terminals ... but it does only has two pins on its battery.

nocash
Posts: 1113
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Fri Jan 10, 2020 1:45 am

Just checked again... the New3DS Xl battery is Li-Ion 1750mAh 3.7V (not 4.2V)... and I am measuring 3.6V on the battery contacts (on the raw/removed battery, and same voltage also when charging, with console being either powered on or off)).
Does that sound charged, or did you mean that it should exceed 3.7V, despite of the battery sticker saying 3.7V?

In the DSi, I have a "normal" worn out battery, causing the console to switch off after 5 minutes. I think that is a normal wear-out effect.

But the New3DS does switch off after 0.000 seconds. I think that is a bit too rapid, even if the battery would be worn out (which I am not even sure about... not so long ago it did still last several hours (even when switched on)... and then the lifetime suddenly dropped from hours to microseconds. Maybe there's a damaged component on PCB, or the battery is heavily damaged (exceeding normal wear-out effects).

Yes, I have read about Thermistors in 10kOhm range, I am just not measuring anything remotely close to 10kOhm on the Nintendo batteries (and as said before, the DSi does have the thermistor with name "TH" on the button/battery PCB (above the battery)).

Some batteries are reportedly merely having a resistor on the 3rd pin (with different resistor values for different battery capacities). And some do reportedly have a 1-wire bus (though those might also have a built-in fuel gauge... which is apparently not the case here, as the MCU is accessing an I2C bus fuel gauge).
For the New3DS battery, I think the 3rd pin is simply shortcut to BT- inside of the battery (I measure 0 ohm between that battery pins, and the console pin has 0 volt when battery is attached, and 1.3V when removing the battery) (but then, my battery might be damaged).

I've meanwhile found a few more fuel gauge I2C register accesses in the MCU firmware, that makes it look as if the New3DS has something newer than MAX17040... either a newer MAXnnnn chip... or something compatible... like Richtek RT9428 (that has a few more registers, but the MCU uses even more than that).

Code: Select all

  index__________;MAX17040______________;Richtek RT9428___
  02h        R   ;VCELL, voltage        ;VBAT
  04h        R   ;SOC, StateOfCharge    ;SOC
  04h.byte   R   ;SOC.msb               ;SOC.msb
  06h        W   ;MODE                  ;CONTROL
  08h.byte   R   ;VERSION.msb?          ;DEVICE ID.msb
  08h        R   ;VERSION               ;DEVICE ID
  0Ah        -   ;-                     ;Status, dSOC
  0Ch        R/W ;RCOMP                 ;CONFIG
  0Eh        R/W ;???                   ;OCV
  3Eh        W   ;???                   ;???
  40h+N      W   ;???                   ;???
  80h+N      W   ;???                   ;???

profi200
Posts: 28
Joined: Fri May 10, 2019 4:48 am

Re: 3DS reverse engineering

Post by profi200 » Fri Jan 10, 2020 7:24 am

nocash wrote:
Thu Jan 09, 2020 11:46 pm
1) Some months ago I noticed that the battery does fully discharge after about 10 hours - even when the console is switched off (unless the charger is connected). In the discharged state, it won't even power-on for a brief moment (until/unless connecting the charger). Is that a known problem? I don't know if it might be a bug in my power-off function, somehow leaving the console in half powered state.
Definitely not normal. Fully powered off it can survive months without charge.

That reminds me that wifiboot fucks up the MCU watchdog timer. HOS doesn't reset it to normal. This is bad and here is why:
If you have to force shutdown the system it doesn't have enough time to finish writes/close file handles. This can and will lead to data corruption! There is a full blown OS running and you need to give it time to properly shutdown. You would not turn off your PC by cutting power while it's on either (unless it hung so badly nothing else works).
nocash wrote:
Thu Jan 09, 2020 11:46 pm
And a general thing about DSi/New3DS batteries... I would love to know how to use the consoles without battery - but they refuse to work when attaching only the external supply without battery.
Both DSi and New3DS have 3pin batteries, BT+, BT-, and some unknown "middle pin", which migt be a resistor, thermistor, or 1-wire bus?

[...]

Did anybody ever manage to power those consoles without battery?
You can test for a thermistor by wiring it up and carefully heating the battery with a hair dryer. Don't heat it up higher than about 50*C or you will get a fire. If they catch on fire they go really nuclear and you can only watch it burn (water will make it even worse).

You can try either powering it from the battery side or try to simulate a charging battery with a resistor. I don't know where i read that but someone had success with a resistor.

nocash wrote:
Fri Jan 10, 2020 1:45 am
Just checked again... the New3DS Xl battery is Li-Ion 1750mAh 3.7V (not 4.2V)... and I am measuring 3.6V on the battery contacts (on the raw/removed battery, and same voltage also when charging, with console being either powered on or off)).
Does that sound charged, or did you mean that it should exceed 3.7V, despite of the battery sticker saying 3.7V?
This is not the the maximum voltage. Every battery in existence is measured in nominal voltage. LiIon usually is in the range of 2.5-4.2V (LiPo has a higher discharge cutoff voltage if i recall correctly). Going below 3V will hurt cycle life a lot and will give you barely any more juice.
nocash wrote:
Thu Jan 09, 2020 11:46 pm
In the DSi, I have a "normal" worn out battery, causing the console to switch off after 5 minutes. I think that is a normal wear-out effect.
If they are that worn out you should get rid of them since there is a higher risk of fires with very worn out batteries. If any of them is swollen get rid of them immediately because they don't swell for no reason. Something is wrong with them and continued usage is risky.

lidnariq
Posts: 8902
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: 3DS reverse engineering

Post by lidnariq » Fri Jan 10, 2020 11:22 am

nocash wrote:
Fri Jan 10, 2020 1:45 am
Just checked again... the New3DS Xl battery is Li-Ion 1750mAh 3.7V (not 4.2V)... and I am measuring 3.6V on the battery contacts (on the raw/removed battery, and same voltage also when charging, with console being either powered on or off)).
Does that sound charged, or did you mean that it should exceed 3.7V, despite of the battery sticker saying 3.7V?
Very empty.

LiIon/LiPoly discharge curves look like this: https://i.stack.imgur.com/LV91V.gif
(where "C" is the proportion of current drawn relative to the battery's capacity, units of (1/Hr))

LiIon can safely go up to not more than 4.25V, and most of the useful battery charge on a new cell is in the range of 4V to about 3.7V.

(Non-rechargable lithium coin cells have an even flatter discharge curve)
But the New3DS does switch off after 0.000 seconds. I think that is a bit too rapid, even if the battery would be worn out (which I am not even sure about... not so long ago it did still last several hours (even when switched on)... and then the lifetime suddenly dropped from hours to microseconds. Maybe there's a damaged component on PCB, or the battery is heavily damaged (exceeding normal wear-out effects).
That sounds like the battery's protection circuitry has disconnected the cell from the contacts, and it's effectively a battery-shaped box now.

nocash
Posts: 1113
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Sat Jan 11, 2020 12:30 am

lidnariq wrote:
Fri Jan 10, 2020 11:22 am
Very empty. LiIon/LiPoly discharge curves look like this: https://i.stack.imgur.com/LV91V.gif
profi200 wrote:
Fri Jan 10, 2020 7:24 am
Definitely not normal. Fully powered off it can survive months without charge.
Thanks. Okay, if 3.6V is empty, and if it isn't caused by known software issues... I've now checked the fuse on the back side of the battery board... and that was blown... I've fixed that, and it does now power-on without charger... and it's now also actually charging with charger.
I guess I must have short-cut the battery contacts when messing with the PCB with charger still plugged in, and didn't notice the problem until some weeks/months later because it was still partially working (with charger, and maybe also without charger when the battery was still full).
profi200 wrote:
Fri Jan 10, 2020 7:24 am
That reminds me that wifiboot fucks up the MCU watchdog timer. HOS doesn't reset it to normal. This is bad and here is why:
If you have to force shutdown the system it doesn't have enough time to finish writes/close file handles. This can and will lead to data corruption! There is a full blown OS running and you need to give it time to properly shutdown. You would not turn off your PC by cutting power while it's on either (unless it hung so badly nothing else works).
The forced-power-off-delay in MCU[24h]? I don't know why they have called it watchdog on 3dbrew. But yeah, I have considered OS timings issues:

Code: Select all

  - Normal-power-off timings are TapButton(0.1s) + Wait until power-down has completed.
  - Forced-power-off timings are HoldButton(3s) + Wait(7s). With MCU[24h] allowing to change/remove the 7s delay.
If the user does hold the button for 3 seconds then I would consider that at as a "hung so badly nothing else works" case, and then the extra 7 second delay would be pointless... or could you think of scenarios where it is needed?

I think that it's quite essential to disable that delay (especially if you are developing code that does occassionally hang during testing).
But I could "restore" the setting in wifiboot before starting the uploaded file... the MCU[24h] setting seems to be battery-backed, that's making it difficult to restore the "old" setting (especially if a crash had occurred)... the only other way would be to restore the hardcoded default setting.
profi200 wrote:
Fri Jan 10, 2020 7:24 am
You can try either powering it from the battery side or try to simulate a charging battery with a resistor. I don't know where i read that but someone had success with a resistor.
But where? I guess a resistor between external supply+ and battery+ might work?
It might even work when shorting that pins with 0 ohms, but then the battery+ would have 4.6V (or even 5V or whatever is connected externally), I don't know if that could damage anything... probably it would work fine, assuming that the voltage regulators would still pass the correct voltages to the mainboard.

---

I think I have located the fuel gauge chip on the New3DS XL battery board (the tiny 8pin bga chip right of the select button; it's very tiny, a good bit smaller than many SMD resistors). There is also some tinier-than-tiny text on it. I've tried to identify some letters using a led-torch, a camera, and a magnifying glass while balancing the pcb on my knees... with that DIY microscope... I can see lots of dust and deep scratches on the gold contacts... and something like "7048" (?) in upper line of chip name.
If that's right then it might stand for MAX17048, but the datasheet doesn't fully match up with the MCU code (on the other hand, the MCU code seems to detect at least two different fuel gauge chip versions).

Anyways, all datasheets are clear about the version/percentage/voltage registers... which are forwarded to the following MCU registers:

Code: Select all

  0Bh     Fuel Gauge Battery Percentage, msb (percent, 0..64h)
  0Ch     Fuel Gauge Battery Percentage, lsb (percent/256, 0..FFh)
  0Dh     Fuel Gauge Battery Voltage (in 20mV units)
  7Fh     ArrayEntry[03h]: Fuel Gauge Version.msb
  7Fh     ArrayEntry[04h]: Fuel Gauge Version.lsb
New details are the battery "percentage/256" fraction, and the "20mV" unit for the battery voltage.

nocash
Posts: 1113
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Mon Jan 13, 2020 5:56 pm

The battery charging is still bad. It takes endless to reach 100%, still consumes 0.15A when switched off with battery at 100%, and tends to discharge overnight to 0% when switched off, without charger attached (I've tried to power-off from within wifiboot, and fastboot, and it's both 0.15A).
So, well, I guess the battery is dead... or maybe there's another bent pin in one of the ribbon cable connectors causing a shortcut. It's probably unfixable without buying new hardware components.
I could leave it as is, or maybe I'll try to get it powered without battery alltogether.

---

Looking at my MCU disassembly, I am afraid that I have just found a nasty problem with RL78 "short addresses" (eg. opcode 8Dh: MOV A,saddr):

Code: Select all

 currently, I have that disassembled as so:
    00h..FFh --> FE20h..FF1Fh  ;datasheet suggests that it works that way
 but, at closer look, it might rather work as so:
    00h..1Fh --> FF00h..FF1Fh  ;top bytes
    20h..FFh --> FE20h..FEFFh  ;bottom bytes
Or in other words, to disassemble opcode 8D 1F:

Code: Select all

    8D 1F  -->  mov a,[0FFE3Fh]   ;read ADC result from RAM, which seems to be wrong : /
    8D 1F  -->  mov a,[0FFF1Fh]   ;read ADC result from the A/D converter's SFR register
I guess the latter is right?

Post Reply