Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix DI interrupt mask ioctl names #8599

Merged
merged 2 commits into from Feb 2, 2020

Conversation

Pokechu22
Copy link
Contributor

This is a correction to some changes in #8394. In it, I added DVDLowUnmaskCoverInterrupt = 0x85 and DVDLowEnableCoverInterrupt = 0x89 (marking 0x89 as an unconfirmed name). After more investigation, I've decided that 0x85 is actually DVDLowMaskCoverInterrupt, while 0x89 is DVDLowUnmaskCoverInterrupt and the previously-unimplemented (as the actual implementation does nothing) 0x87 is DVDLowUnmaskStatusInterrupts. Note that all of those commands are, as far as I can tell, dummied out on the PPC side to always return 1. As such, I've also made use of those commands be reported as a game quirk.


To explain how I made this mistake, first note that most of my research was based on symbols for the US version of Kirby's Dream Collection in donut.MAP. (Kirby's Return to Dream Land has a similar file named iuk.MAP)

This file starts of with a bunch of useless-looking information about duplicate code:
Link map of __start
--> duplicated code: symbol __dt__Q23std13bad_exceptionFv is duplicated by __dt__Q23std9exceptionFv, size = 64 

--> the function __dt__Q23std13bad_exceptionFv will be replaced by a branch to __dt__Q23std9exceptionFv

--> duplicated code: symbol round_decimal is duplicated by round_decimal, size = 296

--> duplicated code: symbol __dt__Q43std3tr16detail57shared_ptr_deleter<c,Q33std6detail20default_delete<A0_c>>Fv is duplicated by __dt__Q23std9exceptionFv, size = 64

--> the function __dt__Q43std3tr16detail57shared_ptr_deleter<c,Q33std6detail20default_delete<A0_c>>Fv will be replaced by a branch to __dt__Q23std9exceptionFv
...

Actual symbols only begin on line 43317:
.init section layout
  Starting        Virtual  File
  address  Size   address  offset
  ---------------------------------
  00000000 000380 80004000 000001e0  1 .init 	Runtime.PPCEABI.H.a __mem.o
  00000000 00029c 80004000 000001e0  4 memcpy 	Runtime.PPCEABI.H.a __mem.o
  0000029c 0000b4 8000429c 0000047c  4 __fill_mem 	Runtime.PPCEABI.H.a __mem.o
  00000350 000030 80004350 00000530  4 memset 	Runtime.PPCEABI.H.a __mem.o
  00000380 001f34 80004380 00000560  1 .init 	TRK_Hollywood_Revolution.a D:\Data\wiiProj\metrotrk\metrotrk\__exception.o
  00000380 000000 80004380 00000560    gTRKInterruptVectorTable (entry of .init) 	TRK_Hollywood_Revolution.a D:\Data\wiiProj\metrotrk\metrotrk\__exception.o
  000022b4 000000 800062b4 00002494    gTRKInterruptVectorTableEnd (entry of .init) 	TRK_Hollywood_Revolution.a D:\Data\wiiProj\metrotrk\metrotrk\__exception.o
  000022b4 00000c 800062c0 000024a0 16 *fill*
