punesemu / puNES

Qt-based Nintendo Entertaiment System emulator and NSF/NSF2/NSFe Music Player (Linux, FreeBSD, OpenBSD and Windows)
GNU General Public License v2.0
657 stars 42 forks source link

Copy protection is triggered on Kosodate Gokko (FDS) #396

Closed TakuikaNinja closed 6 months ago

TakuikaNinja commented 6 months ago

I've been enjoying the new FDS implementation so far. It's definitely cool to see copy-protected disk utilities like Quick Hunter and Jingorou work as intended here, with the ability to save edited disks. However, I've found that Kosodate Gokko (a disk copier from I2) seems to have its copy protection triggered.

Correct behaviour: The logo should flash on the screen after scrolling to indicate that a new disk should be inserted for copying. (Video for reference: https://youtu.be/ckas6sRTavM&t=183) Current, incorrect behaviour: The copy protection is triggered and a hidden mini-game with music plays. (the proper way to trigger this mini-game is to hold the A button while booting the disk, or to boot a badly copied disk)

It seems that Kosodate Gokko manually loads the main program data from after the final "real" file of the disk, into the $0200~$05FF region of system memory (this needs to persist between disk swaps). The main program data does not use real file blocks at all. The loader program keeps loading bytes from disk (only using disk IRQs) until it finds a $12 byte, then loads each byte of the main program. After that, it checks for the starting byte of $20 at $0200 and the ending byte of $23 at $0500 before running the main program. Honestly, it's quite a clever tactic since disk copiers wouldn't expect this data while copying standard file blocks.

I just find it funny how these copy protection measures have unintentionally become anti-emulator measures. The year is 2024 and emulators still can't run FDS programs accurately.

punesemu commented 6 months ago

Hi @TakuikaNinja, thanks for the report, can you kindly send me the FDS of Kosodate Gokko? I don't know when I'll be able to take a look at it, in this period I don't have time to dedicate myself to the emulator but I will do it as soon as I can

TakuikaNinja commented 6 months ago

I'd rather not send the FDS file, even if it's technically abandonware. It shouldn't be too hard to find it in a nointro dataset anyway.

negativeExponent commented 6 months ago

question: is the available image for this game even playable by itself to begin with? or does it need some other data/disks like the video shows.

TakuikaNinja commented 6 months ago

Based on the rudimentary analysis I did, the image does contain everything required to load/run the main program (aside from the disk to copy from and the blank disk to copy to, of course). It's just that it bypasses the normal BIOS disk I/O routines and directly uses the IRQs generated by the disk drive to transfer each byte. The main program uses the same method for its disk transfers, so getting this right is essential for getting it to copy disks correctly.

TakuikaNinja commented 6 months ago

Admittedly, this protection is actually simpler than Jingorou (which finds/loads a block type of 0 from within a mess of data). The main program code in Kosodate Gokko is prefixed with a $12 byte in the image and is sandwiched by mostly blank padding.

negativeExponent commented 6 months ago

"disk to copy from" <- what is this disk? and is the data in this particular image we are talking about? coz the game data for this file is just 65500, or one side. so it this just the loader or sort and does not contain actual game data?

TakuikaNinja commented 6 months ago

"disk to copy from" <- what is this disk? and is the data in this particular image we are talking about? coz the game data for this file is just 65500, or one side. so it this just the loader or sort and does not contain actual game data?

It's an arbitrary disk. Have you forgotten what a disk copier does...? You load up the copier (e.g. Kosodate Gokko), swap to a different disk to copy from, then swap to a blank disk to copy the disk to. This was one of many backup utilities from the FDS' commercial lifespan, which ended up being riddled with casual and commercial piracy. As I've said, the image for Kosodate Gokko contains the copier code we need. It's just loaded in an unusual way which emulators haven't emulated properly. Is that clearer now?

punesemu commented 6 months ago

I've already fixed Kosodate Gokko booting properly (a stupid bug) and managed to successfully copy the Volleyball disk to a clean fds. I'm checking out another thing I discovered during the debugging session.

punesemu commented 6 months ago

One thing I noticed is that it copies a maximum of three files, if the fds is made up of more than 3 files from the fourth onwards they will not be copied.

TakuikaNinja commented 6 months ago

I think the intention might have been to make the user swap disks back to copy all of the data? I've been disassembling the code myself and found that it does have a limit of $2A for the number of loaded file headers. 3 files is well below that, so maybe it's checking the buffer size and prompts for swaps accordingly? I'll see if I can find the manual for it.

punesemu commented 6 months ago

Yes, I really think that the limit is not the number of files but the size of the buffer. In the video I seem to see that at the end of reading the source disk and at the end of the destination disk there is a flash of the screen which does not happen in the emulator. Reading and copying happen correctly but not that flash.

TakuikaNinja commented 6 months ago

The flashing seems to be done by toggling the grayscale mode (bit 0) and emphasis (bits 7-5) in PPUMASK while rendering is disabled. It isn't tied to vblank.

punesemu commented 6 months ago

Fixed with ebc8f54, thx for the info.

punesemu commented 6 months ago

One last thing remains, in the video, when the disk to be copied is inserted, the drive motor turns off when the screen starts flashing while in the emulator the head performs another scan of the disk (without carrying out any actual reading) before stop. I tried to understand why but I couldn't. I simulated the compartment seen in the video by setting a Disk IRQ when reaching the end of head but I found no mention of such a thing in any documentation. In addition to the classic conditions that lead to the engine stopping, I found no other reasons to stop it at that moment.

TakuikaNinja commented 6 months ago

I think it has to do with the routine used to wait for the disk to be ejected. Here's the disassembled section:

; stop disk drive motor and wait until the disk is ejected
; the greyscale mode is toggled to indicate this
WaitForEject:
028F   AD 32 40   L028F     LDA DRIVESTATUS
0292   29 02                AND #$02 ; check disk ready flag
0294   F0 05                BEQ L029B ; branch if ready
0296   A9 2E                LDA #$2E ; stop motor, reset transfer timing
0298   8D 25 40             STA FDSCTRL
029B   A2 0A      L029B     LDX #$0A ; init counter
029D   A0 78      L029D     LDY #$78
029F   20 39 02             JSR Delay ; wait for some time
02A2   E6 FB                INC $FB ; this toggles the grayscale bit
02A4   A5 FB                LDA $FB
02A6   29 E1                AND #$E1 ; disable rendering but keep emphasis/greyscale
02A8   8D 01 20             STA PPUMASK
02AB   AD 32 40             LDA DRIVESTATUS
02AE   4A                   LSR A ; check disk inserted
02AF   90 DE                BCC WaitForEject ; branch to loop if inserted
02B1   CA                   DEX
02B2   D0 E9                BNE L029D ; loop until counter reaches 0
02B4   60                   RTS

The motor is only stopped when the disk is "not ready", which I believe corresponds to the drive head moving from the end of the disk back to the start. The video actually shows the screen flashing before the motor is stopped once it finishes writing to the blank disk.

I think we're done here.

punesemu commented 6 months ago

Thank you very much for the piece of code, it is extremely useful to me. I would like to ask you, if it were possible, to see the routine that takes care of reading the source disk up to WaitForEject, it could help me a lot. If you can't it doesn't matter, I still thank you for the feedback, you helped me improve the quality of the emulation.

TakuikaNinja commented 6 months ago

I'll attach my WIP disassembly of the copier program. Hope that helps! copier.asm.zip

punesemu commented 6 months ago

:pray: Many thanks, it will help me carry out a complete check.

punesemu commented 6 months ago

Ok, thanks to your copier.asm I found and fixed (5448b15) the problems concerning the disk change and which did not allow the correct copy of the FDS which required multiple changes between the source disk and destination disk. I tried multiple FDSs and always got a working copy of the source disk. Thank you so much.

punesemu commented 6 months ago

After this f540b5b I can considered closed this issue.