/* Hey EMACS -*- linux-c -*- */ /* TiEmu - Tiemu Is an EMUlator * * Copyright (c) 2000-2001, Thomas Corvazier, Romain Lievin * Copyright (c) 2001-2003, Romain Lievin * Copyright (c) 2003, Julien Blache * Copyright (c) 2004, Romain Liévin * Copyright (c) 2005, Romain Liévin, Kevin Kofler * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /* Memory management: TI89/92+/V200/Titanium FLASH with Hardware Protection */ #include #include #include #include "libuae.h" #include "ports.h" #include "mem.h" #include "mem89.h" #include "hwprot.h" #include "ti68k_def.h" #include "ti68k_int.h" static uint32_t ba; // FLASH ROM base address (shortcut) static int access1; // protection access authorization (hw1) static int access2; // protection access authorization (hw2) static int crash; // access counter before crashing static int arch_mem_crash; // same #define IN_BOUNDS2(a,v,b) (((v) >= ((a)+ba)) && ((v) <= ((b)+ba))) #define HWP int hw_hwp_init(void) { tihw.protect = 0; ba = tihw.rom_base - 0x200000; access1 = access2 = crash = arch_mem_crash = 0; if (tihw.hw_type >= HW2) tihw.io2[0x13] = 0x18; return 0; } int hw_hwp_reset(void) { return 0; } int hw_hwp_exit(void) { return 0; } static void freeze_calc(void) { access1 = access2 = crash = 0; m68k_setstopped(1); } // note: "if(!(adr & 1))" is used to avoid multiple increment when reading/writing words. // This don't work for longs but I don't think protection is accessed by longs. /* Check whether instruction fetch is allowed at adr. The returned value can be used by breakpoints to determine the origin of violation. */ int hwp_fetch(uint32_t adr) { // protections (hw1) if(tihw.hw_type == HW1) { if(IN_BOUNDS2(0x390000+tihw.archive_limit*0x10000, adr, 0x3fffff)) // archive memory limit (hw1) { // three consecutive access to any adress >=$390000+limit*$10000 and <$400000 crashes the calc if(!(adr & 1)) arch_mem_crash++; if((tihw.hw_type == HW1) && (arch_mem_crash >= 4)) { freeze_calc(); return 1; } } } // protections (hw2) else { if(IN_BOUNDS(0x000000, adr, 0x03ffff)) // RAM page execution protection { if(tihw.ram_exec[adr >> 12]) { freeze_calc(); return 2; } } else if(IN_BOUNDS(0x040000, adr, 0x1fffff)) // RAM page execution protection { if(io2_bit_tst(6, 7)) { freeze_calc(); return 2; } } else if(IN_BOUNDS2(0x210000, adr, 0x1fffff + tihw.rom_size)) // FLASH page execution protection { if(adr >= (0x210000+ba + (uint32_t)tihw.io2[0x13]*0x10000)) { //printf(">> $%06x-%06x ", adr, 0x210000+ba + (uint32_t)tihw.io2[0x13]*0x10000); freeze_calc(); return 3; } } } return 0; } uint8_t hwp_get_byte(uint32_t adr) { #ifdef HWP // stealth I/O if(IN_BOUNDS(0x040000, adr, 0x07ffff)) // archive memory limit bit 0 (hw1) { if(!tihw.protect && (tihw.hw_type == HW1)) bit_clr(tihw.archive_limit, 0); } else if(IN_BOUNDS(0x080000, adr, 0x0bffff)) // archive memory limit bit 1 (hw1) { if(!tihw.protect && (tihw.hw_type == HW1)) bit_clr(tihw.archive_limit, 1); } else if(IN_BOUNDS(0x0c0000, adr, 0x0fffff)) // archive memory limit bit 2 (hw1) { if(!tihw.protect && (tihw.hw_type == HW1)) bit_clr(tihw.archive_limit, 2); } else if(IN_BOUNDS(0x180000, adr, 0x1bffff)) // screen power control { //tihw.on_off = 0; } else if(IN_BOUNDS(0x1c0000, adr, 0x1fffff)) // protection enable { // FIXME: >=7 is probably too lax, but the actual number can vary a lot due to the prefetch. // I guess we should check instructions rather than access counts on HW2. if((access1 >= 3) || (++access2 >= 7)) { tihw.protect = !0; access1 = access2 = 0; } else if(tihw.hw_type == HW1) { // any four consecutive access to $1c0000-1fffff crashes a HW1 calc if(!(adr & 1)) crash++; if(crash >= 4) { freeze_calc(); } } } else if(IN_BOUNDS2(0x200000, adr, 0x20ffff)) // protection access authorization { if(tihw.hw_type == HW1) if(!(adr & 1)) access1++; if(tihw.hw_type != HW1) if(!(adr & 1)) access2++; } else if(IN_BOUNDS2(0x210000, adr, 0x211fff)) // certificate (read protected) { if(tihw.protect) return 0x14; } else if(IN_BOUNDS2(0x212000, adr, 0x217fff)) // protection access authorization { if(tihw.hw_type == HW1) if(!(adr & 1)) access1++; if(tihw.hw_type != HW1) if(!(adr & 1)) access2++; } else if(IN_BOUNDS2(0x218000, adr, 0x219fff)) // read protected { if(tihw.protect) return 0x14; } else if(IN_BOUNDS2(0x21a000, adr, 0x21ffff)) // protection access authorization { if(tihw.hw_type == HW1) if(!(adr & 1)) access1++; if(tihw.hw_type != HW1) if(!(adr & 1)) access2++; } else { access1 = access2 = 0; crash = arch_mem_crash = 0; } #endif // memory return mem_get_byte_ptr(adr); } uint16_t hwp_get_word(uint32_t adr) { // We can't implement this in terms of hwp_get_byte, because the FlashROM // hardware behaves differently for byte and word reads (see flash.c). #ifdef HWP // stealth I/O if(IN_BOUNDS(0x040000, adr, 0x07ffff)) // archive memory limit bit 0 (hw1) { if(!tihw.protect && (tihw.hw_type == HW1)) bit_clr(tihw.archive_limit, 0); } else if(IN_BOUNDS(0x080000, adr, 0x0bffff)) // archive memory limit bit 1 (hw1) { if(!tihw.protect && (tihw.hw_type == HW1)) bit_clr(tihw.archive_limit, 1); } else if(IN_BOUNDS(0x0c0000, adr, 0x0fffff)) // archive memory limit bit 2 (hw1) { if(!tihw.protect && (tihw.hw_type == HW1)) bit_clr(tihw.archive_limit, 2); } else if(IN_BOUNDS(0x180000, adr, 0x1bffff)) // screen power control { //tihw.on_off = 0; } else if(IN_BOUNDS(0x1c0000, adr, 0x1fffff)) // protection enable { access2 += 2; // FIXME: >=7 is probably too lax, but the actual number can vary a lot due to the prefetch. // I guess we should check instructions rather than access counts on HW2. if((access1 >= 3) || (access2 >= 7)) { tihw.protect = !0; access1 = access2 = 0; } else if(tihw.hw_type == HW1) { // any four consecutive access to $1c0000-1fffff crashes a HW1 calc crash++; if(crash >= 4) { freeze_calc(); } } } else if(IN_BOUNDS2(0x200000, adr, 0x20ffff)) // protection access authorization { if(tihw.hw_type == HW1) access1++; else access2++; } else if(IN_BOUNDS2(0x210000, adr, 0x211fff)) // certificate (read protected) { if(tihw.protect) return 0x1414; } else if(IN_BOUNDS2(0x212000, adr, 0x217fff)) // protection access authorization { if(tihw.hw_type == HW1) access1++; else access2++; } else if(IN_BOUNDS2(0x218000, adr, 0x219fff)) // read protected { if(tihw.protect) return 0x1414; } else if(IN_BOUNDS2(0x21a000, adr, 0x21ffff)) // protection access authorization { if(tihw.hw_type == HW1) access1++; else access2++; } else { access1 = access2 = 0; crash = arch_mem_crash = 0; } #endif // memory return mem_get_word_ptr(adr); } uint32_t hwp_get_long(uint32_t adr) { return (hwp_get_word(adr+0) << 16) | hwp_get_word(adr+2); } void hwp_put_byte(uint32_t adr, uint8_t arg) { #ifdef HWP // stealth I/O if(IN_BOUNDS(0x040000, adr, 0x07ffff)) // archive memory limit bit 0 (hw1) { if(!tihw.protect && (tihw.hw_type == HW1)) bit_set(tihw.archive_limit, 0); } else if(IN_BOUNDS(0x080000, adr, 0x0bffff)) // archive memory limit bit 1 (hw1) { if(!tihw.protect && (tihw.hw_type == HW1)) bit_set(tihw.archive_limit, 1); } else if(IN_BOUNDS(0x0c0000, adr, 0x0fffff)) // archive memory limit bit 2 (hw1) { if(!tihw.protect && (tihw.hw_type == HW1)) bit_set(tihw.archive_limit, 2); } else if(IN_BOUNDS(0x180000, adr, 0x1bffff)) // screen power control { //tihw.on_off = !0; } else if(IN_BOUNDS(0x1c0000, adr, 0x1fffff)) // protection disable { // FIXME: >=7 is probably too lax, but the actual number can vary a lot due to the prefetch. // I guess we should check instructions rather than access counts on HW2. if((access1 >= 3) || (++access2 >= 7)) { tihw.protect = 0; access1 = access2 = 0; } else if(tihw.hw_type == HW1) { // any four consecutive accesses to $1c0000-1fffff crash an HW1 calc if(!(adr & 1)) crash++; if(crash >= 4) { freeze_calc(); } } } else if(IN_BOUNDS2(0x200000, adr, 0x20ffff)) // protection access authorization { if(tihw.hw_type == HW1) if(!(adr & 1)) access1++; if(tihw.hw_type != HW1) if(!(adr & 1)) access2++; // don't write on boot code return; } else if(IN_BOUNDS2(0x210000, adr, 0x211fff)) // certificate (read protected) { } else if(IN_BOUNDS2(0x212000, adr, 0x217fff)) // protection access authorization { if(tihw.hw_type == HW1) if(!(adr & 1)) access1++; if(tihw.hw_type != HW1) if(!(adr & 1)) access2++; } else if(IN_BOUNDS2(0x218000, adr, 0x219fff)) // read protected { } else if(IN_BOUNDS2(0x21a000, adr, 0x21ffff)) // protection access authorization { if(tihw.hw_type == HW1) if(!(adr & 1)) access1++; if(tihw.hw_type != HW1) if(!(adr & 1)) access2++; } else { access1= access2 = 0; crash = arch_mem_crash = 0; } #endif // memory mem_put_byte_ptr(adr, arg); return; } void hwp_put_word(uint32_t adr, uint16_t arg) { hwp_put_byte(adr+0, MSB(arg)); hwp_put_byte(adr+1, LSB(arg)); } void hwp_put_long(uint32_t adr, uint32_t arg) { hwp_put_word(adr+0, MSW(arg)); hwp_put_word(adr+2, LSW(arg)); }