1 /*
2  * libtilemcore - Graphing calculator emulation library
3  *
4  * Copyright (C) 2009-2011 Benjamin Moody
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include "tilem.h"
28 
certificate_valid(byte * cert)29 static int certificate_valid(byte* cert)
30 {
31 	int i, n;
32 
33 	if (cert[0] != 0)
34 		return 0;
35 
36 	i = 1;
37 
38 	/* check that the actual certificate area consists of valid
39 	   certificate fields */
40 	while (cert[i] <= 0x0F) {
41 		switch (cert[i + 1] & 0x0F) {
42 		case 0x0D:
43 			n = cert[i + 2] + 3;
44 			break;
45 		case 0x0E:
46 			n = (cert[i + 2] << 8) + cert[i + 3] + 4;
47 			break;
48 		case 0x0F:
49 			n = 6;
50 			break;
51 		default:
52 			n = (cert[i + 1] & 0xf) + 2;
53 		}
54 		i += n;
55 		if (i >= 0x2000)
56 			return 0;
57 	}
58 
59 	/* check that the fields end with FF */
60 	if (cert[i] != 0xFF)
61 		return 0;
62 
63 	/* if there are fields present, assume the certificate is OK */
64 	if (i > 1)
65 		return 1;
66 
67 	/* no fields present -> this could be an incompletely-patched
68 	   certificate from an older version of TilEm; verify that the
69 	   next 4k bytes are truly empty */
70 	while (i < 0x1000) {
71 		if (cert[i] != 0xFF)
72 			return 0;
73 		i++;
74 	}
75 
76 	return 1;
77 }
78 
tilem_calc_fix_certificate(TilemCalc * calc,byte * cert,int app_start,int app_end,unsigned exptab_offset)79 void tilem_calc_fix_certificate(TilemCalc* calc, byte* cert,
80                                 int app_start, int app_end,
81                                 unsigned exptab_offset)
82 {
83 	int i, base, max_apps, page;
84 	unsigned insttab_offset = 0x1fe0;
85 
86 	/* If the ROM was dumped from an unpatched OS, the certificate
87 	   needs to be patched for some calculator functions to
88 	   work. */
89 
90 	/* First, check if the certificate is already valid */
91 
92 	if (cert[0x2000] == 0)
93 		base = 0x2000;
94 	else
95 		base = 0;
96 
97 	if (certificate_valid(cert + base)) {
98 		return;
99 	}
100 
101 	tilem_message(calc, "Repairing certificate area...");
102 
103 	memset(cert, 0xff, 16384);
104 
105 	cert[0] = 0;
106 
107 	cert[insttab_offset] = 0xfe;
108 
109 	if (app_start < app_end)
110 		max_apps = app_end - app_start + 1;
111 	else
112 		max_apps = app_start - app_end + 1;
113 
114 	for (i = 0; i < max_apps; i++) {
115 		if (app_start < app_end)
116 			page = app_start + i;
117 		else
118 			page = app_start - i;
119 
120 		/* Clear installed bit / set expiration count for
121 		   existing apps.  (If this incorrectly detects pages
122 		   that aren't really apps, don't worry about it;
123 		   better to err on the side of caution.) */
124 		if (calc->mem[page << 14] != 0x80
125 		    || calc->mem[(page << 14) + 1] != 0x0f)
126 			continue;
127 
128 		tilem_message(calc, "Found application at page %02x (index %d)",
129 		              page, i);
130 
131 		cert[insttab_offset + ((i + 1) / 8)] &= ~(1 << ((i + 1) % 8));
132 
133 		cert[exptab_offset + 2 * i] = 0x80;
134 		cert[exptab_offset + 2 * i + 1] = 0x00;
135 	}
136 }
137