-[ 0x0E ]--------------------------------------------------------------------
-[ El apasionante mundo de los mviles ]-------------------------------------
-[ by FCA00000 ]-----------------------------------------------------SET-30--

Bienvenido a un nuevo capitulo de "El apasionante mundo de los mviles".

PRESENTACION
*************
En episodios anteriores hemos visto cosas que estn alrededor del mvil:
comandos AT, SMS, SIM Toolkit, ficheros en el SIM, simulacion de teclas, ...
Ahora voy a ver algo que me permite cambiar el funcionamiento interno del mvil.
Como casi todos los cacharros modernos con un mnimo de funcionalidad, el
corazn del mvil es un chip con acceso a una memoria y a unos dispositivos.
Los perifricos con los que se comunica el chip son:
-radio
-teclado
-pantalla
-iluminacin
-altavoz
-micrfono
-infrarrojos
-puerto serie
-cmara
-batera
-memoria extrable
Esto lo cuento para que veas que es un dispositivo realmente potente, y todo
est integrado en un espacio realmente pequeo.
Piensa simplemente en lo que ocupara (y lo que costara) instalar todos
estos dispositivos en un ordenador. Claro que en este caso son ms grandes
y tienen mayores capacidades.
Lo que quiero decir es que si intentas hacer un emulador de un mvil para un
ordenador de sobremesa, posiblemente llevara mucho trabajo.

En realidad no es un dispositivo tan pequeo. En el caso de mi
Siemens C45i, contiene un microprocesador C166 de 16 bits, con memoria interna
de 4Kb, y memoria flash externa de 4 Mg, adems de otra memoria de 1 Mg.
Ahora recuerda los tiempos del Spectrum, que tenian 8 bits, 16 Kb de ROM, y
48 Kb de RAM. Y era (es) una mquina realmente magnfica, con juegos
extraordinarios.
El micro funciona a una velocidad de 25MHz, tiene 76 lineas de entrada/salida,
16 canales de captura de datos, convertidor A/D, unidades de multiplicacin,
bus externo, 58 modos de interrupcion basado en niveles y permisos, 5 timers,
puerto serie incorporado, con arquitectura parcialmente RISC y CISC.
Todo ello, con un consumo mnimo de batera y en un espacio reducido.

Los fabricantes de mviles entienden que los programas que ellos hacen
tambin pueden tener fallos, as que dejan abierta la posibilidad de
cargar nuevas versiones del software.

ACTUALIZACION
*************
La pgina web de Siemens contiene actualizaciones para los diversos modelos.
Para el modelo S45, la ltima version oficial es v21 , aunque yo creo que
solo existen v5, v16, v18, y v21.
Pero lo interesante es que existe un mtodo para modificar el programa incluido.
En cierto modo, es una actualizacin del Sistema Operativo.

Para ello hay que conectar el mvil con un ordenador mediante un cable
serie, que viene incluido con el telfono.
Mirando con un sniffer de puerto los comandos que se intercambian, veo que
usa AT+SQWE=1 , lo que significa que pasa a un modo especial llamado BFB.
Este mismo protocolo se usa para meter archivos en la memoria FLEXMEM, por
ejemplo juegos en WML (no java) o notas de voz.
Simplemente que para en este caso los comandos son mas potentes.

Para acceder a la actualizacion del SO, se pasa a un modo llamado bootstrap.
Bsicamente, se semi-apaga el mvil. Luego se enva un programa pequeo
desde el ordenador hacia el mvil, y ese programa se ejecuta.
Cuando digo semi-apagar me refiero a que los dispositivos electrnicos nunca
se apagan del todo. Simplemente entran en un modo de ahorro de batera.
Cuando reciben un seal, se vuelven a poner en marcha. Esta seal viene
generada por hardware. Puede ser la pulsacin de la tecla de encendido, o
un impulso mandado a traves de algun cable.
Esto explica porqu cuando conecto el cargador de batera, el mvil es
capaz de mostrar un dibujo con una pila.

Para que el bootstrap se pueda enviar, el mvil debe enviar una seal
indicando que est listo para recibir. Esta seal va por el pin 4 del cable.
Pero el cable de datos original tiene cortado ese pin, as que hace falta un
cable especial. Cualquier persona que desee liberar un mvil debe tener ese
cable, y un programa que altera la EPROM, eliminando una rutina de chequeo.
Existen mltiples programas de estos, y hacer el cable no es complicado de
construir si se tienen unos mnimos conocimientos de soldadura.
Tambien es posible comprarlo, claro.

El cable no es el mismo para todos los mviles. Por ejemplo, en los
modelos S65, la seal va por el pin 2. 
Por una casualidad del destino, prob mi cable de datos del S45 con el
modelo C35, y funciona. No s si es porque el cable sirve, o porque el
telfono ya estaba parcheado.
Para los atrevidos, el cable original solo necesita ser modificado para que 
d la seal de alimentacion por el pin 4. El cargador de batera incluye
esta senl por el pin 3, as que si conectas el pin 1 (masa) del cargador
con el pin 1 del cable de datos, y el pin 3 del cargador con el pin 4 del
cable de datos, ya te has hecho tu propio cable.
Al menos a m me funciona con el modelo S45. Y no, no me hago responsable
de lo que puede pasar si haces la prueba y lo conectas mal.

Existe una tecnica para usar el cable por primera vez, parchear el mvil, y
luego no hace falta mas el cable. Pero esto lo explicar mas tarde.

As que las herramientas hardware necesarios son un ordenador con puerto
serie, un cable de S45, un telfono C35 o similar.
Las herramientas software son Windows (algunos de los programas slo
funcionan en este SO), y los programas:

Siemens Flashing Tools (zSiemenz), por RizaPN, para volcar y grabar la EPROM
v_klay, hecho por ValeraVi, para meter un parche
Smelter, hecho por avkiev, para investigar lo que hay en un archivo EPROM
SPC2, hecho por ACiD [mrp], para modificar los dibujos
sfe, por RizaPN, para desensamblar y tracear un archivo EPROM, y hacer parches
Siemens EEPROM tool , por Skylord, para ver lo que hay en un archivo EPROM
AT Debugger, por BoBa! , para ver lo que pasa por la memoria.
Siemens Debugger, por ACiD y SiNgle, para monitorear programas en tiempo real
Keil uVision C166, por la compa#ia Keil Software, debuggea programas y compila
Documentacion del C166, de la compa#ia Infineon

No es mi criterio habitual mencionar autores, programas, o direcciones web, pero
en ese caso hago una excepcin porque realmente esta gente se lo ha
trabajado, y despues de tratar con ellos me doy cuenta de que valen mucho.
Ademas me caen bien.

La mayoria de estos programas se pueden encontrar en www.gsm-dev.com
o en www.gsm-multifund.de/board

Dado que Siemens es una empresa alemana, no es de extraar que la mayora
de la documentacion, los foros, y los programas, estn escritos en esta
lengua. Aber du sprichst deutsch, oder?

Tampoco es raro encontrar documentacin en ruso, sobre todo en las webs
de ValeraVi y BoBa! aunque lo bsico est ya traducido al ingls.

Tambin hay otros muchos programas que incluyen cdigo fuente y te
pueden servir para meterte en este mundillo: 
Siemens Service Mode (flash_2.1.tar.gz), por Wilder.
sources.rar , por RizaPN
x35_patch , por BoBa!
Todos los fuentes de los parches, disponibles en www.gsm-dev.com

Tambien puedes pedirles a los autores que te pasen el cdigo fuente de
sus programas. A m nunca me pusieron impedimentos.

Recientemente he descubierto que hay una pgina web en espaol en
cs.comunidad-siemens.com
A m me parece que el nivel es bueno, y hay alguna gente adaptando
y desarrollando parches, sobre todo para los nuevos modelos.
A ver si despus de leer este artculo te pica el gusanillo y te
unes tambin a la comunidad.

PRIMEROS PASOS
**************
Bueno, pues el primer paso es ver que la cosa funciona.
Conecto el cable al ordenador y al mvil, inicio 'Siemens Flashing Tools', y
cuando me indica que apague el telfono, y pulse el boton de encendido
brevemente, lo hago, y el programa indica que todo va bien.
Selecciono le menu de 'Read Flash', y en menos de 10 minutos obtengo un
fichero con la memoria de mi mvil.

Hay muchas pginas dedicadas a explicar la diferencia entre el cable original
y el cable especial para desbloquear, asi que solo repetire lo que todas
dicen: el cable original no sirve.
(Claro que todavia no me explico porque el cable del S45 sirve para el C35)
Si tienes interes -y asumo que lees este articulo porque lo tienes- no te ser
difcil contactar con algunas de las muchas empresas que fabrican el
cable especial. Y en eBay puedes encontrar Siemens muy baratos.

El archivo con la memoria, tambin conocido como Flash, EEPROM, o FuBu, es
conveniente guardarlo en un lugar seguro. As puedo volver a meterlo en
el mvil si algo falla.
Cuando se enciende el mvil, hay una rutina que verifica que la memoria no
ha sido corrompida. Se toman todos los bytes, y se calcula un checksum.
Por eso uno de los primeros pasos es eliminar esta verificacin, para
poder meter mis programas y modificaciones tranquilamente.
Los telfonos x35 contienen un nico chequeo CRC
Los telfonos x45, x50 contienen dos chequeos CRC
Los modelos x55 y x60 no contienen chequeo.
Para hacerte tu propio parche, puedes usar el programa CRC Patcher
http://www.gsmdev.de/page/index.php?c=viewprojektinfo&id=20

Adems, en mi caso el telfono C35 tiene la versin v5, que es bastante
antigua y contiene fallos. Decido meter la v18, tambin porque la mayora
de los parches estn desarrollados para esta versin.

Esto es un paso importante: los parches oficiales de Siemens ocupan posiciones
de memoria totalmente diferentes segun la versin; si la rutina de enviar
mensajes en la version v5 empieza en la direccin D01234, puede que
empiece en la C43210 en la versin v18.
Puede que algunos parches incluyen las modificaciones para hacerlo
funcionar en otras versiones, pero no es lo normal.

Yo he decidido no usar la version v24 o v25 porque parece que contienen
nuevos fallos, y los parches no estn desarrollados para estas versiones.

Aunque no todos los modelos de Siemens contienen la misma funcionalidad, hay
parches que se han desarrollado para un modelo, y luego alguien los adapta a
otros modelos, siempre que sea posible. Por ejemplo, BoBa!, ZZToP y bEGEM0t se
han encargado de pasar al C35 muchos de los parches que RizaPN o ACiD[mrp] han
hecho para el SL45i. Gran trabajo, por otra parte.

Como iba diciendo, ya que tengo una copia de la Flash, lo siguiente que hay
que hacer es una copia de la EEPROM.
Esta otra zona de la memoria contiene datos que se pueden modificar sin
problemas, siempre que se tenga cuidado.
Me explico: la Flash contiene el programa, tericamente inalterable, mientras
que la EEPROM contiene datos que deben ser almacenados de manera
permanente, aunque se pueden cambiar, pero no se deben perder.
Notar que la EEPROM no contiene los datos que estan en el SIM.
Por ejemplo, la EEPROM almacena la puntuacin que has conseguido en el
juego del buscaminas. Tambin guarda el nivel de volmen para el
altavoz, el libro de direcciones del telfono, el bloc de notas , o la
clave para el navegador de internet.
La EEPROM se compone de unos cuantos ficheros, dependiendo del modelo de 
mvil hay mas o menos ficheros, y todos los modelos coinciden en usar los
mismos indicadores.
Por ejemplo, el fichero 5012 del C35i contiene el nivel de batera, mientras
que 5076 contiene el mensaje de saludo que aparece al encender el mvil.

Este fichero 5012 es especial y tambin hay que guardarlo, ya que contiene
informacin tal como la carga de la bateri, y la configuracin de los
parmetros de fbrica por defecto.

Para leer la EEPROM, no es necesario el cable especial; vale con el cable
original. As que puedo leer mi SiemensS45 o el C35.
Uso el S45 porque contiene ms datos.
Si tienes archivos Flash de otros modelos tambin se pueden investifar.
Arranco el Siemens Debugger, y en el botn de 'Setup' uso el puerto COM1.
Pulso el botn 'Start Service Mode' , y al cabo de un momento me dice que
el BFB no se ha abierto. Esto quiere decir que no tengo acceso a toda la
funcionalidad del programa, pero puedo hacer bastantes cosas.

EEPROM
*************
En la ventana de EEPROM, pulso 'existing only' y tras un momento la
lista 'Block name' contiene varios valores. Elijo 'Notes Function 10' , que es
el bloque 5179, y veo que aparecen un montn de caracteres, correspondiente
al men del mvil 4-3-5: Notes.

A partir de la posicin 0C , y en las posiciones pares (0C, 0E, 10, 12, ...)
aparece el texto "Hola", que es justamente lo que yo tengo almacenado en la
primera entrada del bloc de notas. En la parte hexadecimal veo que el
carcter es 48, tal como corresponde a la letra 'H'.
Es curioso que la primera nota est en el bloque 10. Posteriores pruebas
revelan que la nota segunda est en el bloque 9, y asi sucesivamente.
Armado de valor, hago doble-click sobre la celda 00000C , y escribo '4C'.
Entonces aparece el boton 'Save block', indicando que he hecho una
modificacin y puedo guardarla. Tras pulsar este boton me aparece un
mensaje diciendo que se han escrito 112 bytes en el bloque EEPROM 5179.
Miro el mvil, y la nota aparece ahora como "Lola", ya que 4C corresponde
a la letra 'L'.

Antes de que se me echen al cuello todos aquellos que comprenden la
codificacin ASCII, notar que este es un gran descubrimiento: el telfono
usa la tabla ASCII. Tambien podra usar la EBCBIC, o cualquiera otra
que Siemens se haya inventado. No creas que todos los microprocesadores
trabajan en ASCII; esto es slo una convencin.

Desde el telfono, es posible marcar esa nota como confidencial. En este
caso se pide el cdigo del mvil para protegerla.
Cuando apago el telfono y lo vuelvo a encender, al intentar leer la nota
me pide este cdigo.
Notar que el mvil lo tengo puesto para que no pida el cdigo cuando
lo enciendo: por eso me lo pide ahora al intentar leer la nota.

Desde el Siemens Debugger, miro de nuevo el bloque 5179, y veo que la nota
original sigue all! Slo han cambiado algunos bytes antes de la direccin C0.
O sea, que no lo ha cifrado. Esto quiere decir que cualquiera puede coger
el mvil de otro, y leer las notas -tericamente confidenciales- del usuario
original usando Siemens Debugger. No muy confidencial, dira yo.

La nota original 'sin cifrar' tiene los bytes:
00 00 10 0A 36 FF D4 07 08 1D 04 00 y luego el texto de la nota.
La nota confidencial tiene los bytes:
01 00 10 13 14 FF D4 07 08 1D 04 00 y luego la nota.
As que si cambio los bytes desde el 0 hasta el 5 para que sean como el
caso inicial, la nota pasa a ser no-confidencial.
Es ms: simplemente cambiando el primer byte de 01 a 00, la nota es
no-confidencial. No s el significado de los otros bytes, pero no
parecen servir para nada en este caso.
Probando con otros valores veo que 00 significa no-confidencial, y
cualquier otro dato significa confidencial.

Estars contento, no? Ya he hecho el primer crack.

Borro la nota desde el tlefono, y al mirar el bloque 5179, veo que
todava est all! Los primeros bytes han cambiado, pero los datos
siguen all. As que tampoco hay mucha seguridad en este apartado.
Cualquiera puede leer una nota antigua, por ms que se haya borrado.

El bloque este ocupa 112 bytes. No es mucho, pero suficiente para guardar notas
de 50 letras, pues cada letra ocupa 2 bytes. La cabecera ocupa otros 12 bytes.
Pero tambin es un sitio ideal para guardar un programa pequeo. A veces
la memoria Flash no es el mejor sitio para escribir un mini-parche, pero
en 100 bytes se pueden escribir grandes cosas en ensamblador.
Luego ver esto con ms detalle.

En artculos anteriores me quejaba de que, aunque puedo leer muchos de los
parmetros del mvil mediante comandos AT, es imposible leer las notas.
Bien, ya es posible hacerlo gracias a ACiD[mrp] y Siemens Debugger.
Tambin os haba enseado a escribirlas usando el comando de simulacin
de teclas AT+CKPD , pero he encontrado otro mtodo mejor.
Ya ver si soy capaz de automatizar esta tarea.

