2021/12/21

Forzador MD5 en PYNQ, el software


Siguiendo los pasos detallados anteriormente, no bien creás el IP, te aparecen los drivers en:

./ip_repo/MD5_Brute_Forcer_1.0/drivers/MD5_Brute_Forcer_v1_0/src/MD5_Brute_Forcer.h

 

Los valores de desplazamiento de cada registro son:

#define MD5_BRUTE_FORCER_S_AXI_SLV_REG0_OFFSET 0
#define MD5_BRUTE_FORCER_S_AXI_SLV_REG1_OFFSET 4
#define MD5_BRUTE_FORCER_S_AXI_SLV_REG2_OFFSET 8
#define MD5_BRUTE_FORCER_S_AXI_SLV_REG3_OFFSET 12
#define MD5_BRUTE_FORCER_S_AXI_SLV_REG4_OFFSET 16
#define MD5_BRUTE_FORCER_S_AXI_SLV_REG5_OFFSET 20
#define MD5_BRUTE_FORCER_S_AXI_SLV_REG6_OFFSET 24

 y algunas funciones

#define MD5_BRUTE_FORCER_mWriteReg( \
  BaseAddress, RegOffset, Data) \
    Xil_Out32((BaseAddress) + \
  (RegOffset), (u32)(Data))

#define MD5_BRUTE_FORCER_mReadReg(BaseAddress, RegOffset) \
    Xil_In32((BaseAddress) + (RegOffset))



XStatus MD5_BRUTE_FORCER_Reg_SelfTest(void * baseaddr_p);

 

Tras generar el bitstream, exportar el hardware, abrís la SDK

 

Comprobás que exista lo tuyo, en mi caso MD5_Brute_Forcer:

 

En system.hdf vemos MD5_Brute_Forcer
En system.hdf vemos MD5_Brute_Forcer


Creás entonces una nueva "Application Project" con template de "empty application", que te va a crear una carpeta con el nombre que le pongas con sufijo _bsp. En mi caso, en:

./md5_brute_forcer/md5_brute_forcer.sdk/brute_forcer_bsp/ps7_cortexa9_0/include/

en xparameters.h  te define:


/* Definitions for peripheral MD5_BRUTE_FORCER_0 */
#define XPAR_MD5_BRUTE_FORCER_0_DEVICE_ID 0
#define XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR 0x43C00000
#define XPAR_MD5_BRUTE_FORCER_0_S_AXI_HIGHADDR 0x43C0FFFF

tambien verás que MD5_Brute_Forcer.h ahora está en 

brute_forcer_bsp/ps7_cortexa9_0/include/MD5_Brute_Forcer.h

Creás un main.c

Un problema que no puede resolver es que los archivos xgpio.h  xgpio_l.h que proveen la resolución del nombre de las funciones más básicas de lectura y escritura en la memoria, no están siendo generados o incluidos. Lo que he hecho es tomarlos de uno de los ejercicios y copiarlos en 

brute_forcer_bsp/ps7_cortexa9_0/include/


Llegado este punto, hay que grabar el bitstream, "Xilinx" -> "Program FPGA" por un lado y ejecutar el programa por el otro con botón derecho sobre la aplicación, "Run as" -> "launch on hardware (GDB)" y usando por ejemplo 

miniterm.py  /dev/ttyUSB1  115200 


y a disfrutar de los resultados.

 

Un pipeline
Un pipeline


Dos pipelines
Dos pipelines

Cuatro pipelines
Cuatro pipelines


Como notarás:

En waited dice cuando charlyseconds demoró, va decreciendo.

En found plin plin plin at pipeline tal de tantas ves como evoluciona de 1 a 4 pipelines. El pipeline que lo halló es 1,2,4,8, si mirás el registro, entenderás.

Con los valores 200 a 203, como al valor hay que sumarle el pipeline donde fué hallado.

Y lo más notorio, hay un desplazamiento entre el valor esperado y el obtenido, es algo que siempre ha ocurrido, en las simulaciones tambien, me falta diagnosticar, por ahora se va a tener que ajustar desde el software, al igual que los primeros y últimos valores que no los puede hallar, motivo de otra entrada futura.

