Ejemplo n.º 1
0
void CBoot::Load_FST(bool _bIsWii)
{
  if (!DVDInterface::VolumeIsValid())
    return;

  const DiscIO::IVolume& volume = DVDInterface::GetVolume();

  // copy first 32 bytes of disc to start of Mem 1
  DVDRead(/*offset*/ 0, /*address*/ 0, /*length*/ 0x20, false);

  // copy of game id
  Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180);

  u32 shift = 0;
  if (_bIsWii)
    shift = 2;

  u32 fst_offset = 0;
  u32 fst_size = 0;
  u32 max_fst_size = 0;

  volume.ReadSwapped(0x0424, &fst_offset, _bIsWii);
  volume.ReadSwapped(0x0428, &fst_size, _bIsWii);
  volume.ReadSwapped(0x042c, &max_fst_size, _bIsWii);

  u32 arena_high = ROUND_DOWN(0x817FFFFF - (max_fst_size << shift), 0x20);
  Memory::Write_U32(arena_high, 0x00000034);

  // load FST
  DVDRead(fst_offset << shift, arena_high, fst_size << shift, _bIsWii);
  Memory::Write_U32(arena_high, 0x00000038);
  Memory::Write_U32(max_fst_size << shift, 0x0000003c);
}
Ejemplo n.º 2
0
void ExecuteCommand(UDICR& _DICR)
{
//	_dbg_assert_(DVDINTERFACE, _DICR.RW == 0); // only DVD to Memory
	int GCAM = ((SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_AM_BASEBOARD)
		&& (SConfig::GetInstance().m_EXIDevice[2] == EXIDEVICE_AM_BASEBOARD))
		? 1 : 0;

	if (GCAM)
	{
		ERROR_LOG(DVDINTERFACE,
			"DVD: %08x, %08x, %08x, DMA=addr:%08x,len:%08x,ctrl:%08x",
			m_DICMDBUF[0].Hex, m_DICMDBUF[1].Hex, m_DICMDBUF[2].Hex,
			m_DIMAR.Hex, m_DILENGTH.Hex, m_DICR.Hex);
		// decrypt command. But we have a zero key, that simplifies things a lot.
		// If you get crazy dvd command errors, make sure 0x80000000 - 0x8000000c is zero'd
		m_DICMDBUF[0].Hex <<= 24;
	}


	switch (m_DICMDBUF[0].CMDBYTE0)
	{
	case DVDLowInquiry:
		if (GCAM)
		{
			// 0x29484100...
			// was 21 i'm not entirely sure about this, but it works well.
			m_DIIMMBUF.Hex = 0x21000000;
		}
		else
		{
			// small safety check, dunno if it's needed
			if ((m_DICMDBUF[1].Hex == 0) && (m_DILENGTH.Length == 0x20))
			{
				u8* driveInfo = Memory::GetPointer(m_DIMAR.Address);
				// gives the correct output in GCOS - 06 2001/08 (61)
				// there may be other stuff missing ?
				driveInfo[4] = 0x20;
				driveInfo[5] = 0x01;
				driveInfo[6] = 0x06;
				driveInfo[7] = 0x08;
				driveInfo[8] = 0x61;

				// Just for fun
				INFO_LOG(DVDINTERFACE, "Drive Info: %02x %02x%02x/%02x (%02x)",
					driveInfo[6], driveInfo[4], driveInfo[5], driveInfo[7], driveInfo[8]);
			}
		}
		break;

	// "Set Extension"...not sure what it does
	case 0x55:
		INFO_LOG(DVDINTERFACE, "SetExtension");
		break;

	// DMA Read from Disc
	case 0xA8:
		if (g_bDiscInside)
		{
			switch (m_DICMDBUF[0].CMDBYTE3)
			{
			case 0x00: // Read Sector
				{
					u32 iDVDOffset = m_DICMDBUF[1].Hex << 2;

					DEBUG_LOG(DVDINTERFACE, "Read: DVDOffset=%08x, DMABuffer=%08x, SrcLength=%08x, DMALength=%08x",
						iDVDOffset, m_DIMAR.Address, m_DICMDBUF[2].Hex, m_DILENGTH.Length);
					_dbg_assert_(DVDINTERFACE, m_DICMDBUF[2].Hex == m_DILENGTH.Length);

					if (GCAM)
					{
						if (iDVDOffset & 0x80000000) // read request to hardware buffer
						{
							u32 len = m_DILENGTH.Length / 4;
							switch (iDVDOffset)
							{
							case 0x80000000:
								ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (80000000)");
								for (u32 i = 0; i < len; i++)
									Memory::Write_U32(0, m_DIMAR.Address + i * 4);
								break;
							case 0x80000040:
								ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (2) (80000040)");
								for (u32 i = 0; i < len; i++)
									Memory::Write_U32(~0, m_DIMAR.Address + i * 4);
								Memory::Write_U32(0x00000020, m_DIMAR.Address); // DIMM SIZE, LE
								Memory::Write_U32(0x4743414D, m_DIMAR.Address + 4); // GCAM signature
								break;
							case 0x80000120:
								ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000120)");
								for (u32 i = 0; i < len; i++)
									Memory::Write_U32(0x01010101, m_DIMAR.Address + i * 4);
								break;
							case 0x80000140:
								ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000140)");
								for (u32 i = 0; i < len; i++)
									Memory::Write_U32(0x01010101, m_DIMAR.Address + i * 4);
								break;
							case 0x84000020:
								ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (1) (84000020)");
								for (u32 i = 0; i < len; i++)
									Memory::Write_U32(0x00000000, m_DIMAR.Address + i * 4);
								break;
							default:
								ERROR_LOG(DVDINTERFACE, "GC-AM: UNKNOWN MEDIA BOARD LOCATION %x", iDVDOffset);
								break;
							}
							break;
						}
						else if ((iDVDOffset == 0x1f900000) || (iDVDOffset == 0x1f900020))
						{
							ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD COMM AREA (1f900020)");
							memcpy(Memory::GetPointer(m_DIMAR.Address), media_buffer + iDVDOffset - 0x1f900000, m_DILENGTH.Length);
							for (u32 i = 0; i < m_DILENGTH.Length; i += 4)
								ERROR_LOG(DVDINTERFACE, "GC-AM: %08x", Memory::Read_U32(m_DIMAR.Address + i));
							break;
						}
					}

					// Here is the actual Disk Reading
					if (!DVDRead(iDVDOffset, m_DIMAR.Address, m_DILENGTH.Length))
					{
						PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
					}
				}
				break;

			case 0x40: // Read DiscID
				_dbg_assert_(DVDINTERFACE, m_DICMDBUF[1].Hex == 0);
				_dbg_assert_(DVDINTERFACE, m_DICMDBUF[2].Hex == m_DILENGTH.Length);
				_dbg_assert_(DVDINTERFACE, m_DILENGTH.Length == 0x20);
				if (!DVDRead(m_DICMDBUF[1].Hex, m_DIMAR.Address, m_DILENGTH.Length))
					PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
				WARN_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(m_DIMAR.Address));
				break;

			default:
				_dbg_assert_msg_(DVDINTERFACE, 0, "Unknown Read Subcommand");
				break;
			}
		}
		else
		{
			// there is no disc to read
			_DICR.TSTART = 0;
			m_DILENGTH.Length = 0;
			g_ErrorCode = ERROR_NO_DISK | ERROR_COVER_H;
			GenerateDIInterrupt(INT_DEINT);
			return;
		}
		break;

	// GC-AM
	case 0xAA:
		if (GCAM)
		{
			ERROR_LOG(DVDINTERFACE, "GC-AM: 0xAA, DMABuffer=%08x, DMALength=%08x", m_DIMAR.Address, m_DILENGTH.Length);
			u32 iDVDOffset = m_DICMDBUF[1].Hex << 2;
			unsigned int len = m_DILENGTH.Length; 
			int offset = iDVDOffset - 0x1F900000;
			/*
			if (iDVDOffset == 0x84800000)
			{
				ERROR_LOG(DVDINTERFACE, "firmware upload");
			}
			else*/
			if ((offset < 0) || ((offset + len) > 0x40) || len > 0x40)
			{
				u32 addr = m_DIMAR.Address;
				if (iDVDOffset == 0x84800000) {
					ERROR_LOG(DVDINTERFACE, "FIRMWARE UPLOAD");
				} else {
					ERROR_LOG(DVDINTERFACE, "ILLEGAL MEDIA WRITE");
				}
				while (len >= 4)
				{
					ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08x: %08x", iDVDOffset, Memory::Read_U32(addr));
					addr += 4;
					len -= 4;
					iDVDOffset += 4;
				}
			}
			else
			{
				u32 addr = m_DIMAR.Address;
				memcpy(media_buffer + offset, Memory::GetPointer(addr), len);
				while (len >= 4)
				{
					ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08x: %08x", iDVDOffset, Memory::Read_U32(addr));
					addr += 4;
					len -= 4;
					iDVDOffset += 4;
				}
			}
		}
		break;

	// Seek (immediate)
	case DVDLowSeek:
		if (!GCAM)
		{
			// We don't care :)
			DEBUG_LOG(DVDINTERFACE, "Seek: offset=%08x (ignoring)", m_DICMDBUF[1].Hex << 2);
		}
		else
		{
			memset(media_buffer, 0, 0x20);
			media_buffer[0] = media_buffer[0x20]; // ID
			media_buffer[2] = media_buffer[0x22];
			media_buffer[3] = media_buffer[0x23] | 0x80;
			int cmd = (media_buffer[0x23]<<8)|media_buffer[0x22];
			ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer, cmd=%04x", cmd);
			switch (cmd)
			{
			case 0x00:
				media_buffer[4] = 1;
				break;
			case 0x1:
				media_buffer[7] = 0x20; // DIMM Size
				break;
			case 0x100:
				{
					// urgh
					static int percentage = 0;
					static int status = 0;
					percentage++;
					if (percentage > 100)
					{
						status++;
						percentage = 0;
					}
					media_buffer[4] = status;
					/* status:
					0 - "Initializing media board. Please wait.."
					1 - "Checking network. Please wait..."
					2 - "Found a system disc. Insert a game disc"
					3 - "Testing a game program. %d%%"
					4 - "Loading a game program. %d%%"
					5  - go
					6  - error xx 
					*/
					media_buffer[8] = percentage;
					media_buffer[4] = 0x05;
					media_buffer[8] = 0x64;
					break;
				}
			case 0x101:
				media_buffer[4] = 3; // version
				media_buffer[5] = 3; 
				media_buffer[6] = 1; // xxx
				media_buffer[8] = 1;
				media_buffer[16] = 0xFF;
				media_buffer[17] = 0xFF;
				media_buffer[18] = 0xFF;
				media_buffer[19] = 0xFF;
				break;
			case 0x102:  // get error code
				media_buffer[4] = 1; // 0: download incomplete (31), 1: corrupted, other error 1
				media_buffer[5] = 0;
				break;
			case 0x103:
				memcpy(media_buffer + 4, "A89E27A50364511", 15);  // serial
				break;
#if 0
			case 0x301: // unknown
				memcpy(media_buffer + 4, media_buffer + 0x24, 0x1c);
				break;
			case 0x302:
				break;
#endif
			default:
				ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer (unknown)");
				break;
			}
			memset(media_buffer + 0x20, 0, 0x20);
			m_DIIMMBUF.Hex = 0x66556677; // just a random value that works.
		}
		break;

	case DVDLowOffset:
		DEBUG_LOG(DVDINTERFACE, "DVDLowOffset: ignoring...");
		break;

	// Request Error Code
	case DVDLowRequestError:
		ERROR_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", g_ErrorCode);
		m_DIIMMBUF.Hex = g_ErrorCode;
		break;

	// Audio Stream (Immediate)
	//	m_DICMDBUF[0].CMDBYTE1		= subcommand
	//	m_DICMDBUF[1].Hex << 2		= offset on disc 
	//	m_DICMDBUF[2].Hex			= Length of the stream
	case 0xE1:
		{
			u32 pos = m_DICMDBUF[1].Hex << 2;
			u32 length = m_DICMDBUF[2].Hex;

			// Start playing
			if (!g_bStream && m_DICMDBUF[0].CMDBYTE1 == 0 && pos != 0 && length != 0)
			{
				AudioPos = pos;
				CurrentStart = pos;
				CurrentLength = length;
				NGCADPCM::InitFilter();
				g_bStream = true;
			}

			LoopStart = pos;
			LoopLength = length;
			g_bStream = (m_DICMDBUF[0].CMDBYTE1 == 0); // This command can start/stop the stream

			// Stop stream
			if (m_DICMDBUF[0].CMDBYTE1 == 1)
			{
				AudioPos = 0;
				LoopStart = 0;
				LoopLength = 0;
				CurrentStart = 0;
				CurrentLength = 0;
			}

			WARN_LOG(DVDINTERFACE, "(Audio) Stream subcmd = %08x offset = %08x length=%08x",
				m_DICMDBUF[0].Hex, m_DICMDBUF[1].Hex << 2, m_DICMDBUF[2].Hex);
		}
		break;

	// Request Audio Status (Immediate)
	case 0xE2:
		{
			switch (m_DICMDBUF[0].CMDBYTE1)
			{
			case 0x00: // Returns streaming status
				m_DIIMMBUF.Hex = (AudioPos == 0) ? 0 : 1;
				break;
			case 0x01: // Returns the current offset
				if (g_bStream)
					m_DIIMMBUF.Hex = (AudioPos - CurrentStart) >> 2;
				else
					m_DIIMMBUF.Hex = 0;
				break;
			case 0x02: // Returns the start offset
				if (g_bStream)
					m_DIIMMBUF.Hex = CurrentStart >> 2;
				else
					m_DIIMMBUF.Hex = 0;
				break;
			case 0x03: // Returns the total length
				if (g_bStream)
					m_DIIMMBUF.Hex = CurrentLength;
				else
					m_DIIMMBUF.Hex = 0;
				break;
			default:
				WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x  Request Audio status %s", m_DICMDBUF[0].CMDBYTE1, g_bStream? "on":"off");
				break;
			}
		}