...
... and so I only looked at the info pertaining to dvd_broadway.o, on lines 46010-46066.
  000397dc 000004 800401e0 0003c3c0 16 *fill*
  000397e0 002678 800401e0 0003c3c0  1 .text 	dvd.a dvd_broadway.o
  UNUSED   000074 ........ ........    initDvdContexts dvd.a dvd_broadway.o
  000397e0 0000b8 800401e0 0003c3c0 16 doTransactionCallback 	dvd.a dvd_broadway.o
  UNUSED   0000a8 ........ ........    doCoverCallback dvd.a dvd_broadway.o
  000398a0 0000bc 800402a0 0003c480 16 doPrepareCoverRegisterCallback 	dvd.a dvd_broadway.o
  00039960 000050 80040360 0003c540 16 DVDLowFinalize 	dvd.a dvd_broadway.o
  000399b0 000264 800403b0 0003c590 16 DVDLowInit 	dvd.a dvd_broadway.o
  00039c20 00018c 80040620 0003c800 16 DVDLowReadDiskID 	dvd.a dvd_broadway.o
  00039db0 00026c 800407b0 0003c990 16 DVDLowOpenPartition 	dvd.a dvd_broadway.o
  UNUSED   00028c ........ ........    DVDLowOpenPartitionWithTmdAndTicket dvd.a dvd_broadway.o
  0003a020 000264 80040a20 0003cc00 16 DVDLowOpenPartitionWithTmdAndTicketView 	dvd.a dvd_broadway.o
  0003a290 000210 80040c90 0003ce70 16 DVDLowGetNoDiscBufferSizes 	dvd.a dvd_broadway.o
  0003a4a0 000298 80040ea0 0003d080 16 DVDLowGetNoDiscOpenPartitionParams 	dvd.a dvd_broadway.o
  UNUSED   00023c ........ ........    DVDLowNoDiscOpenPartition dvd.a dvd_broadway.o
  0003a740 000168 80041140 0003d320 16 DVDLowClosePartition 	dvd.a dvd_broadway.o
  0003a8b0 000198 800412b0 0003d490 16 DVDLowUnencryptedRead 	dvd.a dvd_broadway.o
  0003aa50 000198 80041450 0003d630 16 DVDLowStopMotor 	dvd.a dvd_broadway.o
  UNUSED   000168 ........ ........    DVDLowWaitForCoverClose dvd.a dvd_broadway.o
  0003abf0 00016c 800415f0 0003d7d0 16 DVDLowInquiry 	dvd.a dvd_broadway.o
  0003ad60 000168 80041760 0003d940 16 DVDLowRequestError 	dvd.a dvd_broadway.o
  0003aed0 00000c 800418d0 0003dab0 16 DVDLowSetSpinupFlag 	dvd.a dvd_broadway.o
  UNUSED   0000bc ........ ........    DVDLowNotifyReset dvd.a dvd_broadway.o
  0003aee0 00017c 800418e0 0003dac0 16 DVDLowReset 	dvd.a dvd_broadway.o
  0003b060 000198 80041a60 0003dc40 16 DVDLowAudioBufferConfig 	dvd.a dvd_broadway.o
  UNUSED   000034 ........ ........    DVDLowBreak dvd.a dvd_broadway.o
  UNUSED   000048 ........ ........    DVDLowClearCallback dvd.a dvd_broadway.o
  UNUSED   0000cc ........ ........    DVDLowGetCoverStatus dvd.a dvd_broadway.o
  UNUSED   000214 ........ ........    DVDLowReadDvd dvd.a dvd_broadway.o
  UNUSED   0001ac ........ ........    DVDLowReadDvdConfig dvd.a dvd_broadway.o
  UNUSED   000184 ........ ........    DVDLowReadDvdCopyright dvd.a dvd_broadway.o
  UNUSED   000180 ........ ........    DVDLowReadDvdPhysical dvd.a dvd_broadway.o
  UNUSED   000180 ........ ........    DVDLowReadDvdDiscKey dvd.a dvd_broadway.o
  0003b200 000198 80041c00 0003dde0 16 DVDLowReportKey 	dvd.a dvd_broadway.o
  UNUSED   0001c0 ........ ........    DVDLowOffset dvd.a dvd_broadway.o
  UNUSED   000168 ........ ........    DVDLowStopLaser dvd.a dvd_broadway.o
  UNUSED   00016c ........ ........    DVDLowReadDiskBca dvd.a dvd_broadway.o
  UNUSED   000194 ........ ........    DVDLowSerMeasControl dvd.a dvd_broadway.o
  UNUSED   000168 ........ ........    DVDLowRequestDiscStatus dvd.a dvd_broadway.o
  UNUSED   000168 ........ ........    DVDLowRequestRetryNumber dvd.a dvd_broadway.o
  0003b3a0 000184 80041da0 0003df80 16 DVDLowSetMaximumRotation 	dvd.a dvd_broadway.o
  0003b530 0001b0 80041f30 0003e110 16 DVDLowRead 	dvd.a dvd_broadway.o
  0003b6e0 000180 800420e0 0003e2c0 16 DVDLowSeek 	dvd.a dvd_broadway.o
  UNUSED   0000c8 ........ ........    DVDLowGetCoverReg dvd.a dvd_broadway.o
  0003b860 000010 80042260 0003e440 16 DVDLowGetCoverRegister 	dvd.a dvd_broadway.o
  0003b870 00000c 80042270 0003e450 16 DVDLowGetStatusRegister 	dvd.a dvd_broadway.o
  0003b880 00000c 80042280 0003e460 16 DVDLowGetControlRegister 	dvd.a dvd_broadway.o
  0003b890 00016c 80042290 0003e470 16 DVDLowPrepareCoverRegister 	dvd.a dvd_broadway.o
  0003ba00 00016c 80042400 0003e5e0 16 DVDLowPrepareStatusRegister 	dvd.a dvd_broadway.o
  0003bb70 00016c 80042570 0003e750 16 DVDLowPrepareControlRegister 	dvd.a dvd_broadway.o
  UNUSED   000008 ........ ........    DVDLowGetLength dvd.a dvd_broadway.o
  0003bce0 00000c 800426e0 0003e8c0 16 DVDLowGetImmBufferReg 	dvd.a dvd_broadway.o
  UNUSED   000008 ........ ........    DVDLowUnmaskCoverInterrupt dvd.a dvd_broadway.o
  0003bcf0 000168 800426f0 0003e8d0 16 DVDLowClearCoverInterrupt 	dvd.a dvd_broadway.o
  UNUSED   00000c ........ ........    DVDLowGetLastEticketError dvd.a dvd_broadway.o
  UNUSED   000180 ........ ........    DVDLowEnableDvdVideo dvd.a dvd_broadway.o
  0003be58 000008 80042860 0003ea40 16 *fill*

