summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/tecmosys.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/tecmosys.cpp')
-rw-r--r--src/mame/machine/tecmosys.cpp235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/mame/machine/tecmosys.cpp b/src/mame/machine/tecmosys.cpp
new file mode 100644
index 00000000000..7f56a00b8c5
--- /dev/null
+++ b/src/mame/machine/tecmosys.cpp
@@ -0,0 +1,235 @@
+// license:BSD-3-Clause
+// copyright-holders:Farfetch'd,David Haywood,Tomasz Slanina
+/* tecmosys protection related functions */
+
+/*
+ The device validates a password,
+ then uploads the size of a code upload followed by the code upload itself.
+ After that, it uploads 4 ranges of code to checksum, followed by the 4 checksums.
+ The 68K does the checksumming, and returns the results to the protection device.
+
+ Apart from inital protection calls and code upload, the vblank in both games writes
+ info to the protection but they seem to ignore the returned data.
+ Maybe the protection is tied to something else, or maybe it was preliminary work on
+ further security.
+ This is what happens in the vblank:
+ - prot_w( 0xff )
+ - val = prot_r()
+ - prot_w( checksum1[val] )
+ (The area following checksum1 is the code upload in deroon, and active RAM in tkdensho,
+ so the value sent may be meaningless.)
+
+ There is provision for calling the protection read/write functions from two of the trap 0xf switch
+ statements in the 68K, but I don't see it being used anywhere.
+
+ It looks like the code upload is very plain, it can only be 0xff bytes long, and not contain the byte 0xff.
+ The checksum ranges can't contain 0xff either, although the checksum values can.
+ I'd be very interested in putting some trojan ROMs together if anyone has a board to run them on.
+ It might be possible to use one set of ROMs to get the checksum ranges,
+ and another set with dump code places outside those ranges.
+ You can get me at nuapete@hotmail.com
+*/
+
+#include "emu.h"
+#include "includes/tecmosys.h"
+
+enum DEV_STATUS
+{
+ DS_IDLE,
+ DS_LOGIN,
+ DS_SEND_CODE,
+ DS_SEND_ADRS,
+ DS_SEND_CHKSUMS,
+ DS_DONE
+};
+
+struct prot_data
+{
+ UINT8 passwd_len;
+ const UINT8* passwd;
+ const UINT8* code;
+ UINT8 checksum_ranges[17];
+ UINT8 checksums[4];
+};
+
+
+// deroon prot data
+static const UINT8 deroon_passwd[] = {'L','U','N','A',0};
+static const UINT8 deroon_upload[] = {0x02, 0x4e, 0x75, 0x00 }; // code length, code, 0x00 trailer
+static const struct prot_data deroon_data =
+{
+ 5,
+ deroon_passwd,
+ deroon_upload,
+ {
+ 0x10,0x11,0x12,0x13, // range 1 using static ranges from the ROM to avoid calculating sums.
+ 0x24,0x25,0x26,0x27, // range 2
+ 0x38,0x39,0x3a,0x3b, // range 3
+ 0x4c,0x4d,0x4e,0x4f, // range 4
+ 0x00, // trailer
+ },
+ { 0xa6, 0x29, 0x4b, 0x3f }
+};
+
+// tkdensho prot data
+static const UINT8 tkdensho_passwd[] = {'A','G','E','P','R','O','T','E','C','T',' ','S','T','A','R','T',0};
+static const UINT8 tkdensho_upload[] = {0x06, 0x4e, 0xf9, 0x00, 0x00, 0x22, 0xc4,0x00};
+static const struct prot_data tkdensho_data =
+{
+ 0x11,
+ tkdensho_passwd,
+ tkdensho_upload,
+ {
+ 0x10,0x11,0x12,0x13, // range 1
+ 0x24,0x25,0x26,0x27, // range 2
+ 0x38,0x39,0x3a,0x3b, // range 3
+ 0x4c,0x4d,0x4e,0x4f, // range 4
+ 0x00, // trailer
+ },
+ { 0xbf, 0xfa, 0xda, 0xda }
+};
+
+static const struct prot_data tkdensha_data =
+{
+ 0x11,
+ tkdensho_passwd,
+ tkdensho_upload,
+ {
+ 0x10,0x11,0x12,0x13, // range 1
+ 0x24,0x25,0x26,0x27, // range 2
+ 0x38,0x39,0x3a,0x3b, // range 3
+ 0x4c,0x4d,0x4e,0x4f, // range 4
+ 0x00, // trailer
+ },
+ { 0xbf, 0xfa, 0x21, 0x5d }
+};
+
+
+void tecmosys_state::prot_reset()
+{
+ m_device_read_ptr = 0;
+ m_device_status = DS_IDLE;
+ m_device_value = 0xff;
+}
+
+void tecmosys_state::prot_init(int which)
+{
+ switch (which)
+ {
+ case 0: m_device_data = &deroon_data; break;
+ case 1: m_device_data = &tkdensho_data; break;
+ case 2: m_device_data = &tkdensha_data; break;
+ }
+
+ machine().add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(FUNC(tecmosys_state::prot_reset),this));
+}
+
+READ16_MEMBER(tecmosys_state::prot_status_r)
+{
+ if (ACCESSING_BITS_8_15)
+ {
+ // Bit 7: 0 = ready to write
+ // Bit 6: 0 = ready to read
+ return 0;
+ }
+
+ return 0xc0; // simulation is always ready
+}
+
+WRITE16_MEMBER(tecmosys_state::prot_status_w)
+{
+ // deroon clears the status in one place.
+}
+
+
+READ16_MEMBER(tecmosys_state::prot_data_r)
+{
+ // prot appears to be read-ready for two consecutive reads
+ // but returns 0xff for subsequent reads.
+ UINT8 ret = m_device_value;
+ m_device_value = 0xff;
+ //logerror("- prot_r = 0x%02x\n", ret );
+ return ret << 8;
+}
+
+
+WRITE16_MEMBER(tecmosys_state::prot_data_w)
+{
+ // Only LSB
+ data >>= 8;
+
+ //logerror("+ prot_w( 0x%02x )\n", data );
+
+ switch( m_device_status )
+ {
+ case DS_IDLE:
+ if( data == 0x13 )
+ {
+ m_device_status = DS_LOGIN;
+ m_device_value = m_device_data->passwd_len;
+ m_device_read_ptr = 0;
+ break;
+ }
+ break;
+
+ case DS_LOGIN:
+ if( m_device_read_ptr >= m_device_data->passwd_len)
+ {
+ m_device_status = DS_SEND_CODE;
+ m_device_value = m_device_data->code[0];
+ m_device_read_ptr = 1;
+ }
+ else
+ m_device_value = m_device_data->passwd[m_device_read_ptr++] == data ? 0 : 0xff;
+ break;
+
+ case DS_SEND_CODE:
+ if( m_device_read_ptr >= m_device_data->code[0]+2 ) // + code_len + trailer
+ {
+ m_device_status = DS_SEND_ADRS;
+ m_device_value = m_device_data->checksum_ranges[0];
+ m_device_read_ptr = 1;
+ }
+ else
+ m_device_value = data == m_device_data->code[m_device_read_ptr-1] ? m_device_data->code[m_device_read_ptr++] : 0xff;
+ break;
+
+ case DS_SEND_ADRS:
+ if( m_device_read_ptr >= 16+1 ) //+ trailer
+ {
+ m_device_status = DS_SEND_CHKSUMS;
+ m_device_value = 0;
+ m_device_read_ptr = 0;
+ }
+ else
+ {
+ m_device_value = data == m_device_data->checksum_ranges[m_device_read_ptr-1] ? m_device_data->checksum_ranges[m_device_read_ptr++] : 0xff;
+ }
+ break;
+
+ case DS_SEND_CHKSUMS:
+ if( m_device_read_ptr >= 4 )
+ {
+ m_device_status = DS_DONE;
+ m_device_value = 0;
+ }
+ else
+ m_device_value = data == m_device_data->checksums[m_device_read_ptr] ? m_device_data->checksums[m_device_read_ptr++] : 0xff;
+ break;
+
+ case DS_DONE:
+ switch( data )
+ {
+ case 0xff: // trigger
+ case 0x00: // checksum1[val] tkdensho
+ case 0x20: // checksum1[val] deroon \ This is active RAM, so there may be more cases
+ case 0x01: // checksum1[val] deroon / that can be ignored
+ break;
+
+ default:
+ logerror( "Protection still in use??? w=%02x\n", data );
+ break;
+ }
+ break;
+ }
+}