MAS EEPROM
*************
Otro bloque fcil de interpretar es 5166: Alarm Clock
El fichero ocupa 6 bytes, y en mi caso vale
08 20 00 1F F1 FF
Mirando el mvil, yo tengo puesto que suene a las 08:32 de lunes a viernes.
La hora 08:32 se escribe en hexadecimal como 08 20.
El dato 1F F1 se escribe en binario 00011111 11110001
Haciendo que no suene el martes, tengo
08 20 00 1D F1 FF, donde el dato 1D F1 se escribe en binario 00011101 11110001

Haciendo que no suene el mircoles, tengo
08 20 00 1B F1 FF, donde el dato 1B F1 se escribe en binario 00011011 11110001

O sea, que los das de la semana se marcan en bits desde atras hacia adelante.
Todos los das es 7F F1, mientras que 'ningn di' se escribe 00 F0.
El ltimo bit de byte 04 indica si la alarma est activa o no.
As, ya es fcil hacer un programa que sincronice la alarma del ordenador
con la del mvil.

Hay muchos ficheros interesantes, y entre ellos ha captado mi atencin el 5086:
'* WAP Profile 1b (CSD Dialup) *'
Esta es la explicacin preliminar: en un telfono con WAP, primero se
inicia una llamada a un servidor telefnico; algo as como un modem que
siempre est escuchando. Cuando uno se da de alta en este servicio, el
operador de red manda un SMS para configurar el telfono, y decirle algunos
paramtros, por ejemplo el nmero de telfono que tiene que marcar, el
nombre de usuario, y la clave.
Esto en el caso de una llamada a traves de la red 2G, mediante un CSD.
Cuando el telfono es GPRS estos datos se amplan a un servidor web llamado APN.
Para la conexin WAP, otros de los parmetros son el
servidor WAP primario, y el puerto.
Todos estos datos se guardan en la EEPROM, y, si bien se pueden ver desde
el propio telfono, el dato de la clave est oculto.
Pero seguro que est en alguna parte de la memoria.

As que con ayuda del 'Siemens Flashing Tools' hago una copia de la EEPROM.
Luego desde el mvil voy y cambio el perfil CSD, y sustituyo la
clave, poniendo '2222' en vez de 'xxxxxxxx'.
Hago otra copia de la EEPROM, y las comparo.
Es posible sacar cada uno de los ficheros independientemente; as resulta
ms fcil ver lo que ha cambiado.
Los bytes que han cambiado pertenecen al fichero 5086, como ya intuia.
La nueva clave '2222' aparece en la posicin 0x36 (esto es, 54 en
decimal), sin cifrar ni nada.
Para saber la clave inicial, no tengo ms que usar un editor hexdecimal, abrir
el archivo original 5086, y mirar a partir del byte 54 . En el caso de mi
operador, la clave resulta ser 'wap'.
Para el caso de Telefnica, el nombre de usuario es MOVISTAR, y tambin la
clave es MOVISTAR. Esto no es ningn secreto.
Y esto es el segundo hack del dia.

Otro caso: empiezo una partida al juego 'Balloon Shooter', y hago 130 puntos.
Guardo toda la EEPROM.
Borro el record, y guardo la EEPROM de nuevo.
Comparo los archivos, y difieren en
000087D9: FF 7D
O sea: ahora marca FF, pero con 130 puntos marca 7D.
El valor 7D es 125, y 255-125=130.
Asi que el dato se guarda en negativo.
La posicion global 87D9 tiene unos bytes antes, con el texto 'Championship', que
coincide con el archivo 'Games 1', en el bloque 5180. El bloque mide 250 bytes.
As que supongo que el record se guarda en el siguiente bloque 5181: 'Games 2'.
En efecto, el primer byte es 7D. Nada ms fcil que cambiar los primeros
bytes a '9F' y '15' para tener 60000 puntos.
Lo explico otra vez, porque es otro dato que no hay que olvidar:
No slo se guarda en complemento a 2, sino que el byte menos significativo
va primero, como corresponde a una arquitectura little-indian
de 16 bits: 65535-60000=5535, que se escribe '0x159F' en hexadecimal.
Alterando el orden de los bytes, queda '9F 15', como he dicho antes.
Esto es el tercer hack.

Cuando se modifica uno de los bloques, no se sobre-escriben los datos, sino que
se crea un nuevo bloque, y el anterior se invalida. Por eso la memoria EEPROM
necesita ser ms grande que toda la suma de los tamaos de los archivos.

IMEI EN LA EEPROM
*****************
Hay unos ficheros en la EEPROM que contienen informacin sobre el IMEI:
5009=IMEI Block 00
0076=IMEI Block 01
5008=IMEI Block 02
5077=IMEI Block 03

Todos los mviles tienen un identificador nico, creado por el fabricante.
Esto sirve, por ejemplo, cuando te roban el mvil. Slo hay que denunciarlo, y
el operador de telefona lo mete en una base de datos, que comparte con otras
operadoras. Cuando se intenta hacer una llamada desde ese mvil, no se permite.
Tambin sirve para saber el modelo. Esto hace que cuando haces o recibes una
llamada, la red sabe cual telfono tienes, y puede proporcionar funcionalidad
diferente. Un caso es que los tonos de la red (congestin, no hay
respuesta, ocupado, ...) pueden ser polifnicos, si tu modelo lo soporta.
Otra utilidad es identificar y cambiar los modelos que se sabe tienen
algun defecto.

Este identificador llamado IMEI se almacena en un archivo de la EEPROM.
En teora se puede modificar para hacerlo aparecer como otro telfono.
Notar que esto es ilegal en la mayora de los pases.
Adems Siemens ha decidido que esto no sea tan fcil; no se guarda en un
fichero en texto claro, sino que est cifrado.
Como medida extra, se guarda en varios ficheros, con distintos checksum.
Aun asi, resulta sencillo tomarlos de otro telfono, y copiarlo al mio.
Cuando se actualiza la EEPROM o la flash, lo que debe hacerse es una copia
de mis datos, meter la flash, y luego restaurar los datos de estos 4 archivos.
Si la actualizacin se hace con el software original proporcionado por
Siemens, el funcionamiento es ligeramente distinto: el software obtiene
el IMEI con el comando AT+CGSN , despues actualiza la EEPROM, calcula
el contenido de los ficheros, y los mete de nuevo. Esto deja la puerta
abierta a modificar el IMEI en memoria justo antes de escribirlo.
Este comportamiente se puede confirmar viendo el protocolo que usa el
programa de actualizacin original UpdateTool, disponible en la web de Siemens.
No me he metido en esto, pero suena interesante, no?

Otro fichero que hay que guardar es
0067 = Measurement values for temperature and voltaje
Esto guarda el nivel de batera actual y mximo, adems de otros datos.
Si no guardas este fichero, creer que el nivel de batera es el de la
persona que te ha pasado la EEPROM, seguramente se confundir a la hora
de cargarlo, y el telfono no te durar encendido ni 5 minutos.
Como antes, hay que guardar el tuyo, meter la flash, y restaurar tu fichero.

Esto es lo que hacen automticamente muchos de los programas que sirven
para desbloquear el telfono para usarlo en otras redes.
Un programa para esto es AllSiemens , aunque hace falta el cable original.

NO TODO ES ORO
**************
Otro de los bloques es
5058: Calculator & Currency converter
Este mvil tiene una utilidad que permite traducir una moneda en otra.
Se puede usar para convertir pesetas en euros, o pulgadas en centmetros.
El calculo es una simple regla de tres mediante un factor que se guarda
en las posiciones 1D-23 del fichero, mientras que el nombre de las
monedas se guarda en las posiciones 64-77 .
Pero al cambiar cualquiera de los datos desde el Siemens Debugger, no
parece guardarse en el telfono. De hecho, cuando apago el mvil y lo
vuelvo a encender, los datos no estan all. Es como si fuera de solo lectura.
Desde el propio mvil s se pueden modificar, pero Siemens Debugger no los ve.
Parece que se guardan temporalmente en algn otro fichero, aunque sin
modificarse en tiempo real.
La explicacin es el mvil usa un sistema de versiones de ficheros.
Cuando modifico un fichero, en realidad se hace una copia, se modifica el
nuevo fichero, se marca como activo, y el anterior se marca como inactivo.

Usando la aplicacion 'Smelter', voy al menu EEPROM, pulso con el botn
derecho del ratn, y marco la opcin 'Show deleted blocks'.
Esto es util para saber cuales archivos han sido modificados, y se puede
ver el original junto con las versiones que se han ido creando.

As veo que hay 4 versiones del fichero 5058, con todos los cambios que
he ido haciendo. El mvil no responde al refresco de estos datos, ya que
slo lee el fichero cuando se enciende. Es por esto que no tiene sentido
cambiar este fichero desde el ordenador.
Lo digo para que no te sorprendas si a veces tus cambios no los ves
reflejados inmediatamente.

Intentara entender el formato de los datos usados en la conversin de
la moneda, pero no es cuestin de encender y apagar el mvil 200 veces.

Hay otros muchos ficheros que se comportan igual.

En total, hay definidos unos 500 ficheros, aunque estoy seguro de que nuevos
modelos necesitan implementar nuevos ficheros, sobre todo para las redes 3G.

Si te decides a jugar con los ficheros, considera hacer una copia.
A m todava no me ha pasado nada grave, pero es ms que probable
que algn da me encuentre con que el mvil no funcione y sea
debido a algo que he tocado en los ficheros.
Por eso es bueno experimentar con otro mvil que no sea el que usas a diario.
Ya sabes: los experimentos se hacen con gaseosa.

DONDE ESTA LA EEPROM
********************
La EEPROM del C35i se guarda a partir de la direccion 0x3F0000, ocupa
en total 0x10000 bytes y la lista de ficheros esta a partir de 3F7CE0.
En el S45 la memoria est en dos trozos: en 0x1F0000 ocupando 0x10000 , y
en 0x5F0000 ocupando 0x10000.
Esto se puede ver con el programa zSiemens. Elige la opcin de guardar
la EEPROM, y dir la zona de memoria que debes guardar.
Para ver cmo est organizado, empiezo por el modelo mas sencillo.
Con un volcado de la Flash del C35i, en la direccin 0x3F7CE0+0x196=0x3F7E76
est el dato 0x20, o sea, 32 en decimal.
En 0x3F7CE0+0x196+0x02=0x3F7E78 esta el dato 'D6 6D', que pasado a little-endian
(primero el byte menos significativo) quiere decir 6DD6.
Sumando la direccin base de la EEPROM (0x3F0000) obtengo 0x3F6DD6.
En la direccion 0x3F7CE0+0x196+0x06=0x3F7E7C est el dato 'D4 13' que se
lee como 0x13D4 y en decimal es 5076.
Todo junto: el bloque 5076 mide 32 bytes y esta a partir de 0x3F6DD6.
Este bloque resulta ser 'Personalisation - Greeting Text' as que cuando lo
cambio, consigo cambiar el texto que aparece cuando enciendo el telfono.
Por defecto es 'Siemens C35i' pero lo cambio sin ms que alterar la EEPROM.
Existe una manera infinitamente mas sencilla de ver estos datos: vuelca toda
la flash (4Mg) y crgala en el Smelter.
Ve al menu EEPROM, y ordena por el campo llamado Offset. Entonces puedes
ver la lista de todos los ficheros.
Lo que pasa es que el metodo anterior me va a servir para leer los ficheros
desde el propio mvil. Pero no quiero adelantar acontecimientos.

Hay dos zonas de EEPROM: una llamada EEFULL y otra EELITE.
Unos ficheros estan en una zona, y otros en otra. Creo que para usar
la EELITE se necesitan mayores permisos, pero no estoy seguro.

HAY VIDA MAS ALLA DE LOS FICHEROS
*********************************
Y ya que estoy con el Smelter, explico otras opciones.
Para verlas hace falta un archivo con la Flash.
Lo normal es usar la que has extraido de tu mvil, pero tambin es posible
encontrar otras versiones de tu modelo, u otras memorias de otros modelos.
Esto se hace para comparar parches y adaptarlos.

Uno de los modelos que ms parches recibe es el SL45v56.
Busco su Flash y la cargo en Smelter.
El men de EEPROM ya lo conozco. Pero ahora puedo ver los archivos existentes
en otros modelos, y ver los que me faltan en el C35. Tambin puedo sacar
configuraciones de otros usuarios, aunque es ms que probable que, si
pertenecen a otro modelo, no tengan sentido en el mio.

TONOS
*****
Otro de los mens usados es el de Ringtones. Cada uno de los
sonidos (excepto la voz) generados por el mvil se guarda en la memoria.
Las melodas modificables por el usuario se guardan en la EEPROM, en
los bloques 73='Ringer melodies' y 5071='User defined melodies'.
Hay bastantes programas que permiten cambiar estas melodas con
un interface mucho ms sencillo, as que no me meto en el tema.
Pero hay otros tonos que no se pueden cambiar. Entre estos estn las
melodas predefinidas, y los tonos de operatoria normal del mvil.
Por ejemplo, cuando la red esta congestionada, se oye un pitido tut-tut-tut, o
cuando se enciende el mvil emite otro pitido. Tambin cuando se sobrepasa
la longitud de un SMS, los sonidos de los juegos, o el nivel bajo de batera.
Todos estos tonos tienen definido un nmero, y se encuentran en una
posicin de la memoria. Smelter nos dice esto, permitiendo adems la
posibilidad de escucharlo, e incluso guardarlos a un archivo.
De esta manera veo que cada nota se compone de dos partes: tono y duracin.
No hay un dato para el volmen de cada nota.
Cuanto mayor es el tono, suena ms agudo.
Los datos ocupan cada uno 2 bytes, as que un tono de valor 860 (0x035C) y
duracin 210 (0x00D2) se guarda como 5C 03 D2 00
Dado que tambin me dice la posicin de memoria donde se guarda, hacer un
parche para cambiar un tono es cuestin de segundos.

Voy a verlo con un ejemplo.
Cuando la batera se va a acabar, el telfono emite un pitido corto.
Dado que caerzco de sentido musical, no he podido identificar cual es ese tono.
Pero buscando los sonidos de slo 1 nota he encontrado 5. Modificando todos
ellos hasta encontrarlo, lo he convertido de 860:210 a 860:1, y ahora no se oye.
La meloda sigue estando all y suena, pero la duracin es tan corta
que es imperceptible.
De modo similar a los ficheros de la EEPROM, en el C35 los sonidos estn
indexados a partir de la direcion 0xC8E786. Cada meloda es un puntero
que ocupa 8 posiciones, de las cuales la cuarta indica la direccion de
memoria donde se almacenan las notas.
Esto me va a servir para identificar cuando se invoca a una meloda particular.

DIBUJOS
*******
Otra de las posibilidades es modificar los dibujos. 
Si modificar los sonidos es fcil, los dibujos es todava ms.
Uso el programa 'Siemens Picture Change', y cargo la Flash de mi mvil C35i.
Me aparece una lista con los identificadores de los dibujos. Elijo el 210, que
es el icono de infrarrojos, y me aparece en el cuadro de la izquierda.
Lo gracioso de este caso es que este modelo no tiene puerto de infrarrojos!
Lo mejor ser elegir un dibujo que puede ver: 468 es el icono que indica
que el timbre esta apagado, y las llamadas no harn que mi mvil pite.

Pulsando el botn derecho lo guardo en un archivo BMP, que luego edito.
Despus lo vuelvo a cargar haciendo doble-click sobre la lista de la derecha.
Pulsando 'save Patch as...' genero un parche para luego meterlo en el mvil.
El formato del fichero es RTF, aunque la extension es .vkp (v_klay).
La razn para usar RTF es que Word permite incluir iconos y grficos dentro
de sus documentos. As es posible abrir el fichero con word, y se ver
cmo es el dibujo incluido en el parche.
No solo eso, sino que adems  v_klay  tambin mostrar el dibujo al
abrir el cdigo del parche.
Arrancar el v_klay con el parche, y pulso 'Apply Patch' para transferirlo.
Pulso brevemente la tecla de encendido para entrar en el modo bootstrap, y
cuando el parche est cargado, apago el telfono, lo vuelvo a encender, y
tengo mi nuevo icono.
Cuarto hack del da.

Gracias a 'Siemens Picture Change' veo que la direccin es 0x352A29, y esto
sirve para saber a qu posicin de la memoria va a ir a parar el parche.