DVDLowMaskCoverInterrupt and DVDLowUnmaskStatusInterrupts are nowhere to be seen in there. Since I had only seen DVDLowUnmaskCoverInterrupt, I had one name to use, and I decided that 0x85 probably was it since I assumed "unmask" meant "disable" and 0x85 cleared bit 1 of DICVR, which disables the interrupt. That assumption was incorrect, and inconsistent with the way that YAGCD described that bit: "CVRINTMASK - Cover Interrupt Mask. 0: masked, 1: enabled".

It turns out those functions were actually listed them earlier on, on lines 77-79...
--> duplicated code: symbol DVDLowUnmaskStatusInterrupts is duplicated by __DVDStopMotorAsync, size = 8 

--> duplicated code: symbol DVDLowMaskCoverInterrupt is duplicated by __DVDStopMotorAsync, size = 8

... and then again on lines 19992-19997.
Code folded in file: dvd_broadway.o 
--> DVDLowUnmaskStatusInterrupts is duplicated by CanCancel__Q34nw4r2ut13DvdFileStreamCFv, size = 8 

--> DVDLowMaskCoverInterrupt is duplicated by CanCancel__Q34nw4r2ut13DvdFileStreamCFv, size = 8

--> __DVDLowTestAlarm is duplicated by __wpadNoAlloc, size = 8

The fact that those functions were replaced implies that they were used somewhere. But I didn't realize that until much later. I only noticed it when looking at a symbol list for Tony Hawk's Downhill Jam, more on that later.

The way I concluded that I had the names swapped was by looking at the use of those functions on another game with symbols: both DVDLowUnmaskStatusInterrupts and DVDLowMaskCoverInterrupt are referenced by DVDInit.