Y más notorio aún, para cuatro pipelines falla para un número relativamente bajo, tengo que revisar bien, pero me puede llevar mucho tiempo y como no hace a la implementación de software, por hoy no me preocupo.


Estos resultados no salen de un repollo, veamos el programa main.c, antes recordemos, recordemos, no, no recordemos, es de una entrada futura pero que estoy haciendo a la vez, en la del futuro digo que "de paso agrego más valores a los registros", pero bueno, aceptemos este efecto sobrenatural.


Registros
Registros


Lo primero es adaptar las primitiva provistas por el driver de bajo nivel a algo más usable.

Para habilitar y deshabilitar hay que escribir 1 y 0 en el registro 4, eso se obtiene de esta base y desplazamiento:


XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR

MD5_BRUTE_FORCER_S_AXI_SLV_REG4_OFFSET

Las funciones son:

void enable() {
     MD5_BRUTE_FORCER_mWriteReg(
         XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR,
         MD5_BRUTE_FORCER_S_AXI_SLV_REG4_OFFSET, 1
         );
}

void disable() {
    MD5_BRUTE_FORCER_mWriteReg(
      XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR,
      MD5_BRUTE_FORCER_S_AXI_SLV_REG4_OFFSET, 0
    );
}


Para escribir el hash hay que escribir 4 registros de 32 bits en los registro 0 a 3:

void setHash(unsigned int r3,
             unsigned int r2,
             unsigned int r1,
             unsigned int r0) {
    MD5_BRUTE_FORCER_mWriteReg(
       XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR,
       MD5_BRUTE_FORCER_S_AXI_SLV_REG3_OFFSET, r3
    );
    MD5_BRUTE_FORCER_mWriteReg(
       XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR,
       MD5_BRUTE_FORCER_S_AXI_SLV_REG2_OFFSET, r2
    );
    MD5_BRUTE_FORCER_mWriteReg(
       XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR,
       MD5_BRUTE_FORCER_S_AXI_SLV_REG1_OFFSET, r1
    );
    MD5_BRUTE_FORCER_mWriteReg(
       XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR,
       MD5_BRUTE_FORCER_S_AXI_SLV_REG0_OFFSET, r0);
}



Para leer el resultado, está en el registro 5:


unsigned int readTarget() {
        return MD5_BRUTE_FORCER_mReadReg(
         XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR,
         MD5_BRUTE_FORCER_S_AXI_SLV_REG5_OFFSET );
}


Para leer cuantos pipelines hay y cuál tuvo el hit, hay que leer el registro 6 y extraer los bits necesarios:


unsigned int readStatus() {
     return MD5_BRUTE_FORCER_mReadReg(
          XPAR_MD5_BRUTE_FORCER_0_S_AXI_BASEADDR,
          MD5_BRUTE_FORCER_S_AXI_SLV_REG6_OFFSET
     );
}


Lo mismo para la cantidad de pipelines y cuá halló el resultado:

unsigned int readPipelineCount() {
    unsigned int status = readStatus();
    return ( status & 0x0000f000 ) >>12;
}

unsigned int readPipelineHit() {
    unsigned int status = readStatus();
    return status >> 16;
}


Para mostrar los bits de estado:

void printStatus(const char * tab) {
    unsigned int status = readStatus();
    printf("%s",tab);
    if (status & 0x1)  printf("paused ");
    if (status & 0x2)  printf("running ");
    if (status & 0x4)  printf("warming ");
    if (status & 0x8)  printf("found ");
    if (status & 0x10) printf("done ");
    if (status & 0x20) printf("enabled ");
    if (status == 0) printf("errorNoStatus ");

    printf("\r\n");
}


Y eso es todo, otra vez anticipando el futuro, cuando pueda prescindir de los printf probablemente pueda usar un microblaze en la Nexys4DDR, quizás a la vez hacer un IP sin AXI pues no creo que entren los ocho pipelines y el microblaze a la vez.






No hay comentarios:

Publicar un comentario