La direccin, e incluso el identificador de cada icono, es distinto
entre versiones y modelos. Por eso los parches para modificar dibujos
tambin tienen que ser adaptados de un modelo a otro.

Por ejemplo, en el modelo SL45i com la EEPROM v56 , este icono tiene
nmero 307 y est en la posicin 0x4B1F98.

MENUS
*****
En los telfonos Siemens los mens estn organizados como una lista simple.
Cada men est localizado en una posicin de memoria, en la que se dice
quien es su padre, el texto que muestra, la rutina a la que salta, y el
nmero de elementos en el caso de contener sub-mens.
Con el Smelter no hay ms que abrir la Flash, e ir al men 'Menu'.
Al principio aparece la lista pero no el texto del men, pero si
voy a 'Langpack', pulso con el botn derecho, activo 'Show tags' y
'Show texts from firmware', voy de nuevo a 'Menu' y ya me aparecen todos.
La importancia de los mens es que son los puntos de entrada para las rutinas.
Si quiero modificar alguna funcionalidad, lo normal es recorrer el camino
desde el men de entrada hasta esa funcionalidad. Por ejemplo, si quiero
quitar el mensaje 'Minesweeper. With compliments from Microsoft' que sale
antes de jugar al buscaminas, empiezo desde el menu Games->Minesweeper hasta
llegar al punto donde se referencia este mensaje.

El parche ms sencillo consiste en cambiar el texto del men. Pero como
en general estn traducidos, esto no es necesario, a no ser que lo quieras
adaptar a un lenguaje que no est soportado.

Tambin es posible cambiar los mens para que estn en otros sitios.
En mi mvil es posible definir cada una de las teclas como un acceso directo.
Si pulso durante 1 segundo esa tecla puedo ir directamente a un sub-sub-menu.
Lo malo es que no todos los sub-sub-mens estn disponibles.
Puedo elegir:
-Un cierto nmero de telfono
-Conectar a Internet
-Sitio web
-Listn de telfonos
-Listn de direcciones
-Calendario
-Alarma
-Notas
-Calculadora
-Conversor de moneda
-Nuevo SMS
-Iluminacin
-Ocultar ID
-GPRS
-IrDA
-Juegos
-Llamadas perdidas
-Llamadas recibidas
-Mensajes recibidos
-Mensajes enviados
-Favoritos
-Tarjeta de negocios

Pero yo uso frecuentemente el men de 'Datos de la ltima llamada' para 
ver cuanto tiempo he hablado. Y lamentablemente ese men no est entre 
los seleccionables.
El men es Registros->Duracin->Ultima llamada
En la Flash del ME45v28 (que es similar al S45) veo que se es el men 011C
dependiente de 86, y el punto de entrada es F3F5C0. Su padre es 854CA6.
Pero tambin aparece dependiente del men 87, con los mismos datos.
As que lo mas fcil (por ahora; luego mostrar otro mtodo mejor) es
intercambiar los puntos de entrada entre el men 'Tarjeta de negocios' y 'Datos
de la ltima llamada'.
El men 'Tarjeta de negocios' tiene numero 0223, depende de 60, y tiene
punto de entrada F39310. Su padre es 85351A.
Desde el   sfe   busco la cadena '10,93,F3', ya que los datos de puntos de
entrada se guardan en formato inverso. Lo encuentro en 05352A. Notar que es
el quinto menu dentro del 60, y
0x05352A - (5-1)*4 = 0x5351A , que es 0x85351A - 0x800000
El otro punto de entrada F3F5C0='C0,F5,F3' se encuentra en 054CA6 y 054CB6 .
Esto concuerda con el hecho de que aparece en el menu 86 y 87.
Igualmente notar que es el primer menu, y
0x054CA6 - (1-1)*4 = 0x054CA6 , que es 0x854CA6 - 0x800000
O sea, que Smelter nos indica, en la columna 'Entry' del men, donde est
definido este men.

As que el parche intercambiar esos datos , pero slo para el men 86:
0x05352A: 1093F3 C0F5F3 
0x054CA6: C0F5F3 1093F3

Lo cargo en el v_klay  , lo meto en el mvil, y a partir de ahora el men
'Tarjeta de negocios' me lleva a 'Datos de la ltima llamada', y viceversa.
Para que la tcnica sea perfecta, solo tengo que cambiar los textos de los
mens correspondientes.

Por curiosidad, en la flash S45i v4 este men es tambin el 011C pero
depende del 102 y salta a F6A870.

MAS DIFICIL TODAVIA
*******************
Este es el primer parche complicado. A ver si lo sigues sin perderte.
En el mvil la tecla '0' tambin tiene el smbolo'+' que sirve para
escribir nmeros internacionales, por ejemplo +34666..  y si se mantiene
pulsada durante un tiempo aparece el men '+List' para elegir el prefijo de
cualquier pas. Tanto los mviles como los nmeros de telfono de la red
fija tienen el mismo prefijo. Si recibes una llamada que empieza por +376 sabes
que viene desde Andorra.
Esto resulta informativo cuando alguien desde China marca mal y acaba llamando
a tu mvil. Suena raro, pero yo ya he recibido un par de llamadas desde Rusia
y otra desde Indonesia. Pero en general esta lista resulta una tontera.
Mi propsito es cambiarlo para que me diga la red espaola.
En Espaa hay hasta el momento 5 operadores de telefona
mvil: Airtel , Movistar, Amena, Xfera, y Moviline.
Cada uno de ellos tiene asignado unos dgitos de prefijo nacional.
Toda la telefona mvil empieza por '6', aunque para ser ms correcto
debera decir que comienza por '+34 6'.
A partir de esta base, cada uno tiene un grupo de nmeros.
Movistar tiene '+34 606', '+34 609' y '+34 615' y muchos ms.
Xfera tiene '+34 622'.
Airtel tiene '+34 607' , '+34 610' y '+34 617'....
Esta es la lista completa:
AIRTEL 600 607 610 617 627 637 647 661 662 666 667 670 677 678 687 697
AMENA 605 615 625 635 650 651 652 653 654 655 656 657 658
MOVILINE 608 689
MOVISTAR 606 609 616 618 619 620 626 628 629 630 636 639 646 649 659
         660 669 676 679 680 686 690 696 699 
XFERA 622

Cuando quiero llamar a alguien, me interesa saber en cual red est, para
elegir el mejor horario que se ajuste a mi tarifa, o llamar desde el telfono
de la oficina. Por eso voy a desarrollar un parche que sustituya la lista
de prefijos internacionales por otra de prefijos nacionales para mviles.
La lista original tiene 90 pases, y la nueva lista tendr 40, ya que
slo hay otorgados 40 prefijos '+34 6xx'.
Todos los cambios los voy a hacer en el C35i, aunque siguiendo el mismo
proceso es fcil adaptarlo a otros modelos.
Para empezar, busco en la Flash el nombre del primer pas de la lista: Algeria.
S, ya se que en espaol se dice 'Argelia', pero mi mvil est en ingls.
Lo encuentro en la posicin  0x3CD06A  , seguido por los bytes 0x00 0x95 , y
el siguiente pas : Andorra (en 0x3CD073) y de nuevo  0x00 0x95 .
Luego est Argentina en 0x3CD07C , con su currespondiente 0x00 0x95 .
Y despus Australia en 0x3CD087 .
Asi que para empezar sustituyo 'Algeria' por 'Almeria':
3CD06C: 67 6D

Meto el parche, y aparece tal como esperaba.
El nmero de Algeria es +213 asi que busco en el fichero de la flash esa
cadena, como si fuera una palabra de 3 letras.
No la encuentro. Mi siguiente idea es buscar el byte 213, pero seguro que
aparece miles de veces.
El siguiente pas de la lista es Andorra, con prefijo +376, as que lo
traduzco a hexadecimal: 0x01 0x78, y aparece varias veces, pero nunca
cerca de 0xD5, que es el valor hexadecimal de +213. Tras un instante de
perplejidad, recuerdo que el C166 trabaja en formato little-endian, as
que lo que tengo que buscar es 0x78 0x01. Pronto aparece en 0x387C88, y
antes de l tambin est el cdigo de Algeria: 0xD5, 0x00 .
0x387C84: D5 00 20 07
0x387C88: 78 01 21 07
0x387C8C: 36 00 22 07 , correspondiente a +54, el codigo de Argentina
Mi corto ni perezoso cambio el byte D5 por D6, y se muestra el +214 en el mvil.
Para hacer aparecer el prefijo +34 606 , uso la calculadora de Windows que
me lo convierte en hexadecimal : 0x872E = 0x2E 0x87 en little-endian.
Ahora el primer elemento de la lista me aparece 'Almeria' con prefijo +34 606

UN PASO MAS
***********
El siguiente problema al me enfrento es que no puedo poner 'Movistar-606' en
lugar de 'Algeria', porque ocupa ms caracteres y no cabe.
Sospecho que tiene que haber alguna relacin entre la lista de prefijos y
la lista de pases.
Dado que el caracter 0x07 aparece todas las veces, supongo que es un separador.
Pero el numero precedente parece un ndice. Lo cambio y voy a ver que pasa.
Pongo 0x25 en vez de 0x20. Lo que sucede es que el primer pas de la
lista es ahora Austria, el cual estaba antes en la posicion 5.
O sea, que es un ndice a la lista de pases.
Los nombres de los pases a su vez estn separados por 0x00 0x95.
Retraso esto 2 posiciones para incluir 'xx', y ahora la lista
es Algeriaxx, dorra, Argentina, ...
Es decir, que hay una lista que apunta a los nombres de los paises, los
cuales se imprimen hasta encontrar el carcter 0x00.
Intento averiguar donde se referencia a esta posicin de memoria, pero
no encuentro nada.

Despues de darle algunas vueltas, se me ocurre una solucin:
0x387C84 tendr +34 606 y usar el tercer byte=20 para apuntar a 0x3CD06A  ,
         donde guardar 'Movistar-606', sustituyendo a 'Algeria'
   Nadie apuntar a 'Andorra'
0x387C88 tendr +34 609 y usara el tercer byte=22 para apuntar a 0x3CD07C  , 
         donde guardar 'Movistar-609', sustituyendo a 'Argentina'.
   Nadie apuntara a 'Australia'
Esta es una manera de hacer hueco: uso slo la mitad de los pases.

Tambien podra poner 'Mstar606', 'Xfera654' y similares, aunque voy a ver
si hay otra manera de hacerlo ms bonito y completo.

Como estas dos ideas son un poco chapuceras, intento de nuevo encontrar
referencias a la lista de pases.
La manera fcil de sacarlo habra sido usar Smelter para ver las
palabras escondidas en la EPROM. Lamentablemente este mtodo falla porque
no es capaz de interpretar correctamente el Langpack del C35i, aunque
funciona bien con otros modelos. As que experimentando con el ME45 veo que
en esta Flash la palabra 'Algeria' se localiza en el offset 0x061201, y est
referenciada desde 0x061CA9. Intento buscar algo similar en mi Flash del C35.

Tras muchas pruebas, llego a la conclusin de que 0x3CDA20 es un apuntador
al nombre del primer pas.
En 0x3CDA20 hay los bytes 0x69 0x10. 
En 0x3CDA22 hay los bytes 0x72 0x10. 
Decremento el dato que esta en 0x3CDA20 ; esto es, cambio en 0x3CDA20 para que
ponga 0x6A 0x10 (recordar: little-indian) y la lista de paises sale:
lgeria , Andorra, Argentina, ... El cambio es que la 'A' inicial
de Algeria me la he comido.
Cambiando en 0x3CDA20 para que ponga 0x72 0x10 hago que la lista de paises sea:
Andorra , Andorra, Argentina, ...
 
En resumen, la palabra 'Algeria' aparece en 0x3CD06A y est referenciada
desde 0x3CDA20 , con valor 0x1069
Asi que sin mucho cuidado empiezo a modificar los paises en 0x3CD06A :
Airtel600<00><95>Airtel607<00><95>Airtel610<00><95>Airtel617<00><95>...
y sus referencias en 0x3CDA20 y siguientes:
0x3CDA20: 1069
0x3CDA22: 1069+strlen("Airtel600")+2=1074
0x3CDA24: 1074+strlen("Airtel607")+2=107F
0x3CDA26: 107F+strlen("Airtel610")+2=108A

Tambin tengo que cambiar los cdigos de los prefjos:
0x387C84: 2887 , porque +34 600 = 0x8728
0x387C88: 2F87 , porque +34 607 = 0x872F
0x387C8C: 3287 , porque +34 610 = 0x8732
0x387C90: 3987 , porque +34 617 = 0x8739

Para hacer un parche a partir de estos datos, se puede usar un programa
llamado PATSeach, aunque a m me resulta ms sencillo usar el
comando   fc  del MSDOS y comparar la Flash inicial con mi Flash alterada.
Por ejemplo:
fc /b C35_original.bin C35_cambia_prefijos.bin
que, para el trozo que cambia los numeros (+213 pasa a ser +34 600 , +376 pasa
a ser +34 667, +54 pasa a ser +34 610 , +61 pasa a ser +34 617 ) resulta:
387C84: D5 28
387C85: 00 87
387C88: 78 2F
387C89: 01 87
387C8C: 36 32
387C8D: 00 87
387C90: 3D 39
387C91: 00 87

Otro hack satisfactorio.


PARCHES AJENOS
**************
Un parche fcil:
He encontrado por ah un parche para eliminar el
mensaje 'Minesweeper. With compliments from Microsoft' que aparece
antes de empezar a jugar con el buscaminas.
El parche simplemente dice:

;Firmware: C35 v18 lg4
;Author : [ZZToP]
;File : Minesweeper.vkp
;Remove message "With compliments of Microsoft" on start Minesweeper
2589BA: DAC4 0D01

O sea, que cambiara sol 2 bytes.
Para intentar comprender lo que hace, voy a desensamblar el cdigo original.
En vez de empezar por la posicion 2589BA, empiezo 16 bytes antes, en 2589AA.
Eso me indicar lo que hay antes del codigo original:

sfe d C35_18_From_00.bin,2589AA,20 C00000

E589AA: 88 D0       :   mov     [-r0], r13
E589AC: 88 C0       :   mov     [-r0], r12
E589AE: E6 FC 1C 10 :   mov     r12, #101Ch
E589B2: E6 FD E1 03 :   mov     r13, #3E1h
E589B6: E0 0E       :   mov     r14, #0
E589B8: E0 0F       :   mov     r15, #0
E589BA: DA C4 AA 85 :   calls   0C4h, loc_C485AA ;<<< esto ser cambiado
E589BE: 08 04       :   add     r0, #4
E589C0: DB 00       :   rets
;-----------------------------------------------
E589C2: F0 CC       :   mov     r12, r12
E589C4: E0 2D       :   mov     r13, #2
E589C6: FA E9 D2 4E :   jmps    0E9h, loc_E94ED2

Parece que pone algunas variables en la pila, les asigna valores, y llama a
la rutina C485AA. Luego mueve la pila, y retorna en E589C0 .

Desenamblando el parche con:
sfe d Minesweeper.vkp,2589BA,20 E589BA
E589BA: 0D 01       :   jmpr    cc_UC, loc_E589BE

Veo que sustituye el   'calls ... '  por   'jmpr ...'   con lo que saltar
hasta la instruccion siguiente, en E589BE.
Habra sido un poco mas sencillo cambiar el 'calls ... '   por un  'nop', pero
as tambin funciona.

O sea, que elimina la llamada a C485AA.
Eso quiere decir que C485AA es una rutina que
imprime 'Minesweeper. With compliments from Microsoft'.

Para verlo con ms detalle desensamblo a partir de C485AA-02=C4859A8 :
sfe d C35_18_From_00.bin,0485A8,60