Here's DVDInit from launcher.elf in the PAL version of Red Steel (Wii), chosen because it's a launch title
void DVDInit(void)
{
  if (DVDInitialized == 0) {
    OSRegisterVersion(__DVDVersion); // << RVL_SDK - DVD \trelease build: Oct 13 2006 12:34:21 (0x4200_60422) >>
    DVDInitialized = 1;
    DVDLowInit();
    __DVDFSInit();
    __DVDClearWaitingQueue();
    MotorState = 0;
    bootInfo = -0x80000000;
    IDShouldBe = 0x80000000;
    OSInitThreadQueue(&__DVDThreadQueue);
    DVDLowUnmaskStatusInterrupts();
    DVDLowMaskCoverInterrupt();
    if ((*(int *)(bootInfo + 0x20) != -0x1adf83de) && (*(int *)(bootInfo + 0x20) != 0xd15ea5e)) {
      FirstTimeInBootrom = 1;
    }
    memset(__ErrorInfo,0,0x80);
    memcpy(__ErrorInfo,(void *)0x80000000,4);
    __ErrorInfo[4] = DAT_80000006;
    __ErrorInfo[5] = DAT_80000007;
    __DVDLayoutFormat = 0;
    DVDSetAutoFatalMessaging(1);
  }
  return;
}
... and here's DVDInit from Scooby Doo Mystery Mayhem (GC)
void DVDInit(void)
{
  if (DVDInitialized == 0) {
    OSRegisterVersion(__DVDVersion); // << Dolphin SDK - DVD\trelease build: Oct 29 2002 09:56:49 (0x2301) >>
    DVDInitialized = 1;
    __DVDFSInit();
    __DVDClearWaitingQueue();
    __DVDInitWA();
    bootInfo = -0x80000000;
    IDShouldBe = 0x80000000;
    __OSSetInterruptHandler(0x15,__DVDInterruptHandler);
    __OSUnmaskInterrupts(0x400);
    OSInitThreadQueue(&__DVDThreadQueue);
    write_volatile_4(DISR,0x2a);
    write_volatile_4(DICVR,0);
    if (*(int *)(bootInfo + 0x20) == -0x1adf83de) {
      OSReport("load fst\n");
      __fstLoad();
    }
    else {
      if (*(int *)(bootInfo + 0x20) != 0xd15ea5e) {
        FirstTimeInBootrom = 1;
      }
    }
  }
  return;
}

I think these make it pretty obvious that the implementation of DVDLowMaskCoverInterrupt once matched DICVR = 0 (which is the same as DICVR = DICVR & ~4 & ~2 assuming bit 0 ignores writes), which is what ioctl 0x85 does. That means that DVDLowMaskCoverInterrupt DVDLowUnmaskCoverInterrupt probably would have the same as ioctl 0x89, which does DICVR = (DICVR & ~4) | 2. DVDLowUnmaskStatusInterrupts being 0x87 is a pure guess as the IOS implementation does nothing (always returning success), but it feels right.

It's worth noting that DVDLowClearCoverInterrupt is called in a few places other than DVDInit, even though it is dummied out to always return 1: it's used in a few error states, and by BS2.


The reason why I've added a quirk is that evidence indicates that at some point, the functions were not dummied out on the PCC side. This is based on the previously mentioned symbols for Tony Hawk's Downhill Jam, though, annoyingly, the symbols are for a debug version of the game that does not actually exist on the disc, or at least the PAL version of it.

Here are the relevant symbols (reordered, as the file was originally sorted by size and they were scattered all over the place).
 VARIABLES VARIABLES VARIABLES 
 ------------------------------
 LINE  ADDR         SIZE                                FILE - VAR NAME
 27259 80771880        4                            dvdlow.o - StopAtNextInt
 27260 80771884        4                            dvdlow.o - ResetCoverCallback
 27261 80771888        4                            dvdlow.o - ResetOccurred
 27262 8077188c        4                            dvdlow.o - WaitingCoverClose
 27263 80771890        4                            dvdlow.o - Breaking
 27264 80771894        4                            dvdlow.o - Forced
 27265 80771898        8                            dvdlow.o - ForcedTimeout
 27266 807718a0        4                            dvdlow.o - EventStampCounter
 27267 807718a4        4                            dvdlow.o - Wrapped
 27268 807718a8        8                            dvdlow.o - LastResetEnd
 27269 807718b0        4                            dvdlow.o - Callback
