Guest User

Untitled

a guest
Mar 23rd, 2023
826
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 59.12 KB | Gaming | 0 0
  1. // Copyright 2013 Dolphin Emulator Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4.  
  5. #pragma warning(disable : 4189)
  6.  
  7. #include "Core/BootManager.h"
  8.  
  9. #include <algorithm>
  10. #include <memory>
  11. #include <optional>
  12. #include <string>
  13. #include <vector>
  14.  
  15. #include <fmt/format.h>
  16.  
  17. #include "Common/CommonTypes.h"
  18. #include "Common/Config/Config.h"
  19. #include "Common/FileUtil.h"
  20. #include "Common/IniFile.h"
  21. #include "Common/Logging/Log.h"
  22. #include "Common/IOFile.h"
  23. #include "DiscIO/DirectoryBlob.h"
  24.  
  25. #include "Core/Boot/Boot.h"
  26. #include "Core/Config/MainSettings.h"
  27. #include "Core/Config/SYSCONFSettings.h"
  28. #include "Core/ConfigLoaders/BaseConfigLoader.h"
  29. #include "Core/ConfigLoaders/NetPlayConfigLoader.h"
  30. #include "Core/ConfigManager.h"
  31. #include "Core/Core.h"
  32. #include "Core/HW/EXI/EXI.h"
  33. #include "Core/HW/SI/SI.h"
  34. #include "Core/HW/SI/SI_Device.h"
  35. #include "Core/HW/MMIO.h"
  36. #include "Core/HW/Memmap.h"
  37. #include "Core/HW/Sram.h"
  38. #include "Core/HW/DVD/DVDInterface.h"
  39. #include "Core/HW/DVD/DVDThread.h"
  40. #include "Core/HW/DVD/AMBaseboard.h"
  41. #include "Core/HW/WiimoteReal/WiimoteReal.h"
  42. #include "Core/Movie.h"
  43. #include "Core/NetPlayProto.h"
  44. #include "Core/PowerPC/PowerPC.h"
  45. #include "Core/System.h"
  46. #include "Core/WiiRoot.h"
  47. #include "Core/HLE/HLE.h"
  48. #include "Core/PowerPC/PPCSymbolDB.h"
  49.  
  50. #include "DiscIO/Enums.h"
  51. #include "DiscIO/VolumeDisc.h"
  52.  
  53. #ifdef WIN32
  54. #include <winsock2.h>
  55. #else
  56. #include <fcntl.h>
  57. #include <netinet/in.h>
  58. #include <sys/socket.h>
  59. #include <arpa/inet.h>
  60. #endif"GC-AM: {:08x} {:08x} {:08x} {:08x}", memory.Read_U32(Address + i),
  61.                                                                                             memory.Read_U32(Address+i+4),
  62.                                                                                             memory.Read_U32(Address+i+8),
  63.                                                                                             memory.Read_U32(Address+i+12) );
  64.     }
  65. }
  66. void FirmwareMap(bool on)
  67. {
  68.   if (on)
  69.     FIRMWAREMAP = 1;
  70.   else
  71.     FIRMWAREMAP = 0;
  72. }
  73.  
  74. void InitKeys(u32 KeyA, u32 KeyB, u32 KeyC)
  75. {
  76.   GCAMKeyA = KeyA;
  77.   GCAMKeyB = KeyB;
  78.   GCAMKeyC = KeyC;
  79. }
  80. void Init(void)
  81. {
  82.   memset(media_buffer, 0, sizeof(media_buffer));
  83.   memset(network_buffer, 0, sizeof(network_buffer));
  84.   memset(network_command_buffer, 0, sizeof(network_command_buffer));
  85.   memset(firmware, -1, sizeof(firmware));
  86.  
  87.   m_game_type = 0;
  88.   m_segaboot = 0;
  89.   FIRMWAREMAP = 0;
  90.  
  91.   GCAMKeyA = 0;
  92.   GCAMKeyB = 0;
  93.   GCAMKeyC = 0;
  94.  
  95.   if (File::Exists(File::GetUserPath(D_TRIUSER_IDX)) == false)
  96.   {
  97.     File::CreateFullPath(File::GetUserPath(D_TRIUSER_IDX));
  98.   }
  99.  
  100.   std::string netcfg_Filename(File::GetUserPath(D_TRIUSER_IDX) + "trinetcfg.bin");
  101.   if (File::Exists(netcfg_Filename))
  102.   {
  103.     m_netcfg = new File::IOFile(netcfg_Filename, "rb+");
  104.   }
  105.   else
  106.   {
  107.     m_netcfg = new File::IOFile(netcfg_Filename, "wb+");
  108.   }
  109.   if (!m_netcfg)
  110.   {
  111.     PanicAlertFmt("Failed to open/create:{0}", netcfg_Filename);
  112.   }
  113.  
  114.   std::string netctrl_Filename(File::GetUserPath(D_TRIUSER_IDX) + "trinetctrl.bin");
  115.   if (File::Exists(netctrl_Filename))
  116.   {
  117.     m_netctrl = new File::IOFile(netctrl_Filename, "rb+");
  118.   }
  119.   else
  120.   {
  121.     m_netctrl = new File::IOFile(netctrl_Filename, "wb+");
  122.   }
  123.  
  124.   std::string extra_Filename(File::GetUserPath(D_TRIUSER_IDX) + "triextra.bin");
  125.   if (File::Exists(extra_Filename))
  126.   {
  127.     m_extra = new File::IOFile(extra_Filename, "rb+");
  128.   }
  129.   else
  130.   {
  131.     m_extra = new File::IOFile(extra_Filename, "wb+");
  132.   }
  133.  
  134.   std::string dimm_Filename(File::GetUserPath(D_TRIUSER_IDX) + "tridimm_" + SConfig::GetInstance().GetGameID().c_str() + ".bin");
  135.   if (File::Exists(dimm_Filename))
  136.   {
  137.     m_dimm = new File::IOFile(dimm_Filename, "rb+");
  138.   }
  139.   else
  140.   {
  141.     m_dimm = new File::IOFile(dimm_Filename, "wb+");
  142.   }
  143.  
  144.   std::string backup_Filename(File::GetUserPath(D_TRIUSER_IDX) + "backup_" + SConfig::GetInstance().GetGameID().c_str() + ".bin");
  145.   if (File::Exists(backup_Filename))
  146.   {
  147.     m_backup = new File::IOFile(backup_Filename, "rb+");
  148.   }
  149.   else
  150.   {
  151.     m_backup = new File::IOFile(backup_Filename, "wb+");
  152.   }
  153.  
  154.   // This is the firmware for the Triforce
  155.   std::string sega_boot_Filename(File::GetUserPath(D_TRIUSER_IDX) + "segaboot.gcm");
  156.   if (File::Exists(sega_boot_Filename))
  157.   {
  158.     File::IOFile* sega_boot = new File::IOFile(sega_boot_Filename, "rb+");
  159.     if (sega_boot)
  160.     {
  161.       u64 Length = sega_boot->GetSize();
  162.       if (Length >= sizeof(firmware))
  163.       {
  164.         Length = sizeof(firmware);
  165.       }
  166.       sega_boot->ReadBytes(firmware, Length);
  167.       sega_boot->Close();
  168.     }
  169.   }
  170. }
  171. u8 *InitDIMM( void )
  172. {
  173.   if (!m_dimm_disc)
  174.   {
  175.     m_dimm_disc = new u8[512 * 1024 * 1024];
  176.   }
  177.   FIRMWAREMAP = 0;
  178.   return m_dimm_disc;
  179. }
  180. u32 ExecuteCommand(u32* DICMDBUF, u32 Address, u32 Length)
  181. {
  182.   auto& system = Core::System::GetInstance();
  183.   auto& memory = system.GetMemory();
  184.  
  185.   /*
  186.     The triforce IPL sends these commands first
  187.     01010000 00000101 00000000
  188.     01010000 00000000 0000ffff
  189.   */
  190.   if (GCAMKeyA == 0)
  191.   {
  192.     /*
  193.       Since it is currently unknown how the seed is created
  194.       we have to patch out the crypto.
  195.     */
  196.     if (memory.Read_U32(0x8131ecf4))
  197.     {
  198.       memory.Write_U32(0, 0x8131ecf4);
  199.       memory.Write_U32(0, 0x8131ecf8);
  200.       memory.Write_U32(0, 0x8131ecfC);
  201.       memory.Write_U32(0, 0x8131ebe0);
  202.       memory.Write_U32(0, 0x8131ed6c);
  203.       memory.Write_U32(0, 0x8131ed70);
  204.       memory.Write_U32(0, 0x8131ed74);
  205.  
  206.       memory.Write_U32(0x4E800020, 0x813025C8);
  207.       memory.Write_U32(0x4E800020, 0x81302674);
  208.  
  209.       PowerPC::ppcState.iCache.Invalidate(0x813025C8);
  210.       PowerPC::ppcState.iCache.Invalidate(0x81302674);
  211.  
  212.       HLE::Patch(0x813048B8, "OSReport");
  213.       HLE::Patch(0x8130095C, "OSReport");  // Apploader
  214.     }
  215.   }
  216.  
  217.   DICMDBUF[0] ^= GCAMKeyA;
  218.   DICMDBUF[1] ^= GCAMKeyB;
  219.   //Length ^= GCAMKeyC; DMA Length is always plain
  220.  
  221.   u32 seed = DICMDBUF[0] >> 16;
  222.  
  223.   GCAMKeyA *= seed;
  224.   GCAMKeyB *= seed;
  225.   GCAMKeyC *= seed;
  226.  
  227.   DICMDBUF[0] <<= 24;
  228.   DICMDBUF[1] <<= 2;
  229.  
  230.   // SegaBoot adds bits for some reason to offset/length
  231.   // also adds 0x20 to offset
  232.   if (DICMDBUF[1] == 0x00100440)
  233.   {
  234.     m_segaboot = 1;
  235.   }
  236.  
  237.   u32 Command = DICMDBUF[0];
  238.   u32 Offset  = DICMDBUF[1];
  239.  
  240.     INFO_LOG_FMT(DVDINTERFACE, "GCAM: {:08x} {:08x} DMA=addr:{:08x},len:{:08x} Keys: {:08x} {:08x} {:08x}",
  241.                                 Command, Offset, Address, Length, GCAMKeyA, GCAMKeyB, GCAMKeyC );
  242.  
  243.   // Test menu exit to sega boot
  244.   //if (Offset == 0x0002440 && Address == 0x013103a0 )
  245.   //{
  246.   //  FIRMWAREMAP = 1;
  247.   //}
  248.  
  249.     switch(Command>>24)
  250.     {
  251.         // Inquiry
  252.     case 0x12:
  253.       if(FIRMWAREMAP == 1)
  254.       {
  255.         FIRMWAREMAP = 0;
  256.         m_segaboot = 0;
  257.       }
  258.       //Avalon excepts higher version
  259.       if (GetGameType() == KeyOfAvalon )
  260.       {
  261.         return 0x29484100;
  262.       }
  263.  
  264.             return 0x21000000;
  265.             break;
  266.         // Read
  267.         case 0xA8:
  268.       if ((Offset & 0x8FFF0000) == 0x80000000 )
  269.             {
  270.                 switch(Offset)
  271.                 {
  272.                 // Media board status (1)
  273.         case 0x80000000:
  274.                     memory.Write_U16( Common::swap16( 0x0100 ), Address );
  275.                     break;
  276.                 // Media board status (2)
  277.         case 0x80000020:
  278.                     memset( memory.GetPointer(Address), 0, Length );
  279.                     break;
  280.                 // Media board status (3)
  281.         case 0x80000040:
  282.                     memset( memory.GetPointer(Address), 0xFF, Length );
  283.                     // DIMM size (512MB)
  284.                     memory.Write_U32( Common::swap32( 0x20000000 ), Address );
  285.                     // GCAM signature
  286.                     memory.Write_U32( 0x4743414D, Address+4 );
  287.           break;
  288.         // ?
  289.         case 0x80000100:
  290.           memory.Write_U32(Common::swap32( (u32)0x001F1F1F ), Address);
  291.           break;
  292.         // Firmware status (1)
  293.         case 0x80000120:
  294.           memory.Write_U32(Common::swap32( (u32)0x01FA ), Address);
  295.           break;
  296.                 // Firmware status (2)
  297.         case 0x80000140:
  298.           memory.Write_U32(Common::swap32((u32)1), Address);
  299.           break;
  300.         case 0x80000160:
  301.           memory.Write_U32( 0x00001E00, Address);
  302.           break;
  303.         case 0x80000180:
  304.           memory.Write_U32( 0, Address);
  305.           break;
  306.         case 0x800001A0:
  307.           memory.Write_U32( 0xFFFFFFFF , Address);
  308.           break;
  309.                 default:
  310.                     PrintMBBuffer( Address, Length );
  311.           PanicAlertFmtT("Unhandled Media Board Read:{0:08x}", Offset);
  312.                     break;
  313.                 }
  314.                 return 0;
  315.       }
  316.             // Network configuration
  317.             if( (Offset == 0x00000000) && (Length == 0x80) )
  318.             {
  319.         m_netcfg->Seek(0, File::SeekOrigin::Begin);
  320.                 m_netcfg->ReadBytes( memory.GetPointer(Address), Length );
  321.                 return 0;
  322.             }
  323.       // Extra Settings
  324.       // media crc check on/off
  325.       if ((Offset == 0x1FFEFFE0) && (Length == 0x20))
  326.       {
  327.         m_extra->Seek(0, File::SeekOrigin::Begin);
  328.         m_extra->ReadBytes(memory.GetPointer(Address), Length);
  329.         return 0;
  330.       }
  331.             // DIMM memory (8MB)
  332.             if( (Offset >= 0x1F000000) && (Offset <= 0x1F800000) )
  333.             {
  334.         u32 dimmoffset = Offset - 0x1F000000;
  335.         m_dimm->Seek(dimmoffset, File::SeekOrigin::Begin);
  336.                 m_dimm->ReadBytes( memory.GetPointer(Address), Length );
  337.                 return 0;
  338.             }
  339.             // DIMM command (V1)
  340.             if( (Offset >= 0x1F900000) && (Offset <= 0x1F90003F) )
  341.             {
  342.         u32 dimmoffset = Offset - 0x1F900000;
  343.                 memcpy( memory.GetPointer(Address), media_buffer + dimmoffset, Length );
  344.  
  345.                 //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: Read MEDIA BOARD COMM AREA (1) ({:08x})", dimmoffset);
  346.                 PrintMBBuffer( Address, Length );
  347.                 return 0;
  348.             }
  349.             // Network command
  350.             if( (Offset >= NetworkCommandAddress) && (Offset <= 0x1FCFFFFF) )
  351.       {
  352.         u32 dimmoffset = Offset - NetworkCommandAddress;
  353.                 //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: Read NETWORK COMMAND BUFFER ({:08x},{})", Offset, Length );
  354.         memcpy(memory.GetPointer(Address), network_command_buffer + dimmoffset, Length);
  355.                 return 0;
  356.       }
  357.  
  358.       // Network buffer
  359.       if ((Offset >= 0x1FA00000) && (Offset <= 0x1FA0FFFF))
  360.       {
  361.         u32 dimmoffset = Offset - 0x1FA00000;
  362.         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: Read NETWORK BUFFER (1) ({:08x},{})", Offset, Length);
  363.         memcpy(memory.GetPointer(Address), network_buffer + dimmoffset, Length);
  364.         return 0;
  365.       }
  366.  
  367.       // Network buffer
  368.       if ((Offset >= 0x1FD00000) && (Offset <= 0x1FD0FFFF))
  369.       {
  370.         u32 dimmoffset = Offset - 0x1FD00000;
  371.         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: Read NETWORK BUFFER (2) ({:08x},{})", Offset, Length);
  372.         memcpy(memory.GetPointer(Address), network_buffer + dimmoffset, Length);
  373.         return 0;
  374.       }
  375.  
  376.             // DIMM command (V2)
  377.             if( (Offset >= 0x84000000) && (Offset <= 0x8400005F) )
  378.             {
  379.                 u32 dimmoffset = Offset - 0x84000000;
  380.                 memcpy( memory.GetPointer(Address), media_buffer + dimmoffset, Length );
  381.  
  382.                 //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: Read MEDIA BOARD COMM AREA (2) ({:08x})", dimmoffset );
  383.                 PrintMBBuffer( Address, Length );
  384.                 return 0;
  385.       }
  386.  
  387.       // DIMM command (V2)
  388.       if( Offset == 0x88000000 )
  389.       {
  390.         u32 dimmoffset = Offset - 0x88000000;
  391.  
  392.         memset(media_buffer, 0, 0x20);
  393.  
  394.         INFO_LOG_FMT(DVDINTERFACE, "GC-AM: Execute command:{:03X}", *(u16*)(media_buffer + 0x202));
  395.  
  396.         switch( *(u16*)(media_buffer + 0x202) )
  397.         {
  398.           case 1:
  399.             *(u32*)(media_buffer) = 0x1FFF8000;
  400.             break;
  401.           default:
  402.             break;
  403.         }
  404.  
  405.         memcpy( memory.GetPointer(Address), media_buffer + dimmoffset, Length );
  406.  
  407.         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: Read MEDIA BOARD COMM AREA (?) ({:08x})", dimmoffset);
  408.         PrintMBBuffer(Address, Length);
  409.         return 0;
  410.       }
  411.  
  412.       // DIMM command (V2)
  413.       if ((Offset >= 0x89000000) && (Offset <= 0x89000200))
  414.       {
  415.         u32 dimmoffset = Offset - 0x89000000;
  416.         memcpy(memory.GetPointer(Address), media_buffer + dimmoffset, Length);
  417.  
  418.         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: Read MEDIA BOARD COMM AREA (3) ({:08x})", dimmoffset);
  419.         PrintMBBuffer(Address, Length);
  420.         return 0;
  421.       }
  422.  
  423.             // DIMM memory (8MB)
  424.             if( (Offset >= 0xFF000000) && (Offset <= 0xFF800000) )
  425.             {
  426.                 u32 dimmoffset = Offset - 0xFF000000;
  427.         m_dimm->Seek(dimmoffset, File::SeekOrigin::Begin);
  428.                 m_dimm->ReadBytes( memory.GetPointer(Address), Length );
  429.                 return 0;
  430.             }
  431.             // Network control
  432.             if( (Offset == 0xFFFF0000) && (Length == 0x20) )
  433.             {
  434.         m_netctrl->Seek(0, File::SeekOrigin::Begin);
  435.                 m_netctrl->ReadBytes( memory.GetPointer(Address), Length );
  436.                 return 0;
  437.             }
  438.  
  439.             // Max GC disc offset
  440.             if( Offset >= 0x57058000 )
  441.             {
  442.                 PanicAlertFmtT("Unhandled Media Board Read:{0:08x}", Offset );
  443.             }
  444.  
  445.       if (FIRMWAREMAP)
  446.       {
  447.         if (m_segaboot)
  448.         {
  449.           DICMDBUF[1] &= ~0x00100000;
  450.           DICMDBUF[1] -= 0x20;
  451.         }
  452.         memcpy(memory.GetPointer(Address), firmware + Offset, Length);
  453.         return 0;
  454.       }
  455.  
  456.       if (m_dimm_disc)
  457.       {
  458.         memcpy(memory.GetPointer(Address), m_dimm_disc + Offset, Length);
  459.         return 0;
  460.       }
  461.  
  462.       return 1;
  463.             break;
  464.         // Write
  465.         case 0xAA:
  466.             if( (Offset == 0x00600000 ) && (Length == 0x20) )
  467.             {
  468.                 FIRMWAREMAP = 1;
  469.                 return 0;
  470.             }
  471.             if( (Offset == 0x00700000 ) && (Length == 0x20) )
  472.             {
  473.                 FIRMWAREMAP = 1;
  474.                 return 0;
  475.             }
  476.             if(FIRMWAREMAP)
  477.             {
  478.                 // Firmware memory (2MB)
  479.                 if( (Offset >= 0x00400000) && (Offset <= 0x600000) )
  480.                 {
  481.                     u32 fwoffset = Offset - 0x00400000;
  482.                     memcpy( firmware + fwoffset, memory.GetPointer(Address), Length );
  483.                     return 0;
  484.                 }
  485.             }
  486.             // Network configuration
  487.             if( (Offset == 0x00000000) && (Length == 0x80) )
  488.             {
  489.         m_netcfg->Seek(0, File::SeekOrigin::Begin);
  490.                 m_netcfg->WriteBytes( memory.GetPointer(Address), Length );
  491.         m_netcfg->Flush();
  492.                 return 0;
  493.       }
  494.       // Extra Settings
  495.       // media crc check on/off
  496.       if ((Offset == 0x1FFEFFE0) && (Length == 0x20))
  497.       {
  498.         m_extra->Seek(0, File::SeekOrigin::Begin);
  499.         m_extra->WriteBytes(memory.GetPointer(Address), Length);
  500.         m_extra->Flush();
  501.         return 0;
  502.       }
  503.             // Backup memory (8MB)
  504.             if( (Offset >= 0x000006A0) && (Offset <= 0x00800000) )
  505.             {
  506.         m_backup->Seek(Offset, File::SeekOrigin::Begin);
  507.         m_backup->WriteBytes(memory.GetPointer(Address), Length);
  508.         m_backup->Flush();
  509.                 return 0;
  510.             }
  511.             // DIMM memory (8MB)
  512.             if( (Offset >= 0x1F000000) && (Offset <= 0x1F800000) )
  513.             {
  514.                 u32 dimmoffset = Offset - 0x1F000000;
  515.         m_dimm->Seek(dimmoffset, File::SeekOrigin::Begin);
  516.         m_dimm->WriteBytes(memory.GetPointer(Address), Length);
  517.         m_dimm->Flush();
  518.                 return 0;
  519.             }
  520.             // Network command
  521.             if( (Offset >= NetworkCommandAddress) && (Offset <= 0x1F8003FF) )
  522.             {
  523.                 u32 offset = Offset - NetworkCommandAddress;
  524.  
  525.                 memcpy(network_command_buffer + offset, memory.GetPointer(Address), Length);
  526.  
  527.         INFO_LOG_FMT(DVDINTERFACE, "GC-AM: Write NETWORK COMMAND BUFFER ({:08x},{})", Offset, Length);
  528.                 PrintMBBuffer( Address, Length );
  529.                 return 0;
  530.       }
  531.       // Network buffer
  532.       if ((Offset >= 0x1FA00000) && (Offset <= 0x1FA0FFFF))
  533.       {
  534.         u32 offset = Offset - 0x1FA00000;
  535.  
  536.         memcpy(network_buffer + offset, memory.GetPointer(Address), Length);
  537.  
  538.         INFO_LOG_FMT(DVDINTERFACE, "GC-AM: Write NETWORK BUFFER (1) ({:08x},{})", Offset, Length);
  539.         PrintMBBuffer(Address, Length);
  540.         return 0;
  541.       }
  542.       // Network buffer
  543.       if ((Offset >= 0x1FD00000) && (Offset <= 0x1FD0FFFF))
  544.       {
  545.         u32 offset = Offset - 0x1FD00000;
  546.  
  547.         memcpy(network_buffer + offset, memory.GetPointer(Address), Length);
  548.  
  549.         INFO_LOG_FMT(DVDINTERFACE, "GC-AM: Write NETWORK BUFFER (2) ({:08x},{})", Offset, Length);
  550.         PrintMBBuffer(Address, Length);
  551.         return 0;
  552.       }
  553.  
  554.             // DIMM command, used when inquiry returns 0x21000000
  555.             if( (Offset >= 0x1F900000) && (Offset <= 0x1F90003F) )
  556.             {
  557.                 u32 dimmoffset = Offset - 0x1F900000;
  558.                 memcpy( media_buffer + dimmoffset, memory.GetPointer(Address), Length );
  559.  
  560.                 INFO_LOG_FMT(DVDINTERFACE, "GC-AM: Write MEDIA BOARD COMM AREA (1) ({:08x})", dimmoffset );
  561.                 PrintMBBuffer( Address, Length );
  562.                 return 0;
  563.             }
  564.  
  565.             // DIMM command, used when inquiry returns 0x29000000
  566.             if( (Offset >= 0x84000000) && (Offset <= 0x8400005F) )
  567.       {
  568.         u32 dimmoffset = Offset - 0x84000000;
  569.         INFO_LOG_FMT(DVDINTERFACE, "GC-AM: Write MEDIA BOARD COMM AREA (2) ({:08x})", dimmoffset);
  570.         PrintMBBuffer(Address, Length);
  571.  
  572.         u8 cmd_flag = memory.Read_U8(Address);
  573.  
  574.         if (dimmoffset == 0x20 && cmd_flag != 0 )
  575.         {
  576.           m_v2_dma_adr = Address;
  577.         }
  578.  
  579.         //if (dimmoffset == 0x40 && cmd_flag == 0)
  580.         //{
  581.         //  INFO_LOG_FMT(DVDINTERFACE, "GCAM: PC:{:08x}", PC);
  582.         //  PowerPC::breakpoints.Add( PC+8, false );
  583.         //}
  584.  
  585.                 if( dimmoffset == 0x40 && cmd_flag == 1 )
  586.         {
  587.           // Recast for easier access
  588.           u32* media_buffer_in_32 = (u32*)(media_buffer + 0x20);
  589.           u16* media_buffer_in_16 = (u16*)(media_buffer + 0x20);
  590.           u32* media_buffer_out_32 = (u32*)(media_buffer);
  591.           u16* media_buffer_out_16 = (u16*)(media_buffer);
  592.  
  593.                     INFO_LOG_FMT(DVDINTERFACE, "GC-AM: Execute command:{:03X}", media_buffer_in_16[1] );
  594.  
  595.                     memset(media_buffer, 0, 0x20);
  596.  
  597.           media_buffer_out_32[0] = media_buffer_in_32[0] | 0x80000000;  // Set command okay flag
  598.  
  599.           for (u32 i = 0; i < 0x20; i += 4)
  600.           {
  601.             *(u32*)(media_buffer + 0x40 + i) = *(u32*)(media_buffer);
  602.           }
  603.  
  604.           //memory.Write_U8( 0xA9, m_v2_dma_adr + 0x20 );
  605.  
  606.                     switch (media_buffer_in_16[1])
  607.           {
  608.           // ?
  609.           case 0x000:
  610.             media_buffer_out_32[1] = 1;
  611.             break;
  612.           // NAND size
  613.           case 0x001:
  614.             media_buffer_out_32[1] = 0x1FFF8000;
  615.             break;
  616.           // Loading Progress
  617.                     case 0x100:
  618.                         // Status
  619.             media_buffer_out_32[1] = 5;
  620.                         // Progress in %
  621.             media_buffer_out_32[2] = 100;
  622.             break;
  623.           // SegaBoot version: 3.09
  624.           case 0x101:
  625.             // Version
  626.             media_buffer_out_16[2] = Common::swap16(0x0309);
  627.             // Unknown
  628.             media_buffer_out_16[3] = 2;
  629.             media_buffer_out_32[2] = 0x4746; // "GF"
  630.             media_buffer_out_32[4] = 0xFF;
  631.             break;
  632.           // System flags
  633.           case 0x102:
  634.             // 1: GD-ROM
  635.             media_buffer[4] = 0;
  636.             media_buffer[5] = 1;
  637.             // enable development mode (Sega Boot)
  638.             // This also allows region free booting
  639.             media_buffer[6] = 1;
  640.             media_buffer_out_16[4] = 0;  // Access Count
  641.             // Only used when inquiry 0x29
  642.             /*
  643.               0: NAND/MASK BOARD(HDD)
  644.               1: NAND/MASK BOARD(MASK)
  645.               2: NAND/MASK BOARD(NAND)
  646.               3: NAND/MASK BOARD(NAND)
  647.               4: DIMM BOARD (TYPE 3)
  648.               5: DIMM BOARD (TYPE 3)
  649.               6: DIMM BOARD (TYPE 3)
  650.               7: N/A
  651.               8: Unknown
  652.             */
  653.             media_buffer[7] = 1;
  654.             break;
  655.           // Media board serial
  656.           case 0x103:
  657.             memcpy(media_buffer + 4, "A85E-01A62204904", 16);
  658.             break;
  659.           case 0x104:
  660.             media_buffer[4] = 1;
  661.             break;
  662.           }
  663.  
  664.  
  665.           memset(media_buffer + 0x20, 0, 0x20 );
  666.           return 0;
  667.                 }
  668.         else
  669.         {
  670.           memcpy(media_buffer + dimmoffset, memory.GetPointer(Address), Length);
  671.         }
  672.         return 0;
  673.             }
  674.  
  675.       // DIMM command, used when inquiry returns 0x29000000
  676.       if ((Offset >= 0x89000000) && (Offset <= 0x89000200))
  677.       {
  678.         u32 dimmoffset = Offset - 0x89000000;
  679.         INFO_LOG_FMT(DVDINTERFACE, "GC-AM: Write MEDIA BOARD COMM AREA (3) ({:08x})", dimmoffset );
  680.         PrintMBBuffer(Address, Length);
  681.  
  682.         memcpy(media_buffer + dimmoffset, memory.GetPointer(Address), Length);
  683.  
  684.         return 0;
  685.       }
  686.  
  687.       // Firmware Write
  688.       if ((Offset >= 0x84800000) && (Offset <= 0x84818000))
  689.       {
  690.         u32 dimmoffset = Offset - 0x84800000;
  691.  
  692.         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: Write Firmware ({:08x})", dimmoffset );
  693.         PrintMBBuffer(Address, Length);
  694.         return 0;
  695.       }
  696.  
  697.             // DIMM memory (8MB)
  698.             if( (Offset >= 0xFF000000) && (Offset <= 0xFF800000) )
  699.             {
  700.                 u32 dimmoffset = Offset - 0xFF000000;
  701.         m_dimm->Seek(dimmoffset, File::SeekOrigin::Begin);
  702.         m_dimm->WriteBytes(memory.GetPointer(Address), Length);
  703.         m_dimm->Flush();
  704.                 return 0;
  705.             }
  706.             // Network control
  707.             if( (Offset == 0xFFFF0000) && (Length == 0x20) )
  708.             {
  709.                 m_netctrl->Seek( 0, File::SeekOrigin::Begin );
  710.         m_netctrl->WriteBytes(memory.GetPointer(Address), Length);
  711.         m_netctrl->Flush();
  712.                 return 0;
  713.             }
  714.             // Max GC disc offset
  715.             if( Offset >= 0x57058000 )
  716.             {
  717.                 PrintMBBuffer( Address, Length );
  718.                 PanicAlertFmtT("Unhandled Media Board Write:{0:08x}", Offset );
  719.             }
  720.             break;
  721.         // Execute
  722.     case 0xAB:
  723.             if( (Offset == 0) && (Length == 0) )
  724.       {
  725.         // Recast for easier access
  726.         u32* media_buffer_in_32  = (u32*)(media_buffer + 0x20);
  727.         u16* media_buffer_in_16  = (u16*)(media_buffer + 0x20);
  728.         u32* media_buffer_out_32 = (u32*)(media_buffer);
  729.         u16* media_buffer_out_16 = (u16*)(media_buffer);
  730.  
  731.                 memset( media_buffer, 0, 0x20 );
  732.  
  733.                 media_buffer_out_16[0] = media_buffer_in_16[0];
  734.  
  735.                 // Command
  736.         media_buffer_out_16[1] = media_buffer_in_16[1] | 0x8000;  // Set command okay flag
  737.  
  738.                 if (media_buffer_in_16[1])
  739.           //NOTICE_LOG_FMT(DVDINTERFACE, "GCAM: Execute command:{:03X}", media_buffer_in_16[1]);
  740.  
  741.                 switch (media_buffer_in_16[1])
  742.                 {
  743.                     // ?
  744.                     case 0x000:
  745.             media_buffer_out_32[1] = 1;
  746.                         break;
  747.                     // DIMM size
  748.           case 0x001:
  749.             media_buffer_out_32[1] = 0x20000000;
  750.                         break;
  751.                     // Media board status
  752.                     /*
  753.                     0x00: "Initializing media board. Please wait.."
  754.                     0x01: "Checking network. Please wait..."
  755.                     0x02: "Found a system disc. Insert a game disc"
  756.                     0x03: "Testing a game program. {:d}%%"
  757.                     0x04: "Loading a game program. {:d}%%"
  758.                     0x05: go
  759.                     0x06: error xx
  760.                     */
  761.                     case 0x100:
  762.           {
  763.             // Fake loading the game to have a chance to enter test mode
  764.             static u32 status   = 4;
  765.             static u32 progress = 80;
  766.             // Status
  767.             media_buffer_out_32[1] = status;
  768.             // Progress in %
  769.             media_buffer_out_32[2] = progress;
  770.             if (progress < 100)
  771.             {
  772.               progress++;
  773.             }
  774.             else
  775.             {
  776.               status = 5;
  777.             }
  778.           }
  779.           break;
  780.                     // SegaBoot version: 3.11
  781.                     case 0x101:
  782.                         // Version
  783.             media_buffer_out_16[2] = Common::swap16(0x1103);
  784.                         // Unknown
  785.             media_buffer_out_16[3] = 1;
  786.             media_buffer_out_32[2] = 1;
  787.             media_buffer_out_32[4] = 0xFF;
  788.                         break;
  789.                     // System flags
  790.           case 0x102:
  791.             // 1: GD-ROM
  792.             media_buffer[4] = 1;
  793.             media_buffer[5] = 1;
  794.                         // Enable development mode (Sega Boot)
  795.             // This also allows region free booting
  796.                         media_buffer[6] = 1;
  797.             media_buffer_out_16[4] = 0;  // Access Count
  798.                         break;
  799.                     // Media board serial
  800.                     case 0x103:
  801.                         memcpy( media_buffer + 4, "A89E-27A50364511", 16 );
  802.                         break;
  803.                     case 0x104:
  804.                         media_buffer[4] = 1;
  805.                         break;
  806.                     // Hardware test
  807.                     case 0x301:
  808.                         // Test type
  809.                         /*
  810.                             0x01: Media board
  811.                             0x04: Network
  812.                         */
  813.                         //ERROR_LOG_FMT(DVDINTERFACE, "GC-AM: 0x301: ({:08x})", *(u32*)(media_buffer+0x24) );
  814.  
  815.                         //Pointer to a memory address that is directly displayed on screen as a string
  816.                         //ERROR_LOG_FMT(DVDINTERFACE, "GC-AM:        ({:08x})", *(u32*)(media_buffer+0x28) );
  817.  
  818.                         // On real system it shows the status about the DIMM/GD-ROM here
  819.                         // We just show "TEST OK"
  820.             memory.Write_U32(0x54534554, media_buffer_in_32[4] );
  821.             memory.Write_U32(0x004B4F20, media_buffer_in_32[4] + 4 );
  822.  
  823.                         media_buffer_out_32[1] = media_buffer_in_32[1];
  824.                         break;
  825.                     case 0x401:
  826.                     {
  827.             u32 fd        = media_buffer_in_32[2];
  828.             u32 addr_off  = media_buffer_in_32[3] - NetworkCommandAddress;
  829.             u32 len_off   = media_buffer_in_32[4] - NetworkCommandAddress;
  830.  
  831.             struct sockaddr* addr = (struct sockaddr*)(network_command_buffer + addr_off);
  832.             int* len              = (int*)(network_command_buffer + len_off);
  833.  
  834.             int ret = 0;
  835.             int err = 0;
  836.  
  837.             u32 timeout = Timeouts[0] / 1000;
  838.             while (timeout--)
  839.             {
  840.               ret = accept(fd, addr, (socklen_t*)len);
  841.               if (ret == EWOULDBLOCK)
  842.               {
  843.                   sleep(1);
  844.                   continue;
  845.               }
  846.               else
  847.               {
  848.                 // Set newly created socket non-blocking
  849. #ifdef WIN32
  850.                 u_long val = 1;
  851.                 ioctlsocket(fd, FIONBIO, &val);
  852. #else
  853.                 int flags = fcntl(fd, F_GETFL);
  854.                 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
  855. #endif
  856.                 break;
  857.               }
  858.             }
  859.  
  860.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: accept( {} ):{} ({})\n", fd, ret, err);
  861.             media_buffer_out_32[1] = ret;
  862.                     } break;
  863.                     case 0x402:
  864.                     {
  865.                         struct sockaddr_in addr;
  866.  
  867.                         u32 fd  = media_buffer_in_32[2];
  868.             u32 off = media_buffer_in_32[3] - NetworkCommandAddress;
  869.             u32 len = media_buffer_in_32[4];
  870.  
  871.                         memcpy( (void*)&addr, network_command_buffer + off, sizeof(struct sockaddr_in) );
  872.  
  873.                         addr.sin_family                 = Common::swap16(addr.sin_family);
  874.                         *(u32*)(&addr.sin_addr) = Common::swap32(*(u32*)(&addr.sin_addr));
  875.  
  876.             /*
  877.               Triforce games usually use hardcoded IPs
  878.               This is replaced to listen to the ANY address instead
  879.             */
  880.             addr.sin_addr.s_addr = INADDR_ANY;
  881.  
  882.                         int ret = bind( fd, (const sockaddr*)&addr, len );
  883.                         int err = 0;
  884.  
  885.             //if (ret < 0 )
  886.             //  PanicAlertFmt("Socket Bind Failed with{0}", err);
  887.  
  888.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: bind( {}, ({},{:08x}:{}), {} ):{} ({})\n", fd,
  889.                            //addr.sin_family, addr.sin_addr.s_addr,
  890.                            //Common::swap16(addr.sin_port), len, ret, err);
  891.  
  892.             media_buffer_out_32[1] = ret;
  893.                     } break;
  894.                     case 0x403:
  895.                     {
  896.             u32 fd = media_buffer_in_32[2];
  897.  
  898.             int ret = close(fd);
  899.  
  900.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: closesocket( {} ):{}\n", fd, ret);
  901.  
  902.             media_buffer_out_32[1] = ret;
  903.                     } break;
  904.                     case 0x404:
  905.                     {
  906.                         struct sockaddr_in addr;
  907.  
  908.                         u32 fd  = media_buffer_in_32[2];
  909.             u32 off = media_buffer_in_32[3] - NetworkCommandAddress;
  910.             u32 len = media_buffer_in_32[4];
  911.  
  912.             int ret = 0;
  913.             int err = 0;
  914.  
  915.                         memcpy( (void*)&addr, network_command_buffer + off , sizeof(struct sockaddr_in) );
  916.  
  917.             // CyCraft Connect IP, change to localhost
  918.             if (addr.sin_addr.s_addr == 1863035072)
  919.             {
  920.               addr.sin_addr.s_addr = 0x7F000001;
  921.             }
  922.  
  923.             // NAMCO Camera
  924.             if (addr.sin_addr.s_addr == 0xc0a81d68)
  925.             {
  926.               addr.sin_addr.s_addr = 0x7F000001;
  927.               addr.sin_family = htons(AF_INET); // fix family?
  928.             }
  929.  
  930.             addr.sin_family = Common::swap16(addr.sin_family);
  931.             *(u32*)(&addr.sin_addr) = Common::swap32(*(u32*)(&addr.sin_addr));
  932.  
  933.             u32 timeout = 10;
  934.             while(timeout--)
  935.             {
  936.               ret = connect(fd, (const sockaddr*)&addr, len);
  937.               if( ret == 0 )
  938.                 break;
  939.  
  940.               if (err == EWOULDBLOCK || err == EALREADY )
  941.               {
  942.                 sleep(1);
  943.                 continue;
  944.               }
  945.  
  946.               if (err == EISCONN)
  947.               {
  948.                 ret = 0;
  949.                 break;
  950.               }
  951.  
  952.             }
  953.  
  954.                         ////NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: connect( {}, ({},{}:{}), {} ):{} ({})\n", fd, addr.sin_family, inet_ntoa(addr.sin_addr), Common::swap16(addr.sin_port), len, ret, err);
  955.  
  956.             media_buffer_out_32[1] = ret;
  957.                     } break;
  958.                     // getIPbyDNS
  959.                     case 0x405:
  960.                     {
  961.                         //ERROR_LOG_FMT(DVDINTERFACE, "GC-AM: 0x405: ({:08x})", *(u32*)(media_buffer+0x24) );
  962.                         // Address of string
  963.                         //ERROR_LOG_FMT(DVDINTERFACE, "GC-AM:        ({:08x})", *(u32*)(media_buffer+0x28) );
  964.                         // Length of string
  965.                         //ERROR_LOG_FMT(DVDINTERFACE, "GC-AM:        ({:08x})", *(u32*)(media_buffer+0x2C) );
  966.  
  967.                         u32 offset = media_buffer_in_32[2] - NetworkCommandAddress;
  968.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: getIPbyDNS({})", (char*)(network_command_buffer + offset) );
  969.                     } break;
  970.                     // inet_addr
  971.                     case 0x406:
  972.                     {
  973.             char *IP            = (char*)(network_command_buffer + (media_buffer_in_32[2] - NetworkCommandAddress) );
  974.             u32 IPLength = media_buffer_in_32[3];
  975.  
  976.                         memcpy( media_buffer + 8, IP, IPLength );
  977.  
  978.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: inet_addr({})\n", IP );
  979.             media_buffer_out_32[1] = Common::swap32(inet_addr(IP));
  980.                     } break;
  981.           /*
  982.             0x407: ioctl
  983.           */
  984.                     case 0x408:
  985.                     {
  986.             u32 fd      = media_buffer_in_32[2];
  987.             u32 backlog = media_buffer_in_32[3];
  988.  
  989.                         int ret = listen( fd, backlog );
  990.  
  991.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: listen( {}, {} ):{:d}\n", fd, backlog, ret);
  992.  
  993.             media_buffer_out_32[1] = ret;
  994.                     } break;
  995.                     case 0x409:
  996.                     {
  997.             u32 fd  = media_buffer_in_32[2];
  998.             u32 off = media_buffer_in_32[3];
  999.             u16 len = media_buffer_in_32[4];
  1000.  
  1001.             int ret = 0;
  1002.             char* buffer = (char*)(network_buffer+off);
  1003.  
  1004.             if( off >= NetworkCommandAddress && off < 0x1FD00000 )
  1005.             {
  1006.               buffer = (char*)(network_command_buffer + off - NetworkCommandAddress);
  1007.  
  1008.               if( off + len > sizeof(network_command_buffer) )
  1009.               {
  1010.                 PanicAlertFmt("RECV: Buffer overrun:{0} {1} ", off, len);
  1011.               }
  1012.             }
  1013.             else
  1014.             {
  1015.               if (off + len > sizeof(network_buffer))
  1016.               {
  1017.                 PanicAlertFmt("RECV: Buffer overrun:{0} {1} ", off, len);
  1018.               }
  1019.             }
  1020.  
  1021.             u32 timeout = Timeouts[0] / 1000;
  1022.             int err = 0;
  1023.             while (timeout--)
  1024.             {
  1025.               ret = recv(fd, buffer, len, 0);
  1026.               if (ret >= 0)
  1027.                 break;
  1028.  
  1029.               if (err == EWOULDBLOCK)
  1030.               {
  1031.                 sleep(1);
  1032.                 continue;
  1033.               }
  1034.               break;
  1035.  
  1036.             }
  1037.  
  1038.             if( err == EWOULDBLOCK )
  1039.             {
  1040.               ret = 0;
  1041.             }
  1042.  
  1043.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: recv( {}, 0x{:08x}, {} ):{} {}\n", fd, off, len, ret, err);
  1044.  
  1045.             media_buffer_out_32[1] = ret;
  1046.                     } break;
  1047.                     // send
  1048.                     case 0x40A:
  1049.                     {
  1050.             u32 fd     = media_buffer_in_32[2];
  1051.             u32 offset = media_buffer_in_32[3];
  1052.             u32 len    = media_buffer_in_32[4];
  1053.  
  1054.             int ret = 0;
  1055.  
  1056.             if (offset >= NetworkBufferAddress1 && offset < 0x1FA01000)
  1057.             {
  1058.               offset -= NetworkBufferAddress1;
  1059.             }
  1060.             else if (offset >= NetworkBufferAddress2 && offset < 0x1FD01000)
  1061.             {
  1062.               offset -= NetworkBufferAddress2;
  1063.             }
  1064.             else
  1065.             {
  1066.               ERROR_LOG_FMT(DVDINTERFACE, "GC-AM: send(error) unhandled destination:{}\n", offset  );
  1067.             }
  1068.  
  1069.             ret = send(fd, (char*)(network_buffer + offset), len, 0);
  1070.             int err = 0;
  1071.  
  1072.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: send( {}, 0x{:08x}, {} ): {} {}\n", fd, offset, len, ret ,err );
  1073.  
  1074.                         media_buffer_out_32[1] = ret;
  1075.                     } break;
  1076.                     // socket - Protocol is not sent
  1077.                     case 0x40B:
  1078.                     {
  1079.             u32 fd   = media_buffer_in_32[2];
  1080.             u32 af   = media_buffer_in_32[2];
  1081.             u32 type = media_buffer_in_32[3];
  1082.  
  1083.             fd = socket(af, type, IPPROTO_TCP);
  1084.  
  1085.             // Set socket non-blocking
  1086. #ifdef WIN32
  1087.             u_long val = 1;
  1088.             ioctlsocket(fd, FIONBIO, &val);
  1089. #else
  1090.             int flags = fcntl( fd, F_GETFL );
  1091.             fcntl(fd, F_SETFL, flags | O_NONBLOCK);
  1092. #endif
  1093.  
  1094.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: socket( {}, {}, 6 ):{}\n", af, type, fd);
  1095.  
  1096.                         media_buffer_out_32[1] = fd;
  1097.             media_buffer_out_32[2] = media_buffer_in_32[2];
  1098.             media_buffer_out_32[3] = media_buffer_in_32[3];
  1099.             media_buffer_out_32[4] = media_buffer_in_32[4];
  1100.                     } break;
  1101.                     // select
  1102.                     case 0x40C:
  1103.                     {
  1104.             u32 nfds     = media_buffer_in_32[2];
  1105.             u32 NOffsetA = media_buffer_in_32[3] - NetworkCommandAddress;
  1106.             u32 NOffsetB = media_buffer_in_32[6] - NetworkCommandAddress;
  1107.  
  1108.             fd_set readfds_{};
  1109.             fd_set writefds_{};
  1110.  
  1111.             fd_set* readfds  = &readfds_;
  1112.             fd_set* writefds = &writefds_;
  1113.  
  1114.             // Either of these can be zero but select still expects two inputs
  1115.             if (media_buffer_in_32[3])
  1116.             {
  1117.               readfds = (fd_set*)(network_command_buffer + NOffsetA);
  1118.             }
  1119.  
  1120.             if (media_buffer_in_32[6])
  1121.             {
  1122.               writefds = (fd_set*)(network_command_buffer + NOffsetB);
  1123.             }
  1124.  
  1125.             FD_ZERO(writefds);
  1126.             FD_ZERO(readfds);
  1127.  
  1128.             FD_SET(nfds, readfds);
  1129.             FD_SET(nfds, writefds);
  1130.  
  1131.             timeval timeout;
  1132.             timeout.tv_sec = Timeouts[0] / 1000;
  1133.             timeout.tv_usec= 0;
  1134.  
  1135.             int ret = select( nfds, readfds, writefds, nullptr, &timeout );
  1136.  
  1137.             int err = 0;
  1138.  
  1139.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: select( 0x{:08x} 0x{:08x} 0x{:08x} ):{} {} \n", nfds, NOffsetA, NOffsetB, ret, err);
  1140.                         //hexdump( NetworkCMDBuffer, 0x40 );
  1141.  
  1142.                         media_buffer_out_32[1] = ret;
  1143.                     } break;
  1144.           /*
  1145.             0x40D: shutdown
  1146.           */
  1147.                     // setsockopt
  1148.                     case 0x40E:
  1149.                     {
  1150.                         int s            = (int)(media_buffer_in_32[2]);
  1151.             int level           =    (int)(media_buffer_in_32[3]);
  1152.             int optname         =    (int)(media_buffer_in_32[4]);
  1153.             const char* optval  =  (char*)(network_command_buffer + media_buffer_in_32[5] - NetworkCommandAddress );
  1154.             int optlen          =    (int)(media_buffer_in_32[6]);
  1155.  
  1156.                         int ret = setsockopt( s, level, optname, optval, optlen );
  1157.  
  1158.                         int err = 0;
  1159.  
  1160.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: setsockopt( {:d}, {:04x}, {}, {:p}, {} ):{:d} ({})\n", s, level, optname, optval, optlen, ret, err);
  1161.  
  1162.             media_buffer_out_32[1] = ret;
  1163.                     } break;
  1164.           /*
  1165.             0x40F: getsockopt
  1166.           */
  1167.                     case 0x410:
  1168.                     {
  1169.                         u32 fd       = media_buffer_in_32[2];
  1170.             u32 timeoutA = media_buffer_in_32[3];
  1171.             u32 timeoutB = media_buffer_in_32[4];
  1172.             u32 timeoutC = media_buffer_in_32[5];
  1173.  
  1174.             Timeouts[0] = timeoutA;
  1175.             Timeouts[1] = timeoutB;
  1176.             Timeouts[2] = timeoutC;
  1177.  
  1178.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: SetTimeOuts( {}, {}, {}, {} )\n", fd, timeoutA,  timeoutB, timeoutC );
  1179.  
  1180.                         media_buffer_out_32[1] = 0;
  1181.             media_buffer_out_32[3] = media_buffer_in_32[3];
  1182.             media_buffer_out_32[4] = media_buffer_in_32[4];
  1183.             media_buffer_out_32[5] = media_buffer_in_32[5];
  1184.                     } break;
  1185.           /*
  1186.             This excepts 0x46 to be returned
  1187.           */
  1188.                     case 0x411:
  1189.                     {
  1190.             u32 fd = media_buffer_in_32[2];
  1191.  
  1192.             //int ret = closesocket(fd);
  1193.  
  1194.                         //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: SetUnknownFlag( {} )\n", fd);
  1195.  
  1196.                         media_buffer_out_32[1] = 0x46;
  1197.                     } break;
  1198.           /*
  1199.             0x412: routeAdd
  1200.             0x413: routeDelete
  1201.             0x414: getParambyDHCPExec
  1202.           */
  1203.                     // Set IP
  1204.                     case 0x415:
  1205.                     {
  1206.             char* IP = (char*)( network_command_buffer + media_buffer_in_32[2] - NetworkCommandAddress );
  1207.                         //u32 IPLength  = (*(u32*)(media_buffer+0x2C));
  1208.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: modifyMyIPaddr({})\n", IP);
  1209.                     } break;
  1210.           /*
  1211. *           0x416: recvfrom
  1212.             0x417: sendto
  1213.             0x418: recvDimmImage
  1214.             0x419: sendDimmImage
  1215.           */
  1216.           /*
  1217.  
  1218.             This group of commands is used to establish a link connection.
  1219.             Only used by F-Zero AX.
  1220.             Uses UDP for connections.
  1221.           */
  1222.  
  1223.                     // Empty reply
  1224.                     case 0x601: // Init Link ?
  1225.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: 0x601");
  1226.                         break;
  1227.                     case 0x606: // Setup link?
  1228.                     {
  1229.             struct sockaddr_in addra, addrb;
  1230.             addra.sin_addr.s_addr = media_buffer_in_32[4];
  1231.             addrb.sin_addr.s_addr = media_buffer_in_32[5];
  1232.  
  1233.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: 0x606:");
  1234.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:  Size: ({}) ",   media_buffer_in_16[2] );                 // size
  1235.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:  Port: ({})",    Common::swap16(media_buffer_in_16[3]) ); // port
  1236.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:LinkNum:({:02x})",media_buffer[0x28] );                    // linknum
  1237.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:        ({:02x})",media_buffer[0x29] );
  1238.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:        ({:04x})",media_buffer_in_16[5] );
  1239.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:   IP:  ({})",    inet_ntoa( addra.sin_addr ) );           // IP
  1240.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:   IP:  ({})",    inet_ntoa( addrb.sin_addr ) );           // IP
  1241.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:        ({:08x})",Common::swap32(media_buffer_in_32[6]) ); // some RAM address
  1242.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:        ({:08x})",Common::swap32(media_buffer_in_32[7]) ); // some RAM address
  1243.  
  1244.                         media_buffer_out_32[1] = 0;
  1245.                     } break;
  1246.                     case 0x607: // Search other device?
  1247.                     {
  1248.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: 0x607: ({})", media_buffer_in_16[2] );
  1249.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:        ({})", media_buffer_in_16[3] );
  1250.             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM:        ({:08x})", media_buffer_in_32[2] );
  1251.  
  1252.                         u8* Data = (u8*)(network_buffer + media_buffer_in_32[2] - 0x1FD00000 );
  1253.  
  1254.                         for( u32 i=0; i < 0x20; i+=0x10 )
  1255.                         {
  1256.                             //NOTICE_LOG_FMT(DVDINTERFACE, "GC-AM: {:08x} {:08x} {:08x} {:08x}",    *(u32*)(Data+i),
  1257.                                                                                                                                                         //*(u32*)(Data+i+4),
  1258.                                                                                                                                                         //*(u32*)(Data+i+8),
  1259.                                                                                                                                                         //*(u32*)(Data+i+12) );
  1260.                         }
  1261.  
  1262.                         media_buffer[4] = 23;
  1263.                     }   break;
  1264.                     case 0x614:
  1265.                     {
  1266.                         //ERROR_LOG_FMT(DVDINTERFACE, "GC-AM: 0x614");
  1267.                     }   break;
  1268.                     default:
  1269.                         ERROR_LOG_FMT(DVDINTERFACE, "GC-AM: execute buffer UNKNOWN:{:03x}", *(u16*)(media_buffer+0x22) );
  1270.                         break;
  1271.                     }
  1272.  
  1273.                 memset( media_buffer + 0x20, 0, 0x20 );
  1274.                 return 0;
  1275.             }
  1276.  
  1277.             PanicAlertFmtT("Unhandled Media Board Execute:{0:08x}", *(u16*)(media_buffer + 0x22) );
  1278.             break;
  1279.     }
  1280.  
  1281.     return 0;
  1282. }
  1283.  
  1284. u32 GetMediaType(void)
  1285. {
  1286.   switch (GetGameType())
  1287.   {
  1288.     default:
  1289.     case FZeroAX: // Monster Ride is on a NAND
  1290.     case VirtuaStriker3:
  1291.     case VirtuaStriker4:
  1292.     case GekitouProYakyuu:
  1293.     case KeyOfAvalon:
  1294.         return GDROM;
  1295.         break;
  1296.  
  1297.     case MarioKartGP:
  1298.     case MarioKartGP2:
  1299.         return NAND;
  1300.         break;
  1301.   }
  1302. // never reached
  1303. }
  1304. u32 GetGameType(void)
  1305. {
  1306.   u64 gameid = 0;
  1307.   // Convert game ID into hex
  1308.   sscanf(SConfig::GetInstance().GetGameID().c_str(), "%s", (char*)&gameid);
  1309.  
  1310.   // This is checking for the real game IDs (not those people made up) (See boot.id within the game)
  1311.   switch (Common::swap32((u32)gameid))
  1312.   {
  1313.   // SBHA/SBGG - F-ZERO AX
  1314.   case 0x53424841:
  1315.   case 0x53424747:
  1316.       m_game_type = FZeroAX;
  1317.       break;
  1318.   // SBKJ/SBKP - MARIOKART ARCADE GP
  1319.   case 0x53424B50:
  1320.   case 0x53424B5A:
  1321.       m_game_type = MarioKartGP;
  1322.       break;
  1323.   // SBNJ/SBNL - MARIOKART ARCADE GP2
  1324.   case 0x53424E4A:
  1325.   case 0x53424E4C:
  1326.       m_game_type = MarioKartGP2;
  1327.       break;
  1328.   // SBEJ/SBEY - Virtua Striker 2002
  1329.   case 0x5342454A:
  1330.   case 0x53424559:
  1331.       m_game_type = VirtuaStriker3;
  1332.       break;
  1333.   // SBLJ/SBLK/SBLL - VIRTUA STRIKER 4 Ver.2006
  1334.   case 0x53424C4A:
  1335.   case 0x53424C4B:
  1336.   case 0x53424C4C:
  1337.   // SBHJ/SBHN/SBHZ - VIRTUA STRIKER 4 VER.A
  1338.   case 0x5342484A:
  1339.   case 0x5342484E:
  1340.   case 0x5342485A:
  1341.   // SBJA/SBJJ  - VIRTUA STRIKER 4
  1342.   case 0x53424A41:
  1343.   case 0x53424A4A:
  1344.       m_game_type = VirtuaStriker4;
  1345.       break;
  1346.   // SBFX/SBJN - Key of Avalon
  1347.   case 0x53424658:
  1348.   case 0x53424A4E:
  1349.       m_game_type = KeyOfAvalon;
  1350.       break;
  1351.   // SBGX - Gekitou Pro Yakyuu (DIMM Uprade 3.17 shares the same ID)
  1352.   case 0x53424758:
  1353.       m_game_type = GekitouProYakyuu;
  1354.       break;
  1355.   default:
  1356.       PanicAlertFmtT("Unknown game ID:{0:08x}, using default controls.", gameid);
  1357.   // GSBJ/G12U/RELS/RELJ - SegaBoot (does not have a boot.id)
  1358.   case 0x4753424A:
  1359.   case 0x47313255:
  1360.   case 0x52454C53:
  1361.   case 0x52454c4a:
  1362.       m_game_type = VirtuaStriker3;
  1363.       break;
  1364.   }
  1365.     return m_game_type;
  1366. }
  1367. void Shutdown( void )
  1368. {
  1369.   m_netcfg->Close();
  1370.   m_netctrl->Close();
  1371.   m_extra->Close();
  1372.   m_backup->Close();
  1373.     m_dimm->Close();
  1374.  
  1375.   if (m_dimm_disc)
  1376.   {
  1377.       delete[] m_dimm_disc;
  1378.       m_dimm_disc = nullptr;
  1379.   }
  1380. }
  1381.  
  1382. }
  1383.  
Advertisement
Add Comment
Please, Sign In to add comment