0485A8: DB 00       :   rets
;---------------------------------------------
0485AA: 26 F0 66 00 :   sub     r0, #66h
0485AE: 88 F0       :   mov     [-r0], r15
0485B0: 88 E0       :   mov     [-r0], r14
0485B2: 88 C0       :   mov     [-r0], r12
0485B4: 88 D0       :   mov     [-r0], r13
0485B6: D4 10 6E 00 :   mov     r1, [r0+#6Eh]

Indica que 0485AA es el comienzo de una subrutina (esto es buena seal: no
aterrizo en mitad de la nada) y almacena los registros r12, r13, r14 y r15, que
son los que justamente ha asignado en E589AE-E589B8.

?Cmo ha sabido el autor del parche que haba que modificar esa
direccin, y no otra?
Mediante el men. Antes de E589BA, se han puesto las variables para
que r13 y r12 apunten al dibujo con el mensaje.
En realidad, el parche fu desarrollado para el modelo S35. El autor
del parche para el C35 slo ha tenido que entender lo que hace el
original, buscar la rutina correspondiente en el C35, la ha encontrado
en 0485AA, y cambia la zona a sobreescribir.

Yo voy a hacer lo mismo.

APRENDIENDO DE OTROS
********************
He encontrado otro parche fcil :

;----- without_sim.vkp -------
;Firmware : SL45v56
;Author : DeadMans
024C2A: E004 E014

Ms simple, imposible. Slo cambiar 2 bytes en la posicin de
memoria 0x024C2A para hacer que se pueda trabajar con algunos mens del
mvil, aun sin tener insertada la tarjeta SIM.
Pero este parche slo vale para el mvil SL45, version 56.
Voy a ver si lo puedo adaptar para mi C35v18.

Para trabajar en la adaptacin de parches, es necesario entender el
modelo original, y el destino.
As que tras un poco de buscar por ah encuentro la Flash del SL45iv56 en
un fichero llamado SL45iv56.bin . Dado que la mayora de los parches los han
hecho los chicos de www.gsm-dev.com y ellos tienen SL45iv56 , no es difcil
encontrar una flash.

Desensamblando esa zona de memoria en la Flash del SL45v56 con el programa sfe:
sfe.exe d SL45iv56.bin,024C2A,20

024C2A: E0 04       :   mov     r4, #0 ;<<< esto ser cambiado
024C2C: DB 00       :   rets
;------------------------------------------------
024C2E: E0 0C       :   mov     r12, #0
024C30: F0 DC       :   mov     r13, r12
024C32: 5C 1D       :   shl     r13, #1
024C34: D7 40 0C 00 :   extp    #0Ch, #1
024C38: D4 ED 52 23 :   mov     r14, [r13+#2352h]
024C3C: 48 E3       :   cmp     r14, #3
024C3E: 3D 02       :   jmpr    cc_NZ, loc_024C44
024C40: F0 4C       :   mov     r4, r12
024C42: DB 00       :   rets

Y desensamblando el parche:
sfe d without_sim.vkp,180AC,2
0180AC: E0 14       :   mov     r4, #1

O sea, que el parche hace que, en vez de asignar r4=0 , hace r4=1.

Para ver como adapto este parche al C35, uso el   sfe   para buscar
una cadena de bytes parecida

sfe f C35_18_From_00.bin E0,04,DB,00,E0,0C,F0,DC,5C,1D

  1. 0x0180AC (0306:00AC): E0 04 DB 00 E0 0C F0 DC 5C 1D
  2. 0x192AF4 (0364:2AF4): E0 04 DB 00 E0 0C F0 DC 5C 1D
  3. 0x192B5A (0364:2B5A): E0 04 DB 00 E0 0C F0 DC 5C 1D

Desensamblando estas 3 zonas de memoria, la que ms se parece es la primera:
sfe d C35_18_From_00.bin,180AC,50
0180AC: E0 04       :   mov     r4, #0
0180AE: DB 00       :   rets
;------------------------------------------------
0180B0: E0 0C       :   mov     r12, #0
0180B2: F0 DC       :   mov     r13, r12
0180B4: 5C 1D       :   shl     r13, #1
0180B6: D7 40 40 00 :   extp    #40h, #1
0180BA: D4 ED D0 24 :   mov     r14, [r13+#24D0h]
0180BE: 48 E3       :   cmp     r14, #3
0180C0: 3D 02       :   jmpr    cc_NZ, loc_0180C6
0180C2: F0 4C       :   mov     r4, r12
0180C4: DB 00       :   rets

Asi que el parche para el C35 no hay mas que:
0180AC: E004 E014
Lo cargo, lo pruebo, y funciona. Ahora ya puedo acceder a algunos
de los mens sin tener la tarjeta SIM.

Pero no siempre es tan sencillo, claro.

ADAPTANDO DE OTROS
******************
Otro parche que he encontrado se llama
111_Do_Not_Allow_To_Enter_112_In_Keylocked_Mode.vkp
;Firmware: SL45 v56 
0311BC: EA207012 CC00CC00 

que hace que NO se pueda marcar el numero de telfono de emergencia 112.
El parche slo vale para SL45 v56. Voy a ver si lo puedo traducir para mi C35i.
Desensamblo la flash del SL45 v56:

0311B8: 08 02       :   add     r0, #2    
0311BA: 48 40       :   cmp     r4, #0
0311BC: EA 20 70 12 :   jmpa    cc_Z, loc_031270 ; <<<<esto ser cambiado
0311C0: loc_0311C0:
      : E6 FC 4A 00 :   mov     r12, #4Ah

La nueva instruccion CC00CC00 significa   NOP  , NOP  , o sea, que no hace
nada, y por lo tanto no salta a loc_031270

Para adaptarlo al C35i tengo que buscar una cadena que se parezca a esta.
Naturalmente cambiarn las direcciones de las rutinas, por lo que no
puedo confiar en encontrar   'jmpa    cc_Z, loc_031270'
Buscando la cadena  08 02  la encuentro mas de 1000 veces.
La cadena  48 40  la encuentro tambien mas de 1000 veces.
La cadena E6 FC 4A 00 la encuentro tambien 16 veces.
Como no me apetece desensamblar estas 16 ocurrencias, hago un programa
llamado   near  que busque una secuencia de bytes lo suficientemente cercanos.
#include <stdio.h>
#include <string.h>

main(int argc, char *argv[])
{
FILE *ap;
unsigned char c1=0, c0, c;
int i, j;
int buscados[10], total=0, exitos=0;
long posi[10], posi0=-1, posi10;
char cad[200];

ap=fopen(argv[1],"rb");
if(ap==NULL)
 {
 printf("No encuentro archivo flash %s \n", argv[1]);
 exit(1);
 }
/* busca los bytes a partir del argumento 2 */
/* el formato es en hexa: C0 DF 66 ... */
for(i=2;i<argc;i++)
 {
 strcpy(cad, argv[i] );
 c0=cad[1]-'0'; if(c0>9) c0=c0+'0'-'A'+10;
 c1=cad[0]-'0'; if(c1>9) c1=c1+'0'-'A'+10;
 buscados[total]=c0+c1*16;
 printf("Buscando %0.1X \n", buscados[total]);
 posi[total]=-1000;
 total++;
 }

while(!feof(ap))
 {
 c0=getc(ap);
 posi0++;
 for(i=0;i<total;i++)
  if(c0==buscados[i])
   {
   posi[i]=posi0;
   exitos=0;
   for(j=0;j<total;j++)  /* los datos buscados tienen que estar */
    if(posi0-posi[j]<4+10*total/8) /* cerca, no necesariamente pegados */
     exitos++;   /* el orden tampoco importa */
   posi10=posi0/2-10; posi10*=2; /* muestra direccion par, 20 bytes antes */
   if(exitos>8*total/10 && exitos!=total ) /* exito parcial */
    printf("%i en %0.6X -> %0.6X\n", exitos, posi0, posi10 );
   if(exitos==total )
    printf("*** %i en %0.6X -> %0.6X\n", exitos, posi0, posi10);
   }
 }
return 1;
}

Lo ejecuto con
di_near C35_18_From_00.bin 08 02 48 40 E6 FC 4A 00
y me salen 5 posibilidades. De ellas la que ms se parece es
0219DE: 08 02       :   add     r0, #2
0219E0: 48 40       :   cmp     r4, #0
0219E2: 3D 03       :   jmpr    cc_NZ, loc_0219EA
0219E4: E0 14       :   mov     r4, #1
0219E6: EA 00 BA 1A :   jmpa    cc_UC, loc_021ABA
0219EA: loc_0219EA:
        E6 FC 4A 00 :   mov     r12, #4Ah
que, aunque tiene otras lineas en medio, el resto es idntica a la
rutina del SL45.
Ahora tengo 2 saltos: a loc_0219EA y a loc_021ABA.
Y para cada uno, hay posibilidades: puedo eliminar el salto, o forzarlo.
Empiezo por cambiar
jmpr cc_Z, loc_0219EA
o sea:
0219E2: 3D03 2D03
y compruebo que al bloquear teclado (Keylocked_Mode), ahora puedo
escribir cualquier numero, excepto el '1' y el '2'.
Bueno, es una manera de deshabilitar la llamada al nmero de emergencia.
Lo que me interesa no es deshabilitarlo, sino entender cmo funciona.
Lo que hace esta rutina es chequear la tecla pulsada cuando el mvil est
con el teclado bloqueado.
Originalmente, si es '1' o '2', entonces permite esa tecla, aunque hace otro
chequeo posterior para ver que los nmeros 1-1-2 estn en el orden correcto.
Mi parche lo que hace es permitir la tecla si NO es '1' ni '2'.
Adems, evita el segundo chequeo.

Aunque esto parezca una simple conversin, en realidad es otro hack exitoso.

OTRA ADAPTACION
***************
Hay otro parche llamado 'Call Minutes Beep'.
Este es ms difcil de entender, asi que si no ests despejado, mejor
dejas la lectura para otro momento.
Abro el fichero cmb_vibra.vkp con un editor de textos.
En las primeras lineas veo que dice:
; Firmware: SL45i v56
; Author:   rc-flitzer

O sea, que este parche tampoco vale para mi S45 ni para mi C35. Pero al
parecer, el propsito de este parche es cambiar el tiempo y periodo
del pitido de cada minuto.
El mvil tiene una configuracin que hace que cuando estoy hablando, puede
emitir un pitido cada minuto. Esto sirve para saber el tiempo que llevo de
charla, y el parche me permitir cortar la llamada justo antes que transcurra
un minuto completo, apurando al mximo el coste de la llamada.
Adems, el modo de vibracin tambien se puede activar.

Este es el contenido del parche
----------------------------------------------------
0x001F20: F2F40CFE DAC710D1  ; Olvdate de esta linea.

0x27D6EA: FFFFFFFFFFFFFFFF F2F40CFE88C046F4
; This value is time, when vibra should start,
; here 50 = 50 seconds. Because of period is 60 seconds the vibra
; sounds ten seconds before every minute.
; Change value if you like, but has to be smaller than the time period.
0x27D6F2: FFFF 3200    ; = 0x32 = 50 decimal
0x27D6F4: FFFFFFFFFFFFFFFFFFFFFFFFFFFF 3D05E6FC2F00DAC314000D0646F4
; This value is value above plus one for one second vibra.
; You can make two or more seconds, but it's not recommended
0x27D702: FFFF 3300    ; = 0x33 = 0x32 + 1
0x27D704: FFFFFFFFFFFFFFFFFFFFFFFF 9D03E00CDAC3140098C0DB00
----------------------------------------------------

El primer dato de cada linea (0x27D6EA) indica la posicin de memoria
donde se tiene que meter.
El segundo (FFFFFFFFFFFFFFFF) indican los datos originales.
El tercero (F2F40CFE88C046F4) indica los datos que hay que meter.

Luego hay algunas lineas con comentarios. En este caso particular, es posible
modificar algunos de los parmetros, tal como la duracin y el momento en
el que debe vibrar.

Ahora explico cada uno de ellos.
Para la posicion de memoria, hay que entender que viene dada en
hexadecimal, ocupando 24 bits. El procesador C166 usa bancos de 64 Kb (16 bits),
paginados mediante un indicador de 8 bits, lo que da acceso a 16 Mb (24 bits).
La Flash para el C35 ocupa 4 Mb y empieza en 0xC00000 , mientras que para
el modelo SL45 ocupa 6 Mb y empieza en 0xA00000.
Pero para los parches, la direccin se considera empezando en 0x000000, tal
como se encuentra en el fichero con la Flash. 

En otras palabras, direccion_memoria=0xA00000+direcion_fichero
Por eso un parche que dice empezar en 0x27D6EA realmente va a 0xC7D6EA.

El segundo dato me dice que en esa posicion debera haber FFFFFFFFFFFFFFFF , lo
cual son 8 bytes con el valor 0xFF. Esto sirve para no aplicar 2 veces el
parche, y para verificar que efectivamente estoy tratando con la
versin adecuada de la Flash.

El tercer dato contiene los datos a grabar. El formato permite usar lineas
de tantos caracteres como queramos, aunque 16 bytes es un buen nmero.
En esta primera linea veo que los datos son F2F40CFE88C046F4, ocupando 8 bytes.

La segunda linea dice que los datos deben ir a 0x27D6F2 . 
Esto es obvio, pues 0x27D6EA+0x8=0x27D6F2 
El autor ha creado la linea
0x27D6F2: FFFF 3200    ; = 0x32 = 50 decimal
para explicar claramente que este dato se puede cambiar si deseo que
vibre en el segundo 50-esimo, o en otro que se me antoje. 

As que arranco el programa v_klay y cargo este fichero. Me pide apagar
el mvil y pulsar brevemente el boton de encender. Dado que no tengo
un SL45i , el parche ni siquiera se intenta meter en el mvil.

Hay una primera linea que no he explicado:
0x001F20: F2F40CFE DAC710D1

Este linea va en la posicin de memoria 0xA01F20, y espera encontrar
los bytes F2F40CFE para sustituirlos por DAC710D1.

Tras cargar la  Flash del SL45iv56 en un editor hexadecimal, compruebo
que en 0x001F20 yo tengo los bytes F2F40CFE .

A DESENSAMBLAR
**************
Ahora con el programa sfe (Siemens Flash Explorer) escribo:
sfe d SL45iv56.bin,1f00,200
desensambla el fichero SL45iv56.bin desde la posicin 1F00 hasta 200 bytes ms.
No elijo la direccion 01F20 porque me interesa ver un poco de lo que est antes:
001F00: 40 29       :   cmp     r2, r9
001F02: F0 C4       :   mov     r12, r4
001F04: F0 D5       :   mov     r13, r5
001F06: DA A0 0C 2F :   calls   0A0h, loc_A02F0C
001F0A: DA DE 6E 15 :   calls   0DEh, loc_DE156E
001F0E: 48 41       :   cmp     r4, #1
001F10: 3D 12       :   jmpr    cc_NZ, loc_001F36
001F12: DA A0 78 2F :   calls   0A0h, loc_A02F78
001F16: E6 FC 3C 00 :   mov     r12, #3Ch
001F1A: F6 F4 0E FE :   mov     mem_FE0E, r4
001F1E: 5B CC       :   divu    r12
001F20: F2 F4 0C FE :   mov     r4, mem_FE0C ; <<<<esto sera cambiado
001F24: 3D 08       :   jmpr    cc_NZ, loc_001F36
001F26: E6 FC E8 35 :   mov     r12, #35E8h
001F2A: E6 FD 0E 00 :   mov     r13, #0Eh
001F2E: E6 FE 52 00 :   mov     r14, #52h
001F32: DA C1 64 B1 :   calls   0C1h, loc_C1B164
001F36: DA CC 28 C5 : loc_001F36:
001F36: DA CC 28 C5 :   calls   0CCh, loc_CCC528
001F3A: 48 40       :   cmp     r4, #0
001F3C: 3D 04       :   jmpr    cc_NZ, loc_001F46


y el comando
sfe d cmb_vibra.vkp,1F20,4
dice
001F20: DA C7 10 D1 :   calls   0C7h, loc_C7D110

O sea, que el comando
mov     r4, mem_FE0C
sera sustituido por
calls   0C7h, loc_C7D110

En principio esto no tiene mucho sentido, pero sigo desensamblando el parche:
sfe d cmb_vibra.vkp,27D6EA,300

27D6EA: F2 F4 0C FE :   mov     r4, mem_FE0C
27D6EE: 88 C0       :   mov     [-r0], r12
27D6F0: 46 F4 32 00 :   cmp     r4, #32h
27D6F4: 3D 05       :   jmpr    cc_NZ, loc_27D700
27D6F6: E6 FC 2F 00 :   mov     r12, #2Fh
27D6FA: DA C3 14 00 :   calls   0C3h, loc_C30014
27D6FE: 0D 06       :   jmpr    cc_UC, loc_27D70C
;------------------------------------------------
27D700: 46 F4 33 00 : loc_27D700:
27D700: 46 F4 33 00 :   cmp     r4, #33h
27D704: 9D 03       :   jmpr    cc_NC, loc_27D70C
27D706: E0 0C       :   mov     r12, #0
27D708: DA C3 14 00 :   calls   0C3h, loc_C30014
27D70C: 98 C0       : loc_27D70C:
27D70C: 98 C0       :   mov     r12, [r0+]
27D70E: DB 00       :   rets

O sea, que de algun modo 
calls   0C7h, loc_C7D110
llamara a 27D6EA que hara
27D6EA: F2 F4 0C FE :   mov     r4, mem_FE0C 
al igual que la rutina original, y adems hara algo ms.

Ahora es cuando hay que echar mano de los manuales del C166, que dicen que
mov     r4, mem_FE0C
sirve para que el registro r4 tenga el mismo valor que la posicin
de la memoria mem_FE0C.
El documento que yo uso se llama sj2003551.pdf y contiene la descripcin
de todos los comandos, as como los datos de algo que se llaman registros SFR.
Bsicamente, en un C166 los registros siempre se encuentran en una posicin
de memoria, y lo mismo da leerlos de la memoria que usar su propio resultado.
El registro FE0C se llama 'Multiply/Divide High Word' , y se usa en las
operaciones de multiplicacin y divisin.
Por ejemplo, cuando hago
mul	r0, r4
lo que pasa es que se multiplica r0*r4  y el resultado va a parar a mem_FE0C .
Analogamente se usa para la division.
Es por eso que no extraa encontrar 
001F1E: 5B CC       :   divu    r12
justo antes de consultar mem_FE0C .

Pero me estoy desviando del tema.

La nueva rutina a partir de 27D6EE mete r12 en [-r0]
Esto es una manera de almacenar un dato en la pila.
El comando mov [-r0] , r12 quiere decir meter r12 en la direccin a la que
apunta r0 (que suele ser la zona de stack) y luego decrementarlo, haciendo
hueco para un nuevo valor. Esto se hace porque la subrutina modificar r12, y
no deseo perderlo.

cmp     r4, #32h     compara r4 con 0x32 . El valor de r4 se ha asignado
anteriormente, probablemente en loc_DE156E, y creo deducir que almacena
el segundo (hh:mm:SS) en el que est el reloj.
Por eso lo compara con 0x32, para ver si est en el segundo 50-esimo.

Si no es 0, salta a loc_27D700 .
En caso contrario mete #2Fh en r12, y llama a loc_C30014
Desensamblando 0xC30014 (recordar que est en la flash en 0x230014) con
sfe d SL45iv56.bin,230014,200
veo que hace muchas cosas, y r12 parece ser algun tipo de flag de activacin.
Tras esto, salta a loc_27D70C

En loc_27D700 (viniendo desde 27D6F4) mira si est en el segundo 51-esimo.
Si no es asi, salta a loc_27D70C, desde donde se recupera r12, y sale.

Pero si esta en el segundo 51-esimo, pone el flag r12 a 0 , llama
de nuevo a loc_C30014 y luego sale.

Asi que est ms claro ahora: loc_C30014 se encarga de activar/desactivar
el vibrador en funcin de lo que diga r12.

Para adaptar este parche a otro modelo, debo saber cual es la rutina para
activar el vibrador, y tambien parchear 001F20, o su equivalente.
Entonces hay que cargar en el editor el archivo con mi flash del S45 y ver
si por casualidad las mismas rutinas estn en los mismos sitios.

En el archivo ME45FubuV28.fls, los datos 
001F1A: F6 F4 0E FE :   mov     mem_FE0E, r4
aparecen en 8 posiciones, pero filtrando en funcin de la linea precedente
001F16: E6 FC 3C 00 :   mov     r12, #3Ch
me quedo con
0x202390 y 0x20b0e0.

Para decidir por una u otra posicin lo mejor es desensamblar los dos
trozos y ver cual se parece ms al original.
Lamentablemente me da un error, pero dice:
File ME45FubuV28.fls (pos=0x0,sz=0x600000,rd=0x600000) buffered
FirmwareID: ME45v28-lg1-ken8.z2 (ME45 memory mapping)

O sea, que al menos ha reconocido que el fichero pertenece a un ME45, lo
cual no me vale de consuelo.

Encuentro otra Flash de un S45i, y tampoco es capaz de desensamblarlo.

Es cierto que un fichero Flash no es lo mismo que un fichero bin , pero ya
que reconoce lo que hay dentro, esperaba que fuera capaz de desensamblarlo.
No todo est perdido: del fichero ME45FubuV28.fls, corto un trozo
entre 0x202390-20 y 0x202390+20 , lo guardo en un mini-fichero, y esta
vez s que lo puedo desensamblar:

000078: F0 C4       : 	mov	r12, r4
00007A: F0 D5       : 	mov	r13, r5
00007C: DA C0 16 36 : 	calls	0C0h, loc_C03616
000080: DA F5 8A 78 : 	calls	0F5h, loc_F5788A
000084: 48 41       : 	cmp	r4, #1
000086: 3D 12       : 	jmpr	cc_NZ, loc_0000AC
000088: DA C0 EA 36 : 	calls	0C0h, loc_C036EA
00008C: E6 FC 3C 00 : 	mov	r12, #3Ch
000090: F6 F4 0E FE : 	mov	mem_FE0E, r4; <<<< la linea buscada
000094: 5B CC       : 	divu	r12
000096: F2 F4 0C FE : 	mov	r4, mem_FE0C <<<< seguramente lo cambiar
00009A: 3D 08       : 	jmpr	cc_NZ, loc_0000AC
00009C: E6 FC 24 14 : 	mov	r12, #1424h
0000A0: E6 FD 43 00 : 	mov	r13, #43h
0000A4: E6 FE 55 00 : 	mov	r14, #55h
0000A8: DA CA 16 AF : 	calls	0CAh, loc_CAAF16


Como se puede observar, este cdigo del ME45v28 es muy parecido al
del SL45iv56 en 001F00, aunque cambian las direcciones de las rutinas.
As, puedo cotejar entre las flash del SL45iv56 y del ME45v28 .

Similarmente corto y analizo el trozo en 0x20b0e0 :

00003A: 46 FC FF 00 : 	cmp	r12, #0FFh
00003E: FD 09       : 	jmpr	cc_ULE, loc_000052
000040: F0 4C       : 	mov	r4, r12
000042: E6 FC 3C 00 : 	mov	r12, #3Ch
000046: F6 F4 0E FE : 	mov	mem_FE0E, r4
00004A: 5B CC       : 	divu	r12
00004C: F2 F4 0E FE : 	mov	r4, mem_FE0E
000050: DB 00       : 	rets

que no se parece en nada al original.

As que parece que el parche para el ME45FubuV28.fls tiene que
cambiar 0x202390 para apuntar a mi rutina.

Inciso: si tuviera un editor hexadecimal potente, podra posicionarme en
cualquier byte, y desde all hacer que extrajera un trozo de bytes
para invocar al   sfe  .
Lamentablemente no conozco ningn editor que permita hacer eso. Quizs Emacs?

En resumen, por ahora ya s dnde tengo que parchear. Ahora me queda
saber porqu el parche original cambia esta posicin y lo redirige a
calls   0C7h, loc_C7D110
y en cambio el cdigo nuevo se localiza en 27D6EA (en realidad, 0xC7D6EA, debido
a que la memoria esta desplazada 0xA00000 bytes respecto al fichero)

La zona 27D6EA es un bloque de FF FF (o sea, vacio) desde 27D07A hasta 27ECFF.

Una vez aclarado esto, hay que convertir la rutina 27D6EA-27D70E.
Solo hay saltos relativos, y dos llamadas a C30014, as que va a
tocar desensamblar esto.
Como antes, empiezo antes de 230014 para ver si lo anterior tiene sentido

sfe d SL45iv56.bin,230000,180

230000: DA C2 B8 EB :   calls   0C2h, loc_C2EBB8
230004: E0 0C       :   mov     r12, #0
230006: DA C3 D4 00 :   calls   0C3h, loc_C300D4
23000A: DA E6 90 44 :   calls   0E6h, loc_E64490
23000E: 5E 0B       :   bclr    STKUN.5
230010: 6E 0B       :   bclr    STKUN.6
230012: DB 00       :   rets
;----------------------------------------------------
                                                  ;<<<<<aqui entrar
230014: 88 80       :   mov     [-r0], r8 ; guarda r8 en la pila
230016: F0 8C       :   mov     r8, r12 ; usa r12. Bien, porque lo asign antes
230018: 46 F8 32 00 :   cmp     r8, #32h  ; en mi caso, puede ser #2Fh o #0h
23001C: 2D 19       :   jmpr    cc_Z, loc_230050
23001E: 46 F8 31 00 :   cmp     r8, #31h
230022: 2D 16       :   jmpr    cc_Z, loc_230050
230024: 46 F8 34 00 :   cmp     r8, #34h
230028: 2D 25       :   jmpr    cc_Z, loc_230074
...... mas comparaciones de r8
230046: 2D 24       :   jmpr    cc_Z, loc_230090
230048: 46 F8 0A 00 :   cmp     r8, #0Ah
23004C: 2D 21       :   jmpr    cc_Z, loc_230090
23004E: 0D 29       :   jmpr    cc_UC, loc_2300A2 ;<<si r8 es >0, salta.
;----------------------------------------------------
230050: E0 2C       :loc_230050;<<llego aqu en la primera llamada, desde 27D6FA
230050: E0 2C       :   mov     r12, #2
230052: 88 C0       :   mov     [-r0], r12
230054: E0 0D       :   mov     r13, #0
230056: 88 D0       :   mov     [-r0], r13
230058: E6 FC C0 34 :   mov     r12, #34C0h
23005C: E6 FD 0E 00 :   mov     r13, #0Eh
230060: E0 1E       :   mov     r14, #1
230062: F0 F8       :   mov     r15, r8
230064: DA C1 30 AA :   calls   0C1h, loc_C1AA30
230068: 08 04       :   add     r0, #4
23006A: 0D 23       :   jmpr    cc_UC, loc_2300B2
..............
2300A2: E6 FC C0 34 :   mov     r12, #34C0h  ;<<aterrizo aqu en la
                                              segunda llamada, desde 27D708
2300A6: E6 FD 0E 00 :   mov     r13, #0Eh
2300AA: E0 0E       :   mov     r14, #0
2300AC: F0 F8       :   mov     r15, r8
2300AE: DA C1 30 AA :   calls   0C1h, loc_C1AA30
2300B2: 98 80       : loc_2300B2:
2300B2: 98 80       :   mov     r8, [r0+]
2300B4: DB 00       :   rets

En ambos casos, llama a C1AA30. La diferencia es que en el primer caso ha hecho
mov     r14, #1
y en el segundo ha hecho
mov     r14, #0

Parece que en el primer caso hace algo, y en el segundo caso deja de hacerlo.

Ahora tengo que buscar la rutina similar para mi modelo.
No es bueno confiar en los nombres de las variables usadas, ya que cambian
entre versiones; es mejor basarse en las intrucciones.
Buscando los bytes de
23001E: 46 F8 31 00 :   cmp     r8, #31h
en el fichero ME45FubuV28.fls, se encuentran en varias posiciones, pero en
2C0DB0 (menos algunos bytes) al desensamblar queda:

2C0D88: DA CB 24 F7 :   calls   0CBh, loc_CBF724
2C0D8C: E0 0C       :   mov     r12, #0
2C0D8E: DA CC 56 0F :   calls   0CCh, loc_CC0F56
2C0D92: DA F7 B8 8B :   calls   0F7h, loc_F78BB8
2C0D96: 7E 0B       :   bclr    STKUN.7
2C0D98: 8E 0B       :   bclr    STKUN.8
2C0D9A: DB 00       :   rets
;------------------------------------------------
2C0D9C: 88 80       :   mov     [-r0], r8
2C0D9E: F0 8C       :   mov     r8, r12
2C0DA0: DA CA 6A 95 :   calls   0CAh, loc_CA956A
2C0DA4: 46 F8 32 00 :   cmp     r8, #32h
2C0DA8: EA 20 7A 0E :   jmpa    cc_Z, loc_2C0E7A
2C0DAC: 46 F8 31 00 :   cmp     r8, #31h
2C0DB0: EA 20 82 0E :   jmpa    cc_Z, loc_2C0E82
2C0DB4: 46 F8 34 00 :   cmp     r8, #34h
2C0DB8: EA 20 A6 0E :   jmpa    cc_Z, loc_2C0EA6

Que de nuevo se parece un montn a la rutina original de
SL45iv56.bin que estaba en 230000

As que el parche para el ME45FubuV28.fls tiene que llamar a 0x2C0D9C para
activar el vibrador.

Otro hack para la lista.


PRIMER PROGRAMA
***************
Como es obvio, el mvil tiene un puerto serie que permite la comunicacin
con el ordenador. Este puerto est manejado directamente por el micro C166 ; no
hace falta ningun artificio raro.
La manera de escribir en el puerto es a travs de DMA: se pone el dato
en una posicin de memoria, se activa un flag, y ya est.
El registro de memoria es S0TBUF y est en la direccin de memoria 0xFEB0 .
Su significado es 'Serial Channel 0 Transmit Buffer Register'
Para meter un dato, se puede usar una instruccin del tipo
mov     S0TBUF, r3
que se codifica como
F6 F3 B0 FE  (observar que los ltimos 2 bytes son 0xFEB0, en little-indian).

Para decir que el dato ya puede ser transmitido, se usa la instruccin
bclr    S0TIC.7
que pone a 0 el bit 7 de la direccin de memoria S0TIC , la cual est
en 0xFF6C y significa 'ASC0 Transmit Interrupt Control Register'
se codifica como
7E B6

Ahora hay que esperar a que el byte est transmitido.
Esto se sabe porque el micro pone a 1 el mismo bit.
As que espero hasta que valga 1 antes de seguir:
jnb     S0TIC.7, aqui_mismo
y se codifica como
9A B6 FE 70

Normalmente se tiene el dato a transmitir en alguna zona de la memoria, aunque
para este ejemplo voy a transmitir la letra 'V', cuyo valor es 0x56, y que
almaceno temporalmente en rl3.
Suponiendo que estoy en la posicin 0x0485C6, la rutina queda:
0485C6: E7 F6 55 00 :   movb    rl3, #56h
0485CA: C0 63       :   movbz   r3, rl3
0485CC: F6 F3 B0 FE :   mov     S0TBUF, r3
0485D0: 7E B6       :   bclr    S0TIC.7
0485D2: 9A B6 FE 70 : loc_0485D2:
0485D2: 9A B6 FE 70 :   jnb     S0TIC.7, loc_0485D2

El hecho de que las dos ultimas lneas aparezcan duplicadas es la manera
que tiene el des-ensamblador   sfe   de definir una etiqueta.

Aprovechando que ya conozco algo del ejemplo del buscaminas, s que llama
a 0x485AA, as que en vez de aplicar el parche para eliminiar la pantalla
de espera, decido meter all mi rutina.
La rutina original empieza en 485AA y acaba en 485FE por lo que dispongo
de mucho espacio libre.
Pongo todos los bytes a NOP (no=operacion), cuya codificacin es
CC 00 : nop
y luego los bytes de mi rutina, desde 0485C6 hasta 0485D2
Mas claramente:
        nop
        nop
        ...
        nop
        nop
        movb    rl3, #55h
        movbz   r3, rl3
        mov     S0TBUF, r3
        bclr    S0TIC.7
loc_0485D2:
        jnb     S0TIC.7, loc_0485D2
        nop
        nop
        ...
        nop
        rets
Ensamblado quedar algo asi como:
CC00 CC00 ..... CC00  E7F65500  C063  F6F3B0FE  7EB6  9AB6FE70  CC00 ..... CC00

Ya con todo preparado meto el parche en el telfono, conecto el
terminal de Windows, y cuando empiezo a jugar al buscaminas, no me
sale la pantalla de 'Cumpliments to Microsoft' sino que escribe la
letra 'V' en el hyperterminal.
Es importante conectarlo al ordenador. Si no, no podr transmitir
el byte 'V' y entrara en un bucle infinito.

Un momento! Ahora el buscaminas desde E589BA vuelve a llamar
a 485AA, aunque 485AA no hace lo que debera, sino que imprime la 'V'.
Lo malo es que hay otros muchos mens que dejan de funcionar, y en su
lugar imprimen 'V'.
Se ve que 485AA es un punto comn de entrada para varias rutinas.
Esto me puede servir para saber quien llama a esta rutina, aunque seguramente
debera restaurar el comportamiento original para que todo funcione como antes.

De todos modos ya tengo algo as como un mini-debugger. Si quiero saber cuando
una rutina es llamada, slo tengo que llamar a mi rutina de enviar datos.
Claro que primero tengo que ver cmo guardo los valores de rl3 y r3, porque
yo los modifico en mi rutina.

Pero eso corresponde a otro hack.

TRACEANDO
*********
Ahora voy a mejorar el programa anterior para que sea mas til.
En corto, har una rutina que se puede llamar desde cualquier sitio, y me
dir desde dnde me han llamado.
El nombre apropiado sera   print_donde_estoy
O sea, que si mi rutina es llamada desde 89BA, imprimir precisamente 89BA.
Esto me permitir modificar masivamente (con cuidado) la Flash
y me ir diciendo los sitios por los que va pasando.

#include C166.inc
org 0485BCh
   nop
   nop
   nop
   mov     [-r0], r3
   pop     r3
   push    r3
   mov     S0TBUF, r3
   bclr    S0TIR
 aqui_mismo1:
   jnb     S0TIR, aqui_mismo1
   movbz   r3, rh3
   mov     S0TBUF, r3
   bclr    S0TIR
 aqui_mismo2:
   jnb     S0TIR, aqui_mismo2
   mov     r3, [r0+]
   rets
   nop
   nop
end

Para compilarlo:
sfe a puerto.asm d

Primero incluyo el fichero  C166.inc  que contiene constantes comunmente usadas.
Este fichero es fcil de encontrar, aunque quizs con otros nombres.
Se puede encontrar en D:\Keil\C166\asm\REG166.INC si instalas el compilador Kiel
Tambien lo encontraras al instalar el 'COSMIC ST10 Evaluation Kit'

Esto me permite, entre otras cosas, usar los nombres S0TBUF y S0TIR sin
necesidad de especificar la direccin de memoria en la que estn.

A continuacin digo dnde hay que poner la rutina. Slo es necesario
si hago llamadas absolutas a otras funciones en este mismo fichero.
Como yo uso direcciones relativas, no lo necesito.
Siempre es buena idea incluirlo porque cuando se compila dir
automticamente las direcciones en las que se colocar.

Luego uso varios   nop   simplemente para localizar mi rutina en memoria.
Cuando quiero localizar mi rutina en la memoria, me resulta ms fcil
buscar   nop nop nop   en vez de ir a la direccin 0485BC.
Adems as s el hueco de que dispongo si quiero ampliar
el cdigo con nuevas instrucciones.
El siguiente paso es guardar en la pila local los datos que voy a usar.
En todos los micros que yo conozco, hay una pila para guardar datos.
Se usan las instrucciones  push  y  pop  para meter y sacar datos.
Adems, cuando se llama a una rutina, la rutina llamante almacena en la pila
la direccin de la siguiente instruccion, para saber dnde hay que retornar.
En algunas arquitecturas la pila se usa para guardar los argumentos que
se pasan entre una rutina y otra, adems de los parametros de retorno.
Pero el C166 tiene un mecanismo extra. Dado que est pensado para soportar
mltiples tareas, existen unas variables llamadas 'descriptores de contexto'.
Cada tarea tiene una memoria de 4 Kb en la que guardar sus variables. Cuando
se produce un cambio de contexto (una reanudacin de una tarea) simplemente
se conmuta la memoria privada. Todas las variables son restauradas a sus
valores, que fueron guardados al efectuarse el cambio de contexto precedente.
Una de dichas variables es r0 , que se suele usar como una mini-pila local, sin
interferir con la pila comunitaria.

La instruccin
mov     [-r0], r3
mete r3 en la pila local, y decrementa   r0  para que haya
sitio para otros nuevos valores.

La siguiente intruccin
pop r3
saca de la pila el valor que haya, que resulta ser la direccin de la
rutina que nos ha llamado.
Tcnicamente en la pila est el valor del IP: Instruction Pointer

Luego lo vuelvo a meter , ya que se ha quedado en   r3

Entonces meto la parte baja de   r3  en el buffer de transmisin S0TBUF.
Limpio el flag S0TIR para que empiece a transmitir y espero hasta que se enva.
Necesitar un programa tipo hyperterminal o algo mejor para recibir
este dato, ya que por ahora va en binario.

A continuacin meto el otro byte de   r3  para transmitir el byte alto de IP.

Recupero   r3  de la pila local, y retorno con
rets

Para generar el parche:
sfe a puerto.asm p

Antes de que los mas quisquillosos se me echen al cuello, advierto que ya
me he dado cuenta de que esta rutina tiene varios fallos:
-no tiene cuidado con los flags. Debera guardarlos, pero no lo hago.
-no considera las interrupciones. Esta rutina no se puede llamar desde otra
 que haya deshabilitado las interrupciones o este sirviendo una trampa (trap).
-es pesada de llamar. Necesito 4 bytes, y siempre deber ser considerada
 como una rutina en otro segmento, ya que su retorno es con  rets.

Si quieres una rutina mucho mejor, existe un parche llamado
ATCGSN
que permite leer cualquier zona de memoria, escribirla (slo la RAM) , llamar
a una rutina, o buscar datos en la memoria.
No slo eso, sino que hay un programa ATDebugger que es un
buensimo interface para este parche.
Una vez metido este parche en el telfono, se puede usar con el
cable normal, y fuera del 'Service mode'.
Se pueden leer y escribir las variables SFR y los registros r0-r15, aunque
par su propia operatoria, tambin los modifica.
En mi caso no me vale para mis propsitos porque lo que yo quiero es saber los
puntos de entrada de los mens, y eso slo lo puedo hacer yendo uno por uno.
Ya he averiguado que algunos (al menos 10, sin contar el buscaminas) de ellos
van a parar a 0x485AA, y esto me proporciona una base para sustituirlos
por mis propias rutinas.
Por ejemplo, el menu Juegos->Reversi->Opciones->Ayuda
a partir de ahora no dir ayuda, sino que har lo que yo quiera.
Y lo que quiero es que imprima en la pantalla del mvil la direccin desde
la que lo llamo. El mismo dato que se manda por el puerto, pero por pantalla.


IMPRIMIR
********
Para averiguar cmo se hace para imprimir, desensamblo un parche
llamado Thermometer.vkp
Este parche imprime en la pantalla la temperatura de la batera.
S, el mvil tiene un pequeio termmetro para que se apague
automticamente cuando hace mucho calor o mucho frio.
No tiene mucha precisin, y dado que est cerca de la batera, no
reacciona rpidamente a los cambios de la temperatura ambiente.
El parche saca el dato de 0x0C2C08 , hace algunos clculos, asigna
r12=x , r13=y, r14=0x13A+un_indice y llama a 0x0E5ABA4
Tiene en total 60 lineas en ensamblador, pero no voy a aburrir con los detalles.
La asignacin de r12 y r13 est clara. La pantalla mide 101x54 y se
empieza a contar desde la esquina superior izquierda.
Estas variables conendrn las coordenadas donde quiero imprimir.
La rutina en 0x0E5ABA4 no imprime una letra, sino un dibujo. Siguiendo las
indicaciones de antes para usar el 'Siemens Picture Change' , veo que en
la posicin 0x13A esta el '0', por eso tiene que hacer r14=#13Ah.
Para imprimir el '1', el ndice es 0x13A+1=0x13B, y as hasta el '9'.
Como mi dato es una palabra de 16 bytes, lo escribir como un cdigo
hexadecimal de 4 letras 0-9A-F
Por ejemplo, si la direccin es 0x89BA, imprimo los caracteres 8, 9, B, A.
Pero lamentablemente el ndice 0x13A+0x0A no apunta a la letra 'A', sino a
un rectngulo de 6x9 totalmente vaco.
Es mas, el ndice 0x13A+0x0B = 0x145 apunta a un dibujo de 21x7 de una llave.
No todo est perdido. Usando 'Siemens Picture Change' puedo cambiar
los dibujos, incluso su tamanio.
En un momento edito desde 0x144 hasta 0x14A para que contengan los dibujos
 de las letras 'A' hasta 'F', y los meto de nuevo en el tlefono.

Basicamente, si r3 contiene el semi-byte (0-F) a imprimir:
   mov	r12, #32h ; x
   mov	r13, #22h  ; y
   mov	r14, r3
   and	r14, #000Fh
   add	r14, #13Ah ; apuntador base para dibujos
   calls 0E5ABA4h

El segundo problema al que me enfrento es que no voy a tener espacio
suficiente en 0C485AAh . Pero la memoria tiene muchas areas vacas.
Escojo 0C7FAE0, donde puedo usar 256 bytes.
Tambin podra usar 0x2D0000, donde tengo 64kb libres.
En el C35i hay 8 bloques de 64Kb que no se usan. Esto da para escribir muchos
programas en estas zonas libres.
En particular, desde 0x2C6ED2 hasta 0x334000 hay 436Kb libres.

Para imprimir toda la direccin IP tengo que llamar a esta
subrutina 4 veces con distintas posiciones x.
Cada dibujo mide 6x9 as que tengo que variar 'x' en 6+1 pixels.


-------------------------
base 0C00000h ; autoconvierte las direcciones. La memoria empieza en 0x0C00000
#include C166.inc
#define  imprime 0E5ABA4h ; Rutina de la EPROM que imprime un icono
org 0C485AAh ; direccin original de la llamada

   push PSW ; guardo los flags. Slo se pueden guardar en la pila
   mov  [-r0], r3 ; guardo los registros que modificar
   pop r3   ; saco los flags de la pila
   mov  [-r0], r3 ; y los meto en la pila local
   pop     r3     ; extraigo InstructionPointer de la pila
   push    r3     ; y lo meto de nuevo. Ahora lo tengo en r3
   movb     S0TBUF, rh3 ; Primero saco el byte mas significativo
   bclr    S0TIR ; lo mando al puerto
 aqui_mismo1:
   jnb     S0TIR, aqui_mismo1
   movb     S0TBUF, rl3 ; luego la parte baja: el menos significativo
   bclr    S0TIR
 aqui_mismo2:
   jnb     S0TIR, aqui_mismo2
   calls imprime_ip ; una vez 'puerteado', lo muestro en pantalla
   mov     r3, [r0+] ; recupero los flags
   push    r3 ; meto los flags en la pila
   mov     r3, [r0+] ; recupero el registro r3
   pop PSW ; saco los flags de la pila
   rets

org 0C7FAE0h ; no hay espacio suficiente en 0C485AA. Pero aqu hay un montn
imprime_ip: ; imprime r14 de derecha a izquierda . Si r14=ABCD, imprime
            ; primero D , luego C, despues B, y al final A
            ; pero como la posicionX se va decrementanto, aparece ABCD
   mov	[-r0], r12 ; guardo los registros que uso
   mov	[-r0], r13
   mov	[-r0], r14

   mov	r14, r3 ; contiene la palabra (16 bits) a imprimir
   mov	r13, #2Ah  ; y
   mov	r12, #39h ; x
   callr mi_imprime ; imprime solo el nibble (4-bits) menos significativo

   mov	r14, r3
   shr  r14, #04h  ; ahora imprimo el segundo nible menos significativo
   mov	r12, #32h ; a la _izquierda_ del anterior dato
   callr mi_imprime

   mov	r14, r3
   shr  r14, #08h
   mov	r12, #2Bh ; x
   callr mi_imprime

   mov	r14, r3
   shr  r14, #0Ch
   mov	r12, #24h ; x
   callr mi_imprime

   mov     r14, [r0+] ; recupero los registros
   mov     r13, [r0+]
   mov     r12, [r0+]

   rets

mi_imprime:
   and	r14, #000Fh ; me quedo con la parte baja
   add	r14, #13Ah ; base para pictures
   mov     [-r0], r13
   mov     [-r0], r3
   calls imprime
   mov     r3, [r0+]
   mov     r13, [r0+]
   ret
end
--------------------------
Notar que he cambiado el orden de los bytes para que los imprima en big-endian.

Como antes, para compilar:
sfe a puerto_pantalla.asm d

Y para generar el parche:
sfe a puerto_pantalla.asm p

Lo meto en el mvil, navego por los mens, y veo la direccin tanto en el
hyperterminal como en la pantalla del mvil en la zona que hay abajo, en medio.

La rutina anterior tampoco es perfecta. Ahora guardo bien los flags, pero
todava hay otros detalles que no tengo en cuenta, ej. las interrupciones.
Al menos, ahora tengo algo que se puede llamar desde cualquier sitio.
No afectar al programa que llame a mi rutina, pero a m me ser util.
Ciertamente me pueden llamar desde otras rutinas en otros segmentos, pero
todava no imprime correctamente la direccion completa.
Para ello hara falta extraer tambin el CSP (Code Segment Pointer) aunque
esto es ms delicado, pues hace falta saber si me han llamado con una
instruccin CALLS (Call Inter-Segment Subroutine, que si guarda en CSP) o
desde una instruccin CALLA (Call Subroutine Absolute),
CALLI (Call Subroutine Indirect),
o CALLR(Call Subroutine Relative), las cuales no usan CSP.

MEMORIA
*******
Espero que haya quedado suficientemente claro que la zona en la que estn
almacenados los programas en el C35i empieza en la Flash a partir de 0xC00000 .
El telfono tiene otras zonas de memoria:
0x000000 = inicio. Mide 0x000200
0x000200 = DRAM. Mide 0x00EE00
0x00F000 = SFR/ESFR. Mide 0x001000 y almacena los registros.
0x010000 = ROM del chip. Mide 0x008000
0x010800 = Word-writeable. Mide 0x007800
0x100000 = RAM. Mide 0x040000
0xC00000 = Fullflash. Mide 0x400000
La ltima direccin es 0xFFFFFF
Estos 16Mg de memoria ocupan un espacio de direcciones
de 2^24 bits, es decir, 3 bytes.
Hay 2 maneras de agruparlos:
-en 256 bloques de 64Kb, llamados segmentos. Se usa la notacin 0x123456
-en 1024 pginas de 16Kb. Se usa notacin 048:3456
La formula para pasar entre uno y otro es dividir entre 0x4000
Asi, 0xFCA123=3F2:2123 , porque 0x3F2*0x4000+0x2123=0xFCA123
Algunos programas tales como el 'AT Debugger' usan notacin de
pginas, mientras que el resto usan segmentos.
Es conveniente usar la calculadora incluida en 'AT Debugger' para hacer
las transformaciones.

Para acceder a la memoria se puede direccionar de 3 maneras distintas:
-Cdigo, usando el Puntero de Segmento de Cdigo. Tambin llamado Modo Corto
 Es el modo que todos imaginamos; usa la direccin completa:   jmpr loc_FCA123
-Datos, usando Puntero a Pgina de Datos. Tambin llamado Modo Largo.
 Hay 4 registros DPP0, DPP1, DPP2, DPP3 que apuntan a una pgina.
 Se combina con otro valor (offset) para obtener la direccin completa:
  mov DPP0, #03F2h
  mov r12, #2123h
 otro ejemplo : jmps #03F2h, #2123h
-Direccionamiento de Datos via Modo Extendido.
 -Extensin mediante segmento:
  Primero se usa una instruccin para usar un segmento alternativo, y
  luego la instruccin para tomar el dato:
   extp #0FCh, #1h
   mov r12, #0A123h
 -Extensin mediante pgina:
  Primero se usa una instruccon para usar una pgina alternativa, y
  luego la instruccion para tomar el dato:
   extp #03F2h, #1h
   mov r12, #2123h

Hay instrucciones que funcionan con segmentos, y otras con pginas:
JMPS seg, caddr ; salta a una direccin 'caddr' en un segmento 'seg'
JMPA cc, caddr ; salta a una direccin en el mismo segmento

CALLS seg, caddr ; llama a la subrutina en 'caddr' del segmento 'seg'
CALLA cc, caddr ; llama a la subrutina en la direccin absoluta 'caddr' .

RET ; retorna desde una subrutina en el mismo segmento
RETS ; retorna desde una subrutina entre segmentos


El segmento 0, que va desde 0x000000 hasta 0x010000 ocupa 64 Kb (como todos los
dems) y cuando se cambia algun dato en el segmento 1 (direccion 0x100000),
tambin resulta modificado en el segmento 0.
O sea:
   mov r3, #1234h
   extp #40h, #1h
   mov	00h, r3
Escribe 1234 en 40:0000 , es decir, 0x100000
Pues bien: el dato en 00:0000 tambin contiene 1234.
De hecho, para escribir en el segmento 0, debo hacerlo en el segmento 1, y
se copiar automaticamente.
Es por esto que hablar indistintamente de 0x100000 o de 0x000000.

Para leer de la memoria, se puede usar el 'Siemens Debugger' o el 'ATDebugger'.
O tambien puedo modificar mi programa para que lo haga.
Navegando por los menus aprendo que:
Juegos->Wayout->Highscore llama a 3E26
Juegos->Buscaminas->Highscore llama a 1F3A
Lo primero que debo es discernir cual men me ha llamado.
Por simplicidad, solo chequeo el byte menor (ser #26h o #3Ah)
La direccin de memoria que voy a usar es 1000D4=40:00D4
As que renombro la rutina imprime_ip para llamarla imprime_r3, y queda as:

   cmpb  rl3, #26h ; vengo de Juegos-Wayout-Highscore
   jmpr    cc_Z, go_wayout

   cmpb  rl3, #3Ah ; vengo de Juegos-Buscaminas-Highscore
   jmpr    cc_Z, go_mines

go_wayout:
   extp #40h, #1h
   mov	r3, 0D4h ; lee la memoria
   calls imprime_r3
   jmpr    cc_NZ, go_fin
go_mines:
   mov r3, #1234h
   extp #40h, #1h
   mov	0D4h, r3 ; escribe '1234' en la memoria
   calls imprime_r3
   jmpr    cc_NZ, go_fin
go_fin:
   mov     r14, [r0+] ; recupero los registros
   mov     r13, [r0+]
   mov     r12, [r0+]
   mov     r5, [r0+]
   rets

Hala, ya puedo escribir donde me apetezca, y leerlo despues.
Claro que esto no es muy verstil.
Tendra que permitir elegir la zona de la memoria donde quiero leer/escribir, y
pedir tambin el dato en caso de que quiera escribirlo.
Pero para eso ya estan los otros programas que he mencionado antes.

Una cosa curiosa es que el 'Siemens Debugger' parece tener problemas a la hora
de leer algunas direcciones, en particular me resetea el mvil cuando intento
acceder a direcciones entre 0x00E000 y 0x00E400.
Funciona si uso 0x10E000 , y los datos parecen ser correctos.
Por contra, el 'ATDebugger' tiene otro fallo y es que slo me deja
escribir 5  6 comandos. Al cabo del tiempo, la paridad del puerto cambia y el
programa se vuelve loco. La solucin es apagar en mvil, lo cual es un fastidio
cuando he tardado media hora en preparar el escenario correcto.
Por eso me he acostumbrado a usar ambos programas y verifico los datos 2 veces.
El 'ATDebugger' necesita que el mvil est encendido, mientras que
el 'Siemens Debugger' necesita que est apagado, para meter el BootStrap.
Pero en el C35i es posible usar un rodeo:
-encender el mvil
-pulsar el boton de 'Iniciar modo de servicio'
-esperar a que se queje de que el modo BFB no se ha iniciado
-pulsar el boton de 'Salir del modo de servicio'
-pulsar de nuevo el boton de 'Iniciar modo de servicio'
-ahora ya se tiene aceso a toda la funcionalidad del 'Siemens Debugger'.

Bueno, ahora ya puedo manejarme sin problemas con la memoria.

DESARMANDO TRAMPAS
******************
La manera normal de llamar a una subrutina es con JMPS o CALL.
Pero existe una manera mas cmoda de llamar a rutinas que se
usan habitualmente: los traps.

Desde la direccin 0x000000 hasta 0x000200 hay unas rutinas muy
breves que gestionan los errores que pueden suceder en tiempo de ejecucin.
Recordar que el segmento 0x100000 es una copia de 0x000000 .
Segn el manual, en la posicin 0 hay una rutina que se llamar cuando
se produce un RESET por hardware, por software, o Watchdog.
Brevemente, un Watchdog es una rutina invocada por un dispositivo
externo -tpicamente el reloj- que tiene que ser respondida por el programa.
Si no es respondida, el dispositivo entiende que el programa se ha colgado, y
hace un reset del procesador.
Slo hay una rutina que gestiona estos 3 eventos, pero se puede saber cual
de los eventos ha sucedido mirando el valor del registro SFR
llamado 'WDT Control Register' en la direccin FFAE.
Si el bit 1 (llamado WDTR=Watchdog Timer Reset Indication Flag) vale 1, entonces
 es Watchdog quien llama.
Si el bit 2 (llamado SWR=Software Reset Indication Flag) vale 1, entonces
 es un RESET por Software
Si SWR vale 0, entonces es un RESET por Hardware.
La rutina llamada desde 0x000000 hace simplemente:
jmps 0D4h, 04704h
Desensamblando a partir de 0xD44704h veo que hace
mov     CC7, #10h
trap    #30h
rets
Esto es: pone a #10h el registro SFR llamado CC1, que est en la posicin FE8E
Luego llama al  trap  nmero #30h

Un  trap  funciona igual que una interrupcin RESET de las anteriores; se
mira cual es el nmero de  trap  en la tabla que empieza en 0x000000 , y
se llama a la rutina.
Para calcularlo, se toma el numero de trap y se multiplica por 4.
El trap #30h llama a la rutina en 0x0000C0, pues 30h*4h=C0h
En 0x0000C0 hay:
jmps    0D4h, loc_D44A28
y en 0xD44A28 hay:
bfldh   PSW, #0F0h, #0F0h
extp    #3, #4
mov     mem_37AA, r0
mov     mem_37B6, mem_FE10
mov     mem_37B8, DPP0
mov     mem_37BA, DPP1
.......
La primera instruccin limpia todos los bits del registro SFR llamado
PSW (posicin FF10), que contiene los flags.
El bit 7 de la parte alta de PSW (bit 7+8=15) se pone a 1.
Esto hace que el procesador ejecute este trozo de cdigo en la mxima
prioridad, sin permitir que otras tareas lo interrumpan. Esto es normal
cuando se procesa una interrupcin.
luego hace que las siguientes 4 instrucciones usen el segmento #3.
Dichas 4 instrucciones hacen:
guardar  r0  en 3:37AA = 0x00F7AA
meter Context Pointer en 3:37B6 = 0x00F7B6
meter el Data Page Pointer DPP0 en 3:37B8 = 0x00F7B8
meter el Data Page Pointer DPP1 en 3:37BA = 0x00F7BA
Y un montn de cosas ms que involucran muchos registros y no entiendo lo
que hacen. No me apetece ponerme a desensamblar 400 pginas de ensamblador.
Pero el concepto est claro, no?

En total hay 128 traps, y muchas de ellas saltan a 04704h, por lo que
entiendo que es una rutina de propsito general capaz de interpretar
casi todas las situaciones que se producen.
Sin embargo, hay unas pocas  traps que saltan a otras rutinas:
El  trap  20h salta a 0xC3FFFA
en 0xC3FFFA hay:
rets
Esta es la manera ms simple de retornar de un  trap : no hacer nada.

El  trap  35h salta a 0xCCFFEE
en CCFFEE hay:
bset    mem_FE0C.13
bset    STKOV.6
calls   0D3h, loc_D337B0
reti
Y en D337B0 hay:
bclr    CC5IC.6
bclr    CC14IC.6
bclr    CC10IC.6
extr    #1
bclr    CRIC.6
rets

O sea, que limpia el bit 6 de las variables del periferico CAPCOM1.
Esto no tiene mucho sentido para m, porque no todas las variables se limpian.
Ni tampoco se preservan los registros usados.
Es posible que este cdigo en realidad no se llame nunca.
Voy a investigar sobre esto.

Los  traps  es una manera eficiente de llamar a una rutina.
Para invocarlos, se usa la instruccion
trap #35h
que se codifica en los bytes
9B 6A
Buscando en la memoria estos datos, aparecen 2 veces:
Primera vez, en 0xDA48F6. Al desensamblar:
trap    #35h
xorb    7F78h, rl0
movb    PWMCON1, #4Dh
add     r0, r0
add     r0, r0
add     r0, r0
que no tiene mucho sentido, pues  "add r0, r0" no sirve de
mucho, y menos hacerlo 3 veces seguidas.

Segunda vez, en 0xDA6712. Desensamblando 8 bytes antes, en 0xDA670A :
DA6704: 79 53       :   orb     rh2, #3
DA6706: 96 F1 D2 7C :   cmpi2   r1, #7CD2h
DA670A: 41 43       :   cmpb    rl2, rh1
DA670C: 10 81       :   addc    r8, r1
DA670E: 38 86       :   subc    r8, #6
DA6710: 6A 59 9B 6A :   band    mem_FF36.10, S0RBUF.6
DA6714: 54 60 0F E2 :   xor     0E20Fh, PECC0
Veo que en realidad forman parte de la
instruccin "band mem_FF36.10, S0RBUF.6", que tampoco tiene mucho sentido.

Por ello deduzco que la aparicin de estos bytes es simple casualidad.
Quizs sea parte de un dibujo, o de datos. No es cdigo vlido.
Entonces, parece que nadie llama al  trap  35h... hasta ahora


HACIENDO TRAMPAS
****************
Como el C166 es un micro de 16 bits, todas las instrucciones
ocupan 2 o 4 bytes. Incluso la instruccin ms simple
NOP
se codifica como CC 00
Tambin es necesario que empiecen en una posicin par. En el ejemplo
anterior, si los bytes 9B 6A estuvieran en la direccin 0xDA6711, yo
sabra de inmmediato que no es una intruccion.
El mini-tracer de antes tiene un inconveniente: para llamarlo necesito hacer
CALLS 0xC485AAh
que se codifica como
DA C4 AA 85
y ocupa 4 bytes.
Sera mejor si ocupara solo 2 bytes. As podra sustituir
cualquier instruccin por una llamada a mi rutina.
Gracias a los  traps  puedo hacerlo:
-Establezco que el  trap  #35h salte a 0xC7FBC0
 Para ello solo tengo que variar la memoria 35h*4 para que haga
 jmps 0xC7FBC0h
 Es decir, poner bytes FA C7 C0 FB (little-indian) a partir de 0x0000D4
-En mi vctima, llamar a mi trap con
 trap #35h
 Es decir, poner bytes 9B 6A
-Imprimir la direccin que me ha llamado, y hacer lo que hubiera
 en la instruccin original

As, una rutina que sea:

98 90 : mov     r9, [r0+]
F0 C9 : mov     r12, r9
DB 00 : rets

la sustituir por:

98 90 : mov     r9, [r0+]
F0 C9 : mov     r12, r9
9B 6A : trap #35h
DB 00 : rets

La rutina de respuesta al trap es:

org 0C7FBC0h
mi_trap:
   mov     [-r0], r3 ; guardo r3 porque lo voy a sobrescribir
   pop r3 ; en la pila est IP , o sea, dnde ha saltado la trampa
   push r3 ; lo vuelvo a meter.
   calls imprime_r3 ; y lo imprimo
   mov     r3, [r0+]
   reti ; salir de la trampa
end

La rutina de inicializacin del trap es:
go_mines:
   mov r3, #0C7FAh
   extp #40h, #1h
   mov	0D4h, r3  ; direccin del trap #35h
   mov r3, #0FBC0h
   extp #40h, #1h
   mov	0D6h, r3
   calls imprime_r3
   jmpr    cc_NZ, go_fin

Para probar mi trampa, s que cuando pulso la tecla '#', originalmente llama a
D6D580: 9A 08 02 00 :   jnb     mem_FE10.0, loc_D6D588
Entonces sustituyo esos bytes por
9B6ACC00, que significa
trap #35h
nop

As que
-compilo el parche
-lo meto en el mvil
-activo el nuevo trap mediante el men buscaminas->Highscore
-verifico que la memoria 0x0000D4 contiene 'jmps 0x0C7FBC0h'
-pulso '#' en el teclado
-y me muestra la direccion D588, que es el offset de D6D588

Bueno, en realidad me muestra D6D588+2 , pues sta es la direccin
a donde volver despues de la trampa.
Tengo que modificar el parche para adems del offset tambien imprima el
segmento (0x00D6), pero eso es un detalle menor.
Recordar que una instruccin
trap
mete en la pila los valores:
-PSW: flags (Carry, Overflow, ...)
-CSP: Code Segment Pointer
-IP:  Instruction Pointer
Me ayudara todava ms si imprimiera los ltimos 10 valores de
la pila, y las variables r0, r1, r2, ...
Pero eso (ms o menos) es lo que hacen los programas  'Siemens Debugger' o
el 'ATDebugger'. Me permiten llamar a una subrutina, y me dicen el
estado de las variables.
Lo bueno es que yo lo he implementado haciendo que el telfono sea el punto de
partida. Ellos hacen que sea el ordenador el que tenga que invocar al mvil.

Para sacarle todo el partido que yo quiero, empiezo a sustituir un
montn de instrucciones en la Flash.
Por ejemplo, puedo cambiar todas las instrucciones
   mov r9, [r0+]
por
   trap #35h
Y anadir un ultimo paso en
mi_trap:
 ......
 mov     r3, [r0+]
 mov r9, [r0+]  ; <-nueva instruccion
 reti
end

Mejor todava es sustituir 
   rets
por
   trap #35h
As, cada rutina, en vez de salir, me llamar a mi_trap, donde puedo
mirar los valores que retorna a la subrutina llamante.
Entonces tengo que hacer que vuelva a su sitio original.
Voy a explicarlo con ms detalle.
Suponer que en 0xCC1110 hay:
0xCC1110 : E6 FC 11 00 : mov r12, #11h
0xCC1114 : DA 22 22 22 : calls 022h, loc_222222
0xCC1118 : 46 FC 22 00 : cmp r12, #22h

y en 0x222222 hay:
0x222222 : E6 FC 22 00 : mov r12, #22h
0x222226 : DB 00 : rets

Cuando 0x111110 se ejecuta, primero se pone r12=#11h, y la instruccin   calls
hace que en la pila se guarde el valor 0x111118 , pues sta es la siguiente
instruccin que se ejecutar cuando 0x222222 retorne.

Para activar mi trampa pongo a partir de 0x222222 :

0x222222 : mov r12, #22h ; esto no cambia
0x222226 : trap #35h     ; originalmente decia    rets

Y cambio mi trap para que no vuelva a la instruccin que sigue al trap, sino
a la siguiente instruccin de la llamada inicial:
mi_trap:
 ......
 mov [-r0], r6
 mov [-r0], r5
 mov [-r0], r4
 mov [-r0], r3
 pop r3 ; en la pila esta IP: 0x2226+2. No lo necesito
 pop r3 ; en la pila esta CSP: 0x0022. Tampoco lo necesito
 pop r6 ; en la pila esta PSW
 pop r5 ; en la pila esta el IP de la direccin que ha
        ;    llamado a la rutina que me ha llamado: 0x1114+4
 pop r4 ; en la pila esta el CSP de la direccin que ha
        ;    llamado a la rutina que me ha llamado: 0x00CC
 push r6 ; mete PSW de nuevo
 push r4 ; mete CSP (0x00CC) de nuevo
 push r5 ; mete IP (0x1114+4) de nuevo
 mov r3, r4
 calls imprime_r3
 mov r3, r5
 calls imprime_r3
 mov     r3, [r0+]
 mov     r4, [r0+]
 mov     r5, [r0+]
 mov     r6, [r0+]
 reti ; esto sacara IP, CSP, PSW
end

Llamo a la rutina 0xCC1110 y efectivamente al retornar desde loc_222222, llama
a mi trampa e imprime 0xCC1118 .

Parece que la trampa funciona bien.

DESMONTANDO TRAMPAS VIEJAS
**************************
Para tracear una funcin necesito que caiga en alguna de mis trampas.
Como no tengo ni idea de donde comenzar la funcin, lo mejor es poner
muchas trampas y confiar en que tarde o temprano caiga en alguna.
Pero si pongo una trampa al azar en una instruccin   rets  cualquiera, tengo
que asegurarme de que la trampa est en buenas condiciones.
En otras palabras: si sustituyo     rets    por    trap #35h   , tengo que
estar seguro de que el  trap #35h va a saltar a 0xC7FBC0. Esto es, que la
direccin 0x0000D4 contiene 'jmps 0x0C7FBC0h'.
Si miro esta zona de memoria, veo que hay
0000D4: FA CC EE FF :   jmps    0CCh, loc_CCFFEE
?Quien ha puesto esos datos? Porque yo tambin los voy a poner, y
el ltimo que los ponga, gana la carrera!
Busco en la Flash algo que tenga que ver con CCFFEE y veo que los
bytes EE FF (Recordar little-indian) aparecen 25 veces. Los desensamblo
todos en 25 minutos, y veo que uno de ellos hace
D48B02: E6 FC EE FF :   mov     r12, #0FFEEh
D48B06: E6 FD CC 00 :   mov     r13, #0CCh
D48B0A: DA D3 7E 38 :   calls   0D3h, loc_D3387E
Humm, tambien aparece cerca el dato #0CCh , lo cual es bastante interesante.
Desensamblo loc_D3387E para ver lo que hace:
D3387E: 1E E7       :   bclr    DP6.1
D33880: 88 C0       :   mov     [-r0], r12
D33882: 88 D0       :   mov     [-r0], r13
D33884: E6 FC 35 00 :   mov     r12, #35h
D33888: 98 E0       :   mov     r14, [r0+]
D3388A: 98 D0       :   mov     r13, [r0+]
D3388C: DA D4 BA 93 :   calls   0D4h, loc_D493BA
D33890: D1 80       :   extr    #1
D33892: E6 B5 0F 00 :   mov     CRIC, #0Fh
D33896: 0A 92 30 30 :   bfldl   CCM5, #30h, #30h
D3389A: DB 00       :   rets
Fantstico: usa r12 y r13, y ademas hace algo con #35h , que es
justamente la trampa que yo intento poner.
Investigando un poco ms veo que loc_D493BA pone r1 y r13 en la memoria
apuntada por r12*4. Eso es coherente con mis datos, y loc_D493BA resulta
ser una rutina genrica para estabecer el salto de las trampas.
As que tengo que deshabilitar esta rutina, o bien cambiar
D48B02: mov     r12, #0FFEEh
D48B06: mov     r13, #0CCh
por
D48B02: mov     r12, #0FBC0h
D48B06: mov     r13, #0C7h

pues  mi_trap  est en    org 0C7FBC0h.

Ahora me enfrento con otro problema: ?que pasa si sustituyo
un  rets   por     trap #35h , pero todava no se ha puesto la trampa?
O sea, ?y si todava no se ha pasado por D48B02?
Pues que saltar a 0x0000D4, que apuntar a la nada sideral. Cuelgue asegurado.
Para solucionarlo tengo que hacer que mi trampa se ponga realmente pronto.

Lo primero que se me ocurre es que el  trap #0h  debe ponerse muy pronto, ya
que es la rutina del Watchdog.
Tras un rato de bsqueda encuentro:
D44714: 88 80       :   mov     [-r0], r8
D44716: E0 08       :   mov     r8, #0
D44718: F0 C8       : loc_144718:
D44718: F0 C8       :   mov     r12, r8
D4471A: E6 FD 04 47 :   mov     r13, #4704h
D4471E: E6 FE D4 00 :   mov     r14, #0D4h
D44722: DA D4 BA 93 :   calls   0D4h, loc_D493BA
que establece la direccin 0xD44704 como destino del trap #0h.
Por supuesto, hace uso de la rutina loc_D493BA para establecer la trampa.
Ahora imagina el flujo del programa como una gran red. Existe un punto de
partida P0 y un destino P9 (la pulsacin de la tecla '#'). En algn
punto P4 del camino voy a establecer la trampa. Tengo que evitar que
los puntos P2 (entre P0 y P4) llame a la trampa, pero tambin tengo
que hacer que algn P6 (entre P4 y P9) la llame.
Empiezo a analizar el cdigo inversamente desde 0xD44714 y despus de
unas cuantas horas de estudio he aprendido mucho, pero no he llegado
a ninguna conclusin clara sobre cual es el comienzo.

Lo siguiente que se me ocurre es que una direccin til podra ser
la primera de la Flash: 0xC00000
Desensamblando:
C00000: mov     r12, #32F8h
C00004: mov     r13, #3D7h
C00008: calls   0C0h, loc_C06866
C0000C: jmps    0C0h, loc_C090D4
C00010: rets
y
C06866: mov     r13, r13
C06868: mov     r12, r12
C0686A: mov     [-r0], r13
C0686C: mov     DPP0, #40h
C06870: mov     [-r0], r12
C06872: mov     r14, mem_100396
C06876: mov     [-r0], r14
................

parece prometedor porque establece todas las variables que usa; no asume que
tengan valores vlidos. Adems pone DPP0=#40h  que es el primer segmento.
No slo eso, sino que ms tarde define los otros segmentos.
Hay otros factores que no me convencen: el primero es que no hace nada con
las interrupciones ni el watchdog. Yo esperara que una rutina de
inicializacin establecera unos criterios rgidos para que nade la interrumpa.
Otro aspecto que me intriga es que use mem_100396 . All no hay nada, pues
ninguna rutina ha puesto ningun dato.
La mejor forma de probarlo es modificando 
C00000: mov     r12, #32F8h
para que llame a  imprime_r3 , ponga r12=#32F8h , y retorne.
Lo hago, y veo que lamentablmente no se llama cuando yo espero.

EL PRIMER DIA CREO EL CIELO Y LA TIERRA
***************************************
Una de las primeras cosas que se hace cuando se inicializa el micro es poner
con valores buenos las variables importantes.
Entre ellas se pueden incluir:
DPP0 = Data Page Pointer, almacenado en FE00 si 16 bits, o en 0x00 si 8 bits.
CSP = Code Segment Pointer, en FE08 o 0x04
CP = Context Pointer CP, almacenado en FE10 si  16 bits, o en 0x08 si 8 bits.
SYSCON = System Control Register, en FF12 o 0x89
SP = Stack Pointer Register, en FE12 o 0x09
STKOV = Stack Overflow Register, en FE14 o 0x0A
STKUN = Stack Underflow Register, en FE16 o 0x0B

Se pone la pila SP con la instruccin
mov SP, xxyy  
que se codifica como
E6 09 yy xx
Normalmente tambin se pondrn  STKOV y STKUN para definir cunto puede
crecer la pila.

Hay 2 asignaciones de la pila en 0xD449A0 y 0xD449AE, y otra en 0xC7FC40
Desensamblando cerca de 0xD449A0:
D4498E: B7 48 B7 B7 : 	srst
D44992: 9A D6 03 F0 : 	jnb	TFR.15, loc_D4499C
D44996: E6 47 00 00 : 	mov	CC7, #0
D4499A: 0D 29       : 	jmpr	cc_UC, loc_D449EE
;------------------------------------------------------------
D4499C: 9A D6 05 E0 : loc_D4499C:
D4499C: 9A D6 05 E0 : 	jnb	TFR.14, loc_D449AA
D449A0: E6 09 00 FC : 	mov	SP, #0FC00h
D449A4: E6 47 01 00 : 	mov	CC7, #1
D449A8: 0D 22       : 	jmpr	cc_UC, loc_D449EE
;------------------------------------------------------------
D449AA: 9A D6 05 D0 : loc_D449AA:
D449AA: 9A D6 05 D0 : 	jnb	TFR.13, loc_D449B8
D449AE: E6 09 00 FC : 	mov	SP, #0FC00h
D449B2: E6 47 02 00 : 	mov	CC7, #2
D449B6: 0D 1B       : 	jmpr	cc_UC, loc_D449EE
..................
D449EE: 76 47 00 02 : loc_D449EE:
D449EE: 76 47 00 02 : 	or	CC7, #200h
D449F2: F2 D6 1C FF : 	mov	TFR, ZEROS
D449F6: FA 00 C0 00 : 	jmps	0, loc_0000C0

Paso a paso:
-srst   hace un reset del micro. Esto limpia algunas variables para
        que el micro pueda trabajar en un entorno seguro.
-mira si el bit 15 de TFR esta puesto. TFR=Trap Flag Register.
        Es decir, si est procesando una trampa provocada
        por una Interruption No Enmascarable (NMI) externa
-si es as, hace CC7=0 y la procesa en loc_D449EE
-mira si est activado el bit 14.
        Es decir, si est procesando un Stack Overflow
-si es as, pone la pila SP=FC00, hace CC7=1 y la procesa en loc_D449EE
-mira si est activado el bit 13.
        Es decir, si est procesando un Stack Underflow
-si es as, pone la pila SP=FC00, hace CC7=2 y la procesa en loc_D449EE
-en loc_D449EE limpia los flags de trampas TFR y salta a 0000C0
        Recordar que en 0000C0 est la tabla de saltos, as que
        es equivalente a     trap #30    pues 0x30*4=0xC0

Lo importante es que la rutina 0xD449A0 parece un lugar bueno para llamar
a la rutina que coloca la trampa.

La otra asignacin de la pila se produce en 0xC7FC40
C7FC1A: A5 5A A5 A5 : 	diswdt
C7FC1E: E6 03 03 00 : 	mov	DPP3, #3
C7FC22: E6 02 42 00 : 	mov	DPP2, #42h
C7FC26: E6 01 41 00 : 	mov	DPP1, #41h
C7FC2A: E6 00 00 00 : 	mov	DPP0, #0
C7FC2E: E6 08 00 FC : 	mov	mem_FE10, #0FC00h
C7FC32: CC 00       : 	nop
C7FC34: E6 89 46 14 : 	mov	SYSCON, #1446h
C7FC38: E6 0B 00 FC : 	mov	STKUN, #0FC00h
C7FC3C: E6 0A 0C FA : 	mov	STKOV, #0FA0Ch
C7FC40: E6 09 00 FC : 	mov	SP, #0FC00h
C7FC44: CC 00       : 	nop
C7FC46: DA 87 C2 FC : 	calls	87h, loc_87FCC2
?Que ms se puede pedir?
-Deshabilita el watchdog para que nadie le interrumpa.
-Pone todos los DPP a valores de segmentos conocidos.
-Establece SYSCON a un valor que permite control total de la memoria.
-Asigna buenos valores para la pila y sus correspondientes lmites.
Sin duda esta es una rutina que se llama bastante pronto.
Cualquier cosa que haga aqui se va a ejecutar muy temprano y con todo
el control a mi merced.

Pero tambin es una gran responsabilidad. Cualquier fallo en esta rutina
y el mvil no sera' capaz de inicializarse. Esto incluye que es posible
que no se pueda re-cargar la Flash para deshacer el error. Yo aviso.

Perfecto; ahora ya puedo sustituir todos los    rets  que quiera porque
s que la trampa est puesta.


DONDE MONTAR TRAMPAS
********************
Buscando en la flash veo que   rets  aparece unas 70.000 veces.
Si sustituyo todos por   trap #35h    corro el riesgo de que el sistema vaya
muy lento debido a todos los datos que tiene que sacar.
Adems, no todas las veces que sale la cadena DB 00  significa que es   rets .
Es posible que haya una instruccin del tipo
mov      r14, #000DBh
que se codifica como
E6 FE DB 00
pero en realidad no es un   rets . Esta situacin no la puedo evitar a
no ser que analice/desensamble el cdigo.
Otro caso es que aparezca en una posicin impar. Ya que el C166 es
de 16 bits ls instrucciones slo pueden aparecer en posiciones pares.


Hago un pequeo programa (llamado  di_calls ) que me extraiga de
la flash la lista de subrutinas que son llamadas, y quien las llama:
#include <stdio.h>
#include <string.h>

main(int argc, char *argv[])
{
FILE *ap, *ap2;
unsigned char c1=0, c0, c2, c3, c;
int i, j;
long posi0=-1, posi10;
long llamados[20000];
int frec[20000], total=0, encontrado;

ap=fopen(argv[1],"rb");
if(ap==NULL)
 {
 printf("No encuentro archivo flash %s \n", argv[1]);
 exit(1);
 }
ap2=fopen(argv[1],"rb");

while(!feof(ap))
 {
 c0=getc(ap); posi0++;
 c1=getc(ap); posi0++;
  if(c0==0xDA || c0==0xFA) /* calls XXXXXX o jumps XXXXXX */
   {
   c2=getc(ap);
   posi0++;
   c3=getc(ap);
   posi0++;
   posi10=c1*65536+c3*256+c2;
   if(c2%2==1) /* debe ser posicion par */
    continue;
   if(c1<0xC0) /* debe llamar a una rutina de la flash */
    continue;
   /* la direccion destino no puede ser 0000 o FFFF */
   fseek(ap2, posi10-0xC00000, SEEK_SET);
   c0=getc(ap2);
   c1=getc(ap2);
   if(c0==0 && c1==0)
    continue;
   if(c0==0xFF && c1==0xFF)
    continue;
   /* miro si ha sido llamada anteriormente */
   encontrado=-1;
   for(i=0;i<total;i++)
    if(llamados[i]==posi10)
	{ /* si: indica que ha sido llamado una vez mas */
	frec[i]++;
	encontrado=i;
	}
   if(encontrado<0)
	{ /* no: indica que ha sido llamado por primera vez */
	llamados[total]=posi10;
	frec[total]=1;
	total++;
	}
   /* imprime llamador y llamado */
   printf("+%0.6X>%0.6X\n", 0xC00000+posi0-3, posi10 );
   }
  }
/* imprime aquellas subrutinas llamadas mas de 300 veces */
encontrado=300;
printf("*** %i - %i\n", encontrado, total );
for(i=0;i<total;i++)
 if(frec[i]>encontrado)
  printf("+%0.6X * %i\n", llamados[i], frec[i] );
return 1;
}

Lo invoco con
di_calls.exe C35_18_From_00.bin >di_calls.txt
que genera un fichero di_calls.txt con 63.000 llamadas, y veo que
hay 10 rutinas que se llaman mas de 300 veces !
Debo evitar poner trampas en esas rutinas, y las subrutinas llamadas por ellas.
Por ejemplo: 0xD31140 es llamado 1304 veces, y se desensambla:
D31140: mov     [-r0], r15
D31142: mov     [-r0], r14
..........................
D3115C: calls   0D3h, loc_D309A2
...........................
D311F2: rets
Para no sobrecargar el  debug  , NO tengo que sustituir
D311F2: rets
por
D311F2: trap #35h

Y en la rutina en loc_D309A2 tampoco debo sustituir su   rets  por   trap #35h.

Igualmente en las rutinas llamadas desde loc_D309A2 tampoco sustituyo.
Lo que me doy cuenta es que estoy otra vez en el problema de la red: unas
rutinas llaman a otras y al final me pierdo.

Lo primero que tengo que hacer es crear un flag para que la trampa
atrape a sus victimas o las libere.
Decido que la rutina   mi_trap  slo llamara a  imprime_r3  cuando
la memoria 0x100800 valga 1.
Tendr que ampliar   mi_trap :
 .............
 push r5 ; mete IP (0x1114+4) de nuevo
 extp #40h, #1h
 mov r3, 0800h ; lee la memoria
 cmp r3, #1 ; mira el flag 
 jmpr cc_NZ, go_fin_trap; no est activado
 mov r3, r4
 calls imprime_r3
 mov r3, r5
 calls imprime_r3
go_fin_trap:
 mov     r3, [r0+]
 .............
 reti ; esto sacara IP, CSP, PSW


As al menos no perder tanto tiempo mandando los datos al puerto.
Para escribir en la memoria 0x100800 lo puedo hacer desde el 'Siemens Debugger'
o habilitar el men Juegos->Buscaminas->Highscore para que lo ponga.

La primera vez lo pruebo con el parche anterior del nmero de
emergencia 112, que s que en algun momento pasa por
021AC6: DB 00       :   rets
el cual sustituyo por
021AC6: 9B 6A       :   trap #35h

Meto el parche, activo el flag en 0x100800 , bloqueo el teclado, y cuando
intento escribir el numero '1' , aparece en el puerto serie el dato 021AC8.
Perfecto. Ahora me lanzo a la aventura y sustituyo 200  rets   al azar.
Parcheo la Flash, activo el flag, y el puerto serie empieza a volcar las
direcciones de memoria por las que voy pasando.
Mando y recibo SMS, hago llamadas, navego por los mens, y obtengo
un montn de direcciones interesantes.
Quizs demasiadas. Algunas rutinas se llaman demasiadas veces, y decido
restaurarlas por el   rets   original.
Como mejora podra crear una lista de rutinas que s deseo imprimir, y
otras que no. La rutina de mi_trap tendr que ver si la rutina interceptada
est'a en una lista u otra, y actuar en consecuencia.

NOTAS FINALES
*************
Esto es slo un acercamiento al Sistema Operativo de los telfonos Siemens
y su microprocesador interno.
En otro artculo seguir investigando y desarrollar ms parches.

*EOF*