...
FUNCTIONS FUNCTIONS FUNCTIONS 
 ----------------------------------
 LINE  ADDR         SIZE                                FILE  NAME
...
 16453 803aa1a4      708                            dvdlow.o  __DVDInterruptHandler
 16454 803aa468      112                            dvdlow.o  AlarmHandlerForTimeout
 16455 803aa4d8        8                            dvdlow.o  DVDLowInit
 16456 803aa4e0      388                            dvdlow.o  DVDLowRead
 16457 803aa664      368                            dvdlow.o  DVDLowSeek
 16458 803aa7d4       40                            dvdlow.o  DVDLowWaitForCoverClose
 16459 803aa7fc      392                            dvdlow.o  DVDLowReadDiskID
 16460 803aa984      400                            dvdlow.o  DVDLowStopMotor
 16461 803aab14      344                            dvdlow.o  DVDLowRequestError
 16462 803aac6c      372                            dvdlow.o  DVDLowInquiry
 16465 803aade0      388                            dvdlow.o  DVDLowAudioBufferConfig
 16479 803aaf64       48                            dvdlow.o  DVDLowSetSpinupFlag
 16480 803aaf94      180                            dvdlow.o  DVDLowReset
 16481 803ab048       52                            dvdlow.o  DVDLowNotifyReset
 16483 803ab07c      200                            dvdlow.o  DVDLowBreak
 16484 803ab144       28                            dvdlow.o  DVDLowClearCallback
 16486 803ab160       12                            dvdlow.o  DVDLowGetCoverReg
 16487 803ab16c       12                            dvdlow.o  DVDLowGetLength
 16488 803ab178       12                            dvdlow.o  DVDLowGetImmBufferReg
 16489 803ab184       20                            dvdlow.o  DVDLowUnmaskStatusInterrupts
 16490 803ab198       20                            dvdlow.o  DVDLowMaskCoverInterrupt
 16492 803ab1ac       20                            dvdlow.o  DVDLowClearCoverInterrupt
 16493 803ab1c0       48                            dvdlow.o  __DVDLowTestAlarm

Note that the size of DVDLowMaskCoverInterrupt and DVDLowUnmaskStatusInterrupts is 20, same as DVDLowClearCoverInterrupt. I'm not completely sure this explains everything, since I do not see any references to IOS in the full symbol list (so perhaps at that point in development, Wii games directly interacted with DI?).

0x85 is actually DVDLowMaskCoverInterrupt, while 0x89 is DVDLowUnmaskCoverInterrupt.  I'm also fairly sure that 0x87 is DVDLowUnmaskStatusInterrupts.
"uses-DVDLowRequestRetryNumber",
"uses-DVDLowSerMeasControl",
"uses-different-partition-command",
"uses-di-interrupt-command"};
Copy link
Member

@lioncash lioncash Feb 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest placing a trailing comma after the last element, so that clang-format doesn't do this wonky formatting.

Technically, given we're on C++17, which has deduction guides, the type specifier can likely also be simplified down to:

constexpr std::array GAME_QUIRKS_NAMES{
  // ...
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, that's why it did it that. I remember that happening before, actually. I've also simplified the type specification like that (and I can confirm that the static_assert after will give a compile error if it's not updated, which wouldn't be the case with e.g. std::array<const char*, static_cast<size_t>(GameQuirk::COUNT)> since it doesn't care if the array is larger than what's actually specified)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and it seems like OSX and android hate that, so back to std::array<const char*, 10>.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, unfortunately those builders use a version of libc++ that's too old. :/

@leoetlino leoetlino merged commit 4c9b1f3 into dolphin-emu:master Feb 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants