En pocas palabras para no repetir lo dicho antes:
Necesito hacer un acelerador criptográfico en la PL (Programmable Logic) de un Zynq-7020 (PYNQ en particular) accesible desde un programa que se ejecute en el PS (Processing System) o como todos le conocemos, CPU.
Ya había logrado usar IP (la forma en que llaman a los componentes en este mundo), en particular dos UARTs. Ahora quiero hacer mi propia IP y que haga un cirfrado sencillo.
No voy a apoyarme en una experiencia anterior con Parallella sino en los ejercicios del libro comentado que he estudiado.
Estos proyectos están a la par de los dos proyectos "serial" y "dual-serial" y también lo construiré de cero sin ninguna dependencia cruzada para evitar complicaciones, apuntando a las siguientes hitos:
- Acelerador echo: que me devuelva lo que escribo.
- Acelerador xor: que calcule el xor de dos argumentos en un tercero.
Acelerador con eco
Manos a la obra, esta parte es común a todos los proyectos anteriores:
- Create Project
- RTL Project
- Target Language Verilog
- Skip add files
- Skip add constraints
- Default Part
- Boards
- Seleccionar pynq-z2
- Agregar el xdc, que es el mapeo de los pines a la FPGA
Acá empieza la diferencia, crear el IP
- Tools -> Create and Package New IP
- Create a new AXI4 peripheral
- Name, version, etc...
- Next Steps -> Edit IP
- Finish
Ahora se pone delicado, hay que buscar el archivo que te creó y al final hay un comentario que dice "Add user logic here", nada por ahora.
Edición del acelerador |
Más arriba, buscando "slv_reg0" encontras los nombres de los registros para comunicarte con la CPU. Son todos de 32 bits.
Voy a usar
- slv_reg0 como clave
- slv_reg1 como input
- slv_reg2 como output
- slv_reg3 como contador, ya que está...
Lo primero que tengo que hacer es que me funcione como memoria, o sea, escribo algo y luego lo vuelvo a leer. Si está ok, estamos encaminados, sigamos entonces.
Hay que ir al tab:
- Package IP - accelerator
- Re-Package IP
Listo, cerró, volvemos al proyecto original.
- Create Block Design
- Add IP
- Zynq
- run block automation
- Add IP
- Buscar el nombre, en este caso accelerator
- run connection automation
- Save Block Design
- Tools -> Validate
- Sources -> Design Sources -> tu proyecto -> botón derecho -> Create HDL Wrapper
- Generate bitstream
- File -> Export Hardware
- include bitstream
- File -> Launch SDK
Lo que queda es puro software
- File -> New -> Application Project
- Templates -> Empty
Para encontrar la dirección del acelerador, hay que mirar system.hdf:
Dirección del acelerador |
Con este sencillo programa pruebo que funciona, lo que escribo lo puedo volver a leer:
#include <stdio.h>
#include "xil_printf.h"
#include "xil_io.h"
#define BaseAddress 0x43c00000
#define REG_KEY 0
#define REG_CLEARTEXT 4
#define REG_CIPHERTEXT 8
int main() {
u32 key;
u32 clearText;
u32 cipherText;
xil_printf("Accelerator\n\r");
for (u32 i=0; i< 255; ++i) {
key = Xil_In32(BaseAddress + REG_KEY);
clearText = Xil_In32(BaseAddress + REG_CLEARTEXT);
cipherText = Xil_In32(BaseAddress + REG_CIPHERTEXT);
xil_printf("i : %d\n", i );
xil_printf("key : %d\n", key );
xil_printf("clear text : %d\n", clearText );
xil_printf("cipher text: %d\n", cipherText );
Xil_Out32(BaseAddress + REG_KEY, i);
Xil_Out32(BaseAddress + REG_CLEARTEXT, i);
Xil_Out32(BaseAddress + REG_CIPHERTEXT, i);
sleep(5);
}
return 0;
}
La ejecución en la terminal:
echo Ok |
Acelerador XOR
Recorrí un tortuoso camino, con muchas pruebas fallidas. Cuando finalmente me rendí y busqué en internet, lo primero que hallé fueron estos minutos de 4 a 8, que tampoco funcionó, hasta que me dí cuenta de mi error:
#define BaseAddress 0x43c0000
¿Lo viste? Me quería matar, bueno, no importa, pensé bastante, el acelerador funciona y recorrí el camino de editar IP y reintegrarlo hasta el aburrimiento. Prometo que voy a hacer un machete de cómo hacer esto, pero despues, en diciembre que ahora estoy hasta las manos.
Nota del futuro: el paso anterior de echo también tenía ese problema, pero no se manifestó pues la dirección errónea no coincidió con nada que se pudiera romper. Lo corregí y dió ok.
El código Verilog, en verde mis agregados y modificaciones:
Código Verilog xor |
Los dos bloques calculan tanto el xor como el incremento del contador, cuyos registros están conectados a los Out que permanentemente están conectados a los registros 2 y 3. No me gusta mucho pues claramente el contador está contando el clock, no la cantidad de pedidos de cifrado y el exor se hace en cada ciclo de clock, es demasiado veloz, qué pasa si quiero hacer un cifrado de verdad que no llegue a hacerse en tal breve intervalo o si quiero hacer el ataque pensado? Bueno, eso esa el próxima entrega o la siguiente...
El programa tal como está ahora:
#include "xil_printf.h"
#include "xil_io.h"
#define BaseAddress 0x43c00000
#define REG_KEY 0
#define REG_CLEARTEXT 4
#define REG_CIPHERTEXT 8
#define REG_COUNT 12
int main() {
u32 key;
u32 clearText;
u32 cipherText;
u32 count;
xil_printf("Accelerator\n\r");
Xil_Out32(BaseAddress + REG_KEY, 3);
for (u32 i=0; i< 255; ++i) {
Xil_Out32(BaseAddress + REG_CLEARTEXT, i);
key = Xil_In32(BaseAddress + REG_KEY);
clearText = Xil_In32(BaseAddress + REG_CLEARTEXT);
cipherText = Xil_In32(BaseAddress + REG_CIPHERTEXT);
count = Xil_In32(BaseAddress + REG_COUNT);
xil_printf("i : 0x%08x\n", i );
xil_printf("key : 0x%08x\n", key );
xil_printf("clear text : 0x%08x\n", clearText );
xil_printf("cipher text: 0x%08x\n", cipherText );
xil_printf("count : 0x%08x\n", count );
sleep(5);
}
return 0;
}
Y la salida, comparando con lo esperado en la calculadora:
Ejecución Ok |
No hay comentarios:
Publicar un comentario