Ejemplo n.º 3
0
// __________________________________________________________________________________________________
// GameCube Bootstrap 2 HLE:
// copy the apploader to 0x81200000
// execute the apploader, function by function, using the above utility.
bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
{
  INFO_LOG(BOOT, "Faking GC BS2...");

  // Set up MSR and the BAT SPR registers.
  UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
  m_MSR.FP = 1;
  m_MSR.DR = 1;
  m_MSR.IR = 1;
  m_MSR.EE = 1;
  PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
  PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
  PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
  PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
  PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
  PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;

  // Write necessary values
  // Here we write values to memory that the apploader does not take care of. Game info goes
  // to 0x80000000 according to YAGCD 4.2.

  // It's possible to boot DOL and ELF files without a disc inserted
  if (DVDInterface::VolumeIsValid())
    DVDRead(/*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, false);  // write disc info

  PowerPC::HostWrite_U32(0x0D15EA5E,
                         0x80000020);  // Booted from bootrom. 0xE5207C22 = booted from jtag
  PowerPC::HostWrite_U32(Memory::REALRAM_SIZE,
                         0x80000028);  // Physical Memory Size (24MB on retail)
  // TODO determine why some games fail when using a retail ID. (Seem to take different EXI paths,
  // see Ikaruga for example)
  PowerPC::HostWrite_U32(
      0x10000006,
      0x8000002C);  // Console type - DevKit  (retail ID == 0x00000003) see YAGCD 4.2.1.1.2

  PowerPC::HostWrite_U32(SConfig::GetInstance().bNTSC ? 0 : 1,
                         0x800000CC);  // Fake the VI Init of the IPL (YAGCD 4.2.1.4)

  PowerPC::HostWrite_U32(0x01000000, 0x800000d0);  // ARAM Size. 16MB main + 4/16/32MB external
                                                   // (retail consoles have no external ARAM)

  PowerPC::HostWrite_U32(0x09a7ec80, 0x800000F8);  // Bus Clock Speed
  PowerPC::HostWrite_U32(0x1cf7c580, 0x800000FC);  // CPU Clock Speed

  PowerPC::HostWrite_U32(0x4c000064, 0x80000300);  // Write default DFI Handler:     rfi
  PowerPC::HostWrite_U32(0x4c000064, 0x80000800);  // Write default FPU Handler:     rfi
  PowerPC::HostWrite_U32(0x4c000064, 0x80000C00);  // Write default Syscall Handler: rfi

  PowerPC::HostWrite_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000,
                         0x800030D8);  // Preset time base ticks
  // HIO checks this
  // PowerPC::HostWrite_U16(0x8200,     0x000030e6); // Console type

  HLE::Patch(0x81300000, "OSReport");  // HLE OSReport for Apploader

  if (!DVDInterface::VolumeIsValid())
    return false;

  // Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc,
  // but the size can differ between discs. Compare with YAGCD chap 13.
  const DiscIO::IVolume& volume = DVDInterface::GetVolume();
  const u32 apploader_offset = 0x2440;
  u32 apploader_entry, apploader_size, apploader_trailer;
  if (skipAppLoader || !volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, false) ||
      !volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, false) ||
      !volume.ReadSwapped(apploader_offset + 0x18, &apploader_trailer, false) ||
      apploader_entry == (u32)-1 || apploader_size + apploader_trailer == (u32)-1)
  {
    INFO_LOG(BOOT, "GC BS2: Not running apploader!");
    return false;
  }
  DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size + apploader_trailer, false);

  // Setup pointers like real BS2 does
  if (SConfig::GetInstance().bNTSC)
  {
    PowerPC::ppcState.gpr[1] = 0x81566550;  // StackPointer, used to be set to 0x816ffff0
    PowerPC::ppcState.gpr[2] = 0x81465cc0;  // Global pointer to Small Data Area 2 Base (haven't
                                            // seen anything use it...meh)
    PowerPC::ppcState.gpr[13] =
        0x81465320;  // Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it)
  }
  else
  {
    PowerPC::ppcState.gpr[1] = 0x815edca8;
    PowerPC::ppcState.gpr[2] = 0x814b5b20;
    PowerPC::ppcState.gpr[13] = 0x814b4fc0;
  }

  // TODO - Make Apploader(or just RunFunction()) debuggable!!!

  // Call iAppLoaderEntry.
  DEBUG_LOG(MASTER_LOG, "Call iAppLoaderEntry");
  u32 iAppLoaderFuncAddr = 0x80003100;
  PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
  PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
  PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
  RunFunction(apploader_entry);
  u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
  u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
  u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);

  // iAppLoaderInit
  DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit");
  PowerPC::ppcState.gpr[3] = 0x81300000;
  RunFunction(iAppLoaderInit);

  // iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem).
  // To give you an idea about where the stuff is located on the disc take a look at yagcd
  // ch 13.
  DEBUG_LOG(MASTER_LOG, "Call iAppLoaderMain");
  do
  {
    PowerPC::ppcState.gpr[3] = 0x81300004;
    PowerPC::ppcState.gpr[4] = 0x81300008;
    PowerPC::ppcState.gpr[5] = 0x8130000c;

    RunFunction(iAppLoaderMain);

    u32 iRamAddress = PowerPC::Read_U32(0x81300004);
    u32 iLength = PowerPC::Read_U32(0x81300008);
    u32 iDVDOffset = PowerPC::Read_U32(0x8130000c);

    INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x   memOffset: %08x   length: %i", iDVDOffset,
             iRamAddress, iLength);
    DVDRead(iDVDOffset, iRamAddress, iLength, false);

  } while (PowerPC::ppcState.gpr[3] != 0x00);

  // iAppLoaderClose
  DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose");
  RunFunction(iAppLoaderClose);

  // return
  PC = PowerPC::ppcState.gpr[3];

  // Load patches
  PatchEngine::LoadPatches();

  // If we have any patches that need to be applied very early, here's a good place
  PatchEngine::ApplyFramePatches();

  return true;
}
Ejemplo n.º 4
0
// __________________________________________________________________________________________________
// Wii Bootstrap 2 HLE:
// copy the apploader to 0x81200000
// execute the apploader
bool CBoot::EmulatedBS2_Wii()
{
  INFO_LOG(BOOT, "Faking Wii BS2...");

  // Setup Wii memory
  DiscIO::Country country_code = DiscIO::Country::COUNTRY_UNKNOWN;
  if (DVDInterface::VolumeIsValid())
    country_code = DVDInterface::GetVolume().GetCountry();
  if (SetupWiiMemory(country_code) == false)
    return false;

  // Execute the apploader
  bool apploaderRan = false;
  if (DVDInterface::VolumeIsValid() &&
      DVDInterface::GetVolume().GetVolumeType() == DiscIO::Platform::WII_DISC)
  {
    // This is some kind of consistency check that is compared to the 0x00
    // values as the game boots. This location keeps the 4 byte ID for as long
    // as the game is running. The 6 byte ID at 0x00 is overwritten sometime
    // after this check during booting.
    DVDRead(0, 0x3180, 4, true);

    // Set up MSR and the BAT SPR registers.
    UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
    m_MSR.FP = 1;
    m_MSR.DR = 1;
    m_MSR.IR = 1;
    m_MSR.EE = 1;
    PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
    PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
    PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
    PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
    PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
    PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
    PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
    PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
    PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
    PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
    PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
    PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;

    Memory::Write_U32(0x4c000064, 0x00000300);  // Write default DSI Handler:     rfi
    Memory::Write_U32(0x4c000064, 0x00000800);  // Write default FPU Handler:     rfi
    Memory::Write_U32(0x4c000064, 0x00000C00);  // Write default Syscall Handler: rfi

    HLE::Patch(0x81300000, "OSReport");  // HLE OSReport for Apploader

    PowerPC::ppcState.gpr[1] = 0x816ffff0;  // StackPointer

    const u32 apploader_offset = 0x2440;  // 0x1c40;

    // Load Apploader to Memory
    const DiscIO::IVolume& volume = DVDInterface::GetVolume();
    u32 apploader_entry, apploader_size;
    if (!volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, true) ||
        !volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, true) ||
        apploader_entry == (u32)-1 || apploader_size == (u32)-1)
    {
      ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
      return false;
    }
    DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size, true);

    // call iAppLoaderEntry
    DEBUG_LOG(BOOT, "Call iAppLoaderEntry");

    u32 iAppLoaderFuncAddr = 0x80004000;
    PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
    PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
    PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
    RunFunction(apploader_entry);
    u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
    u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
    u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);

    // iAppLoaderInit
    DEBUG_LOG(BOOT, "Run iAppLoaderInit");
    PowerPC::ppcState.gpr[3] = 0x81300000;
    RunFunction(iAppLoaderInit);

    // Let the apploader load the exe to memory. At this point I get an unknown IPC command
    // (command zero) when I load Wii Sports or other games a second time. I don't notice
    // any side effects however. It's a little disconcerting however that Start after Stop
    // behaves differently than the first Start after starting Dolphin. It means something
    // was not reset correctly.
    DEBUG_LOG(BOOT, "Run iAppLoaderMain");
    do
    {
      PowerPC::ppcState.gpr[3] = 0x81300004;
      PowerPC::ppcState.gpr[4] = 0x81300008;
      PowerPC::ppcState.gpr[5] = 0x8130000c;

      RunFunction(iAppLoaderMain);

      u32 iRamAddress = PowerPC::Read_U32(0x81300004);
      u32 iLength = PowerPC::Read_U32(0x81300008);
      u32 iDVDOffset = PowerPC::Read_U32(0x8130000c) << 2;

      INFO_LOG(BOOT, "DVDRead: offset: %08x   memOffset: %08x   length: %i", iDVDOffset,
               iRamAddress, iLength);
      DVDRead(iDVDOffset, iRamAddress, iLength, true);
    } while (PowerPC::ppcState.gpr[3] != 0x00);

    // iAppLoaderClose
    DEBUG_LOG(BOOT, "Run iAppLoaderClose");
    RunFunction(iAppLoaderClose);

    apploaderRan = true;

    // Pass the "#002 check"
    // Apploader writes the IOS version and revision here, we copy it
    // Fake IOSv9 r2.4 if no version is found (elf loading)
    u32 firmwareVer = PowerPC::Read_U32(0x80003188);
    PowerPC::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x80003140);

    // Load patches and run startup patches
    PatchEngine::LoadPatches();

    // return
    PC = PowerPC::ppcState.gpr[3];
  }

  return apploaderRan;
}
Ejemplo n.º 5
0
bool CBoot::SetupWiiMemory(DiscIO::Country country)
{
  static const CountrySetting SETTING_EUROPE = {"EUR", "PAL", "EU", "LE"};
  static const CountrySetting SETTING_USA = {"USA", "NTSC", "US", "LU"};
  static const CountrySetting SETTING_JAPAN = {"JPN", "NTSC", "JP", "LJ"};
  static const CountrySetting SETTING_KOREA = {"KOR", "NTSC", "KR", "LKH"};
  static const std::map<DiscIO::Country, const CountrySetting> country_settings = {
      {DiscIO::Country::COUNTRY_EUROPE, SETTING_EUROPE},
      {DiscIO::Country::COUNTRY_USA, SETTING_USA},
      {DiscIO::Country::COUNTRY_JAPAN, SETTING_JAPAN},
      {DiscIO::Country::COUNTRY_KOREA, SETTING_KOREA},
      // TODO: Determine if Taiwan have their own specific settings.
      //      Also determine if there are other specific settings
      //      for other countries.
      {DiscIO::Country::COUNTRY_TAIWAN, SETTING_JAPAN}};
  auto entryPos = country_settings.find(country);
  const CountrySetting& country_setting =
      (entryPos != country_settings.end()) ?
          entryPos->second :
          (SConfig::GetInstance().bNTSC ?
               SETTING_USA :
               SETTING_EUROPE);  // default to USA or EUR depending on game's video mode

  SettingsHandler gen;
  std::string serno;
  std::string settings_Filename(
      Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + WII_SETTING);
  if (File::Exists(settings_Filename))
  {
    File::IOFile settingsFileHandle(settings_Filename, "rb");
    if (settingsFileHandle.ReadBytes((void*)gen.GetData(), SettingsHandler::SETTINGS_SIZE))
    {
      gen.Decrypt();
      serno = gen.GetValue("SERNO");
      gen.Reset();
    }
    File::Delete(settings_Filename);
  }

  if (serno.empty() || serno == "000000000")
  {
    if (Core::g_want_determinism)
      serno = "123456789";
    else
      serno = gen.generateSerialNumber();
    INFO_LOG(BOOT, "No previous serial number found, generated one instead: %s", serno.c_str());
  }
  else
  {
    INFO_LOG(BOOT, "Using serial number: %s", serno.c_str());
  }

  std::string model = "RVL-001(" + country_setting.area + ")";
  gen.AddSetting("AREA", country_setting.area);
  gen.AddSetting("MODEL", model);
  gen.AddSetting("DVD", "0");
  gen.AddSetting("MPCH", "0x7FFE");
  gen.AddSetting("CODE", country_setting.code);
  gen.AddSetting("SERNO", serno);
  gen.AddSetting("VIDEO", country_setting.video);
  gen.AddSetting("GAME", country_setting.game);

  File::CreateFullPath(settings_Filename);
  {
    File::IOFile settingsFileHandle(settings_Filename, "wb");

    if (!settingsFileHandle.WriteBytes(gen.GetData(), SettingsHandler::SETTINGS_SIZE))
    {
      PanicAlertT("SetupWiiMemory: Can't create setting.txt file");
      return false;
    }
    // Write the 256 byte setting.txt to memory.
    Memory::CopyToEmu(0x3800, gen.GetData(), SettingsHandler::SETTINGS_SIZE);
  }

  INFO_LOG(BOOT, "Setup Wii Memory...");

  /*
  Set hardcoded global variables to Wii memory. These are partly collected from
  WiiBrew. These values are needed for the games to function correctly. A few
  values in this region will also be placed here by the game as it boots.
  They are:
  0x80000038  Start of FST
  0x8000003c  Size of FST Size
  0x80000060  Copyright code
  */

  // When booting a WAD or the system menu, there will probably not be a disc inserted
  if (DVDInterface::VolumeIsValid())
    DVDRead(0x00000000, 0x00000000, 0x20, false);  // Game Code

  Memory::Write_U32(0x0D15EA5E, 0x00000020);            // Another magic word
  Memory::Write_U32(0x00000001, 0x00000024);            // Unknown
  Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028);  // MEM1 size 24MB
  Memory::Write_U32(0x00000023, 0x0000002c);            // Production Board Model
  Memory::Write_U32(0x00000000, 0x00000030);            // Init
  Memory::Write_U32(0x817FEC60, 0x00000034);            // Init
  // 38, 3C should get start, size of FST through apploader
  Memory::Write_U32(0x38a00040, 0x00000060);            // Exception init
  Memory::Write_U32(0x8008f7b8, 0x000000e4);            // Thread Init
  Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0);  // "Simulated memory size" (debug mode?)
  Memory::Write_U32(0x8179b500, 0x000000f4);            // __start
  Memory::Write_U32(0x0e7be2c0, 0x000000f8);            // Bus speed
  Memory::Write_U32(0x2B73A840, 0x000000fc);            // CPU speed
  Memory::Write_U16(0x0000, 0x000030e6);                // Console type
  Memory::Write_U32(0x00000000, 0x000030c0);            // EXI
  Memory::Write_U32(0x00000000, 0x000030c4);            // EXI
  Memory::Write_U32(0x00000000, 0x000030dc);            // Time
  Memory::Write_U32(0x00000000, 0x000030d8);            // Time
  Memory::Write_U16(0x8201, 0x000030e6);                // Dev console / debug capable
  Memory::Write_U32(0x00000000, 0x000030f0);            // Apploader
  Memory::Write_U32(0x01800000, 0x00003100);            // BAT
  Memory::Write_U32(0x01800000, 0x00003104);            // BAT
  Memory::Write_U32(0x00000000, 0x0000310c);            // Init
  Memory::Write_U32(0x8179d500, 0x00003110);            // Init
  Memory::Write_U32(0x04000000, 0x00003118);            // Unknown
  Memory::Write_U32(0x04000000, 0x0000311c);            // BAT
  Memory::Write_U32(0x93400000, 0x00003120);            // BAT
  Memory::Write_U32(0x90000800, 0x00003124);            // Init - MEM2 low
  Memory::Write_U32(0x93ae0000, 0x00003128);            // Init - MEM2 high
  Memory::Write_U32(0x93ae0000, 0x00003130);            // IOS MEM2 low
  Memory::Write_U32(0x93b00000, 0x00003134);            // IOS MEM2 high
  Memory::Write_U32(0x00000012, 0x00003138);            // Console type
  // 40 is copied from 88 after running apploader
  Memory::Write_U32(0x00090204, 0x00003140);  // IOS revision (IOS9, v2.4)
  Memory::Write_U32(0x00062507, 0x00003144);  // IOS date in USA format (June 25, 2007)
  Memory::Write_U16(0x0113, 0x0000315e);      // Apploader
  Memory::Write_U32(0x0000FF16, 0x00003158);  // DDR ram vendor code
  Memory::Write_U32(0x00000000, 0x00003160);  // Init semaphore (sysmenu waits for this to clear)
  Memory::Write_U32(0x00090204, 0x00003188);  // Expected IOS revision

  Memory::Write_U8(0x80, 0x0000315c);         // OSInit
  Memory::Write_U16(0x0000, 0x000030e0);      // PADInit
  Memory::Write_U32(0x80000000, 0x00003184);  // GameID Address

  // Fake the VI Init of the IPL
  Memory::Write_U32(SConfig::GetInstance().bNTSC ? 0 : 1, 0x000000CC);

  // Clear exception handler. Why? Don't we begin with only zeros?
  for (int i = 0x3000; i <= 0x3038; i += 4)
  {
    Memory::Write_U32(0x00000000, i);
  }
  return true;
}