// ======================================================================================================== // ======================================================================================================== // ******************************************* device_common.c ******************************************** // ======================================================================================================== // ======================================================================================================== #include "common.h" #include "device_common.h" // ======================================================================================================== // ======================================================================================================== // 10_4_2021: ADDED THIS FROM device_regen_funcs.c because we use it to fetch Calibration data. No sense // in including ALL of device_regen_func.c here. // Load BRAM with data. We ALWAYS read or write 16-bit words from BRAM. If 'byte_or_word_data' is 0, then // we use the ByteData array (8-bits each byte) and load a 16-bit word in the low-order byte to high_order // byte order, i.e., low order byte of 16-bit word goes into byte 0, high order byte of 16-bit word goes // into byte 1, etc. WE MUST INCREMENT val_num (the index into ByteData) BY 2, NOT 1. When 'byte_or_word_data' // is 1, we transfer 16-bits to 16-bits. NOTE: I switched the meaning of 'byte_or_word' from the old code // here. void LoadUnloadBRAM(int max_string_len, int num_vals, volatile unsigned int *CtrlRegA, volatile unsigned int *DataRegA, unsigned int ctrl_mask, unsigned char *ByteData, signed short *WordData, int load_or_unload, int byte_or_word_data, int debug_flag) { int val_num, locked_up, increment; // BYTE-TO-WORD // Sanity check. When byte_or_word_data is 0, then we are transferring in byte data two bytes at-a-time, i.e., we transfer 16-bits at a time // into the PL side so ensure num_vals is an even number. if ( byte_or_word_data == 0 && (num_vals % 2) != 0 ) { printf("ERROR: LoadUnloadBRAM(): 'num_vals' MUST BE an even number for ByteData transfers to BRAM!\n"); exit(EXIT_FAILURE); } // **************************************** // ***** Load BRAM with data if ( debug_flag == 1 ) { if ( load_or_unload == 0 ) printf("LB.1) Loading BRAM: Number of values to load %d\n", num_vals); else printf("LB.1) UnLoading BRAM: Number of values to unload %d\n", num_vals); } if ( byte_or_word_data == 0 ) increment = 2; else increment = 1; for ( val_num = 0; val_num < num_vals; val_num += increment ) { #ifdef DEBUG printf("%4d) Load/unload %d\t\n", val_num, load_or_unload); fflush(stdout); #endif // Wait for 'stopped' from hardware to be asserted, which indicates that the hardware is ready to receive a byte. locked_up = 0; while ( ((*DataRegA) & (1 << IN_SM_HANDSHAKE)) == 0 ) { locked_up++; if ( locked_up > 10000000 ) { printf("ERROR: LoadUnloadBRAM(): 'stopped' has not been asserted for the threshold number of cycles -- Locked UP?\n"); fflush(stdout); locked_up = 0; } } // Put the data bytes into the register and assert 'continue' (OUT_CP_HANDSHAKE). iEnrollSpreadFactors are loaded one in each 16-bit word of PNL BRAM, so // byte_or_word_data is set to 1 for SpreadFactor loads/unloads if ( load_or_unload == 0 ) { if ( byte_or_word_data == 0 ) *CtrlRegA = ctrl_mask | (1 << OUT_CP_HANDSHAKE) | (0x000000FF & ByteData[val_num]) | (0x0000FF00 & (ByteData[val_num+1] << 8)); else *CtrlRegA = ctrl_mask | (1 << OUT_CP_HANDSHAKE) | (0x0000FFFF & WordData[val_num]); } // When 'stopped' is asserted, the data is ready on the output register from the PNL BRAM -- get it. else { if ( byte_or_word_data == 0 ) { ByteData[val_num] = (0x000000FF & *DataRegA); ByteData[val_num+1] = ((0x0000FF00 & *DataRegA) >> 8); } else WordData[val_num] = (0x0000FFFF & *DataRegA); *CtrlRegA = ctrl_mask | (1 << OUT_CP_HANDSHAKE); } // Wait for hardware to de-assert 'stopped' (it got the byte). while ( ((*DataRegA) & (1 << IN_SM_HANDSHAKE)) != 0 ); // De-assert 'continue'. ALSO, assert 'done' (OUT_CP_LM_ULM_DONE) SIMULTANEOUSLY to tell hardware this is the last word. if ( val_num == num_vals - increment ) *CtrlRegA = ctrl_mask | (1 << OUT_CP_LM_ULM_DONE); else *CtrlRegA = ctrl_mask; } // Handle case where 'num_vals' is 0. if ( num_vals == 0 ) *CtrlRegA = ctrl_mask | (1 << OUT_CP_LM_ULM_DONE); // De-assert 'OUT_CP_LM_ULM_DONE' *CtrlRegA = ctrl_mask; fflush(stdout); return; } // ======================================================================================================== // ======================================================================================================== // Get the challenges and masks to be applied to the functional unit. Verifier will send number of rising // challenges (inspects challenges as it reads them) and indicate whether masks will also be sent. int ReceiveChlngsAndMasks(int max_string_len, int verifier_socket_desc, unsigned char ***challenges_b_ptr, int num_chlng_bits, int *num_rise_chlngs_ptr, int *has_masks_ptr, int num_POs, unsigned char ***masks_b_ptr) { int num_chlngs, chlng_mask_num, chlng_num; char num_chlngs_str[max_string_len]; unsigned char *chlng_ptr; // Get the number of challenges that verifier intends to send. if ( SockGetB((unsigned char *)num_chlngs_str, max_string_len, verifier_socket_desc) < 0 ) { printf("ERROR: ReceiveChlngsAndMasks(): Failed to receive 'num_chlngs_str'!\n"); fflush(stdout); exit(EXIT_FAILURE); } // DEBUG #ifdef DEBUG printf("ReceiveChlngsAndMasks(): 'num_chlngs_str' received from verifier '%s'\n", num_chlngs_str); fflush(stdout); #endif if ( sscanf(num_chlngs_str, "%d %d %d", &num_chlngs, num_rise_chlngs_ptr, has_masks_ptr) != 3 ) { printf("ERROR: ReceiveChlngsAndMasks(): Expected 'num_chlngs', 'num_rise_chlngs' and 'has_masks' in '%s'\n", num_chlngs_str); fflush(stdout); exit(EXIT_FAILURE); } // Allocate the base arrays based on the number of challenges we will receive. if ( (*challenges_b_ptr = (unsigned char **)malloc(sizeof(unsigned char *) * num_chlngs)) == NULL ) { printf("ERROR: ReceiveChlngsAndMasks(): Failed to allocate storage for challenges_b array!\n"); fflush(stdout); exit(EXIT_FAILURE); } if ( *has_masks_ptr == 1 ) if ( (*masks_b_ptr = (unsigned char **)malloc(sizeof(unsigned char *) * num_chlngs)) == NULL ) { printf("ERROR: ReceiveChlngsAndMasks(): Failed to allocate storage for masks_b array!\n"); fflush(stdout); exit(EXIT_FAILURE); } // Receive the challenges and masks sent by the verifier. chlng_num = 0; chlng_mask_num = 0; while ( chlng_num != num_chlngs ) { // Allocate space to store the binary challenges if ( chlng_mask_num == 0 ) { if ( ((*challenges_b_ptr)[chlng_num] = (unsigned char *)malloc(sizeof(char)*num_chlng_bits/8)) == NULL ) { printf("ERROR: ReceiveChlngsAndMasks(): Failed to allocate storage for challenges_b element!\n"); fflush(stdout); exit(EXIT_FAILURE); } chlng_ptr = (*challenges_b_ptr)[chlng_num]; } else if ( ((*masks_b_ptr)[chlng_num] = (unsigned char *)malloc(sizeof(char)*num_POs/8)) == NULL ) { printf("ERROR: ReceiveChlngsAndMasks(): Failed to allocate storage for masks_b element!\n"); fflush(stdout); exit(EXIT_FAILURE); } // Get the binary challenge data if ( chlng_mask_num == 0 ) { if ( SockGetB(chlng_ptr, num_chlng_bits/8, verifier_socket_desc) != num_chlng_bits/8 ) { printf("ERROR: ReceiveChlngsAndMasks(): number of challenge bytes received is not equal to %d\n", num_chlng_bits/8); fflush(stdout); exit(EXIT_FAILURE); } } else if ( SockGetB((*masks_b_ptr)[chlng_num], num_POs/8, verifier_socket_desc) != num_POs/8 ) { printf("ERROR: ReceiveChlngsAndMasks(): number of mask bytes received is not equal to %d\n", num_POs/8); fflush(stdout); exit(EXIT_FAILURE); } // DEBUG // printf("Vector %d\n\t", chlng_num); // int i; // for ( i = 0; i < num_chlng_bits/8; i++ ) // printf("%02X ", chlng_ptr[i]); // printf("\n"); // Increment to next challenge, and potentially the mask, have been received. if ( (*has_masks_ptr == 0 && chlng_mask_num == 0) || (*has_masks_ptr == 1 && chlng_mask_num == 1) ) { chlng_num++; chlng_mask_num = 0; } else chlng_mask_num++; } // DEBUG // printf("ReceiveChlngsAndMasks(): %d challenges received from verifier!\n", chlng_num); fflush(stdout); return num_chlngs; } // ======================================================================================================== // ======================================================================================================== // Transfer a challenge plus optionally a mask through the GPIO to the VHDL side. void LoadChlngAndMask(int max_string_len, volatile unsigned int *CtrlRegA, volatile unsigned int *DataRegA, int chlng_num, unsigned char **challenges_b, int ctrl_mask, int num_chlng_bits, int chlng_chunk_size, int has_masks, int num_POs, unsigned char **masks_b) { int word_num, iter_num, load_iterations, bit_len; unsigned char *chlng_ptr; int chlng_val_chunk; // Sanity check if ( (num_chlng_bits % chlng_chunk_size) != 0 ) { printf("ERROR: LoadChlngAndMask(): Challenge size %d must be evenly divisible by %d!\n", num_chlng_bits, chlng_chunk_size); exit(EXIT_FAILURE); } // Reset the VHDL pointers to the challenge buffers. *CtrlRegA = ctrl_mask | (1 << OUT_CP_DTO_RESTART); usleep(1000); *CtrlRegA = ctrl_mask; #ifdef DEBUG printf("LoadChlngAndMask(): Reset VHDL challenge pointers!\n"); fflush(stdout); #endif if ( has_masks == 0 ) load_iterations = 1; else load_iterations = 2; // Send a binary challenge, 16-bits at a time, starting with the low order to high order bits. for ( iter_num = 0; iter_num < load_iterations; iter_num++ ) { // Set size of data transfer. if ( iter_num == 0 ) bit_len = num_chlng_bits; else bit_len = num_POs; #ifdef DEBUG printf("LoadChlngAndMask(): Current control mask '%08X'\n", ctrl_mask); fflush(stdout); #endif // Iterate over each of the 16-bit chunks. Verifier has ordered the data from low order to high order, i.e., the exact format that we need to load it up by // in the VHDL. for ( word_num = 0; word_num < bit_len/chlng_chunk_size; word_num++ ) { // Add 2 bytes at a time to the pointer. if ( iter_num == 0 ) chlng_ptr = challenges_b[chlng_num] + word_num*2; else chlng_ptr = masks_b[chlng_num] + word_num*2; chlng_val_chunk = (chlng_ptr[1] << 8) + chlng_ptr[0]; #ifdef DEBUG printf("LoadChlngAndMask(): 16-bit chunk %d in hex '%04X'\n", word_num, chlng_val_chunk); fflush(stdout); #endif // Four step protocol // 1) Assert 'data_ready' while putting the 16-bit binary value on the low order bits of CtrlReg //printf("LoadChlngAndMask(): Writing 'data_ready' with 16-bit binary value in hex '%04X'\n", chlng_val_chunk); fflush(stdout); *CtrlRegA = ctrl_mask | (1 << OUT_CP_DTO_DATA_READY) | chlng_val_chunk; // 2) Wait for 'done_reading to go to 1 (it is low by default). State machine latches data in 2 clk cycles. // Maintain 1 on 'data_ready' and continue to hold 16-bit binary chunk. // printf("LoadChlngAndMask(): Waiting state machine 'done_reading' to be set to '1'\n"); fflush(stdout); while ( (*DataRegA & (1 << IN_SM_DTO_DONE_READING)) == 0 ); // 3) Once 'done_reading' goes to 1, set 'data_ready' to 0 and remove chunk; // printf("LoadChlngAndMask(): De-asserting 'data_ready'\n"); fflush(stdout); *CtrlRegA = ctrl_mask; // 4) Wait for 'done_reading to go to 0. // printf("LoadChlngAndMask(): Waiting state machine 'done_reading' to be set to '0'\n"); fflush(stdout); while ( (*DataRegA & (1 << IN_SM_DTO_DONE_READING)) != 0 ); // printf("LoadChlngAndMask(): Done handshake associated with challenge chunk transfer\n"); fflush(stdout); } } // 6/1/2016: Tell CollectPNs (if it is waiting) that challenge and possibly a mask have been loaded. *CtrlRegA = ctrl_mask | (1 << OUT_CP_DTO_VEC_LOADED); *CtrlRegA = ctrl_mask; return; } // ======================================================================================================== // ======================================================================================================== // DEBUG ROUTINE. Check that the challenge received are precisely the same as the ones stored in the file on // the server. Write an ASCII file. void SaveASCIIChlngs(int max_string_len, int num_chlngs, unsigned char **challenges_b, int num_chlng_bits, int has_masks, int num_POs, unsigned char **masks_b) { int byte_cnter, bit_cnter; unsigned char *chlng_ptr; int chlng_num; FILE *OUTFILE; if ( (OUTFILE = fopen("ReceivedVectors.txt", "w")) == NULL ) { printf("ERROR: SaveASCIIChlngs(): Could not open ReceivedVectors.txt for writing!\n"); fflush(stdout); exit(EXIT_FAILURE); } for ( chlng_num = 0; chlng_num < num_chlngs; chlng_num++ ) { chlng_ptr = challenges_b[chlng_num]; // Print ASCII version of bitstring in high order to low order. for ( byte_cnter = num_chlng_bits/8 - 1; byte_cnter >= 0; byte_cnter-- ) { for ( bit_cnter = 7; bit_cnter >= 0; bit_cnter-- ) { // Check binary bit for 0 or 1 if ( (chlng_ptr[byte_cnter] & (unsigned char)(1 << bit_cnter)) == 0 ) fprintf(OUTFILE, "0"); else fprintf(OUTFILE, "1"); } fprintf(OUTFILE, "\n"); } } fclose(OUTFILE); // Do the same for the received masks. if ( has_masks == 1 ) { if ( (OUTFILE = fopen("ReceivedMasks.txt", "w")) == NULL ) { printf("ERROR: SaveASCIIChlngs(): Could not open ReceivedMasks.txt for writing!\n"); fflush(stdout); exit(EXIT_FAILURE); } for ( chlng_num = 0; chlng_num < num_chlngs; chlng_num++ ) { // Print ASCII version of bitstring in high order to low order. for ( byte_cnter = num_POs/8 - 1; byte_cnter >= 0; byte_cnter-- ) { for ( bit_cnter = 7; bit_cnter >= 0; bit_cnter-- ) { // Check binary bit for 0 or 1 if ( (masks_b[chlng_num][byte_cnter] & (unsigned char)(1 << bit_cnter)) == 0 ) fprintf(OUTFILE, "0"); else fprintf(OUTFILE, "1"); } } fprintf(OUTFILE, "\n"); } fclose(OUTFILE); } return; } // ======================================================================================================== // ======================================================================================================== // Send 'GO' and get challenges and masks int GoGetChlngs(int max_string_len, int num_POs, int num_chlng_bits, int verifier_socket_desc, int *num_rise_chlngs_ptr, int *has_masks_ptr, unsigned char ***challenges_b_ptr, unsigned char ***masks_b_ptr, int send_GO, int debug_flag) { int num_chlngs; struct timeval t0, t1; long elapsed; // **************************************** // ***** Send "GO" to the verifier if ( send_GO == 1 ) { if ( debug_flag == 1 ) { printf("GGV.1) Sending 'GO' to verifier\n"); gettimeofday(&t0, 0); } if ( SockSendB((unsigned char *)"GO", 2, verifier_socket_desc) < 0 ) { printf("ERROR: GoGetChlngs(): Send 'GO' request failed\n"); fflush(stdout); exit(EXIT_FAILURE); } if ( debug_flag == 1 ) { gettimeofday(&t1, 0); elapsed = (t1.tv_sec-t0.tv_sec)*1000000 + t1.tv_usec-t0.tv_usec; printf("\tElapsed %ld us\n\n", (long)elapsed); } } // **************************************** // ***** Get the challenges and select masks from verifier. if ( debug_flag == 1 ) { printf("GGV.2) Receiving challenges and masks from verifier\n"); gettimeofday(&t0, 0); } // Read all the challenges from the verifier into a set of string arrays. Verifier will send number of rising challenges (inspects challenges // as it reads them) and indicate whether masks will also be sent. num_chlngs = ReceiveChlngsAndMasks(max_string_len, verifier_socket_desc, challenges_b_ptr, num_chlng_bits, num_rise_chlngs_ptr, has_masks_ptr, num_POs, masks_b_ptr); if ( debug_flag == 1 ) { gettimeofday(&t1, 0); elapsed = (t1.tv_sec-t0.tv_sec)*1000000 + t1.tv_usec-t0.tv_usec; printf("\tElapsed %ld us\n\n", (long)elapsed); } printf("\tNumber of challenges received %d\tNumber of rising challenges %d\tHas masks ? %d\n\n", num_chlngs, *num_rise_chlngs_ptr, *has_masks_ptr); fflush(stdout); // DEBUG // SaveASCIIVectors(max_string_len, num_chlngs, *challenges_b_ptr, num_chlng_bits, *has_masks_ptr, num_POs, *masks_b_ptr); return num_chlngs; }