/****************************************************************************** *File name : MM_lib.c *Version.Revision: 1.4 *Purpose: * This module contains all the procedures relative to the memory management * services: load, dump and check *Public Functions: * int delet_memory_segment(int) * int create_memory_header (unsigned int *, memory_header *, unsigned int) * unsigned int memory_load(TC_packet *, memory_header *, int *) * unsigned int memory_dump(memory_header *, unsigned int *, unsigned int *) * unsigned int memory_check(memory_header *) * unsigned int copy_OBSW_image (unsigned int, unsigned int, unsigned int) *Private Functions: * none *Description: * see the respective functions *Creation Date & Author: 05-09-2005, SP *Version, Update date & Author: 1.1, 27-10-2005, DS * moved here function to execute patching * 1.2, 25-11-2005, SP * comments by Ed Bach * 1.3, 09-11-2006, SP * new adicpy (form old HIFI mmmcpy) * 1.4, 15-12-2006, SP * removed adicpy ******************************************************************************/ #include #include"MM_crc.h" #include"MM_21020.h" #include"MM_lib.h" /*======================= LOCAL DEFINES ========================*/ enum { MEMORY_PROM_ID, MEMORY_RAM_ID, MEMORY_1355_REG_ID, MEMORY_EEPROM_ID, MEMORY_SMCS_DRAM_ID, MEMORY_1553_ID, MEMORY_DM_IN_PM_ID, NUMBER_OF_MEM_SEGMENT }; typedef struct { unsigned int ID; unsigned int offset; unsigned int size; int is_writeable; /* 1 RW, 0 Read only */ } memory_segment_def; /*======================= EXTERN FUNCT ========================*/ extern unsigned int IFSI_DIV(unsigned int, unsigned int); extern unsigned int IFSI_MOD(unsigned int, unsigned int); /*========================= GLOBAL VAR =========================*/ //used by function copy_OBSW_image and by assembly func copyPathed_AndReset unsigned int adicpy_len = 50; //used to infrom adicpy_PM that DPU should be reset unsigned int Make_reset = 0; /*========================= STATIC VAR =========================*/ static memory_segment_def MEmory_map[NUMBER_OF_MEM_SEGMENT] = { {MEMORY_PROM_ID, 0x100, 0x1555, 0}, /* MEMORY_PROM */ {MEMORY_RAM_ID, DATA_MEMORY_BASE_ADDRESS, 0x80000, 1}, /* MEMORY_RAM */ {MEMORY_1355_REG_ID, SMCS_REGISTERS_BASE_ADDRESS, 0x70, 1}, /* 1355 REGISTERS */ {MEMORY_EEPROM_ID, EEPROM_MEMORY_BASE_ADDRESS, 0x40000, 0}, /* EEPROM */ {MEMORY_SMCS_DRAM_ID, IF_1355_BASE_ADDRESS, 0x2000, 1}, /* 1355 DRAM */ {MEMORY_1553_ID, BUS_IF_MIL_AND_ANALOG_INP, 0x4000, 1}, /* 1553 AREA */ {MEMORY_DM_IN_PM_ID, START_DM_IN_PM, 0x3A0, 0} /* DATA MEMORY in PM */ }; static int NUmber_of_mem_segment = NUMBER_OF_MEM_SEGMENT; /****************************************************************************** *Function name : delete_memory_segments *Purpose: * This function deletes all inital memory segments defined by PACS *Syntax: * delet_memory_segments(void); *Input: * none *Output: * none *Return: * none ******************************************************************************/ void delete_memory_segments(void) { NUmber_of_mem_segment = 0; } /****************************************************************************** *Function name : add_memory_segment *Purpose: * This function adds a memory segment *Syntax: * int result = add_memory_segment(unsigned int par_ID, unsigned int par_offset, unsigned int par_size, int par_is_writeable); *Input: * par_ID : ID * par_offset : offset * par_size : dimension of segment * par_is_writeable : 1 if writeable, 0 otherwise *Output: * none *Return: * result : 1 OK, 0 array full ******************************************************************************/ int add_memory_segment(unsigned int par_ID, unsigned int par_offset, unsigned int par_size, int par_is_writeable) { if (NUmber_of_mem_segment == NUMBER_OF_MEM_SEGMENT)// is NUmber_of_mem_segment = NUMBER_OF_MEM_SEGMENT? return 0; // return immediately MEmory_map[NUmber_of_mem_segment].ID = par_ID; MEmory_map[NUmber_of_mem_segment].offset = par_offset; MEmory_map[NUmber_of_mem_segment].size = par_size; MEmory_map[NUmber_of_mem_segment].is_writeable = par_is_writeable; NUmber_of_mem_segment++; return 1; } /****************************************************************************** *Function name : create_memory_header *Purpose: * This function extracts from the telecommand the memory header according to * this description: * 1st word --> 3 bit for subsystem (0 is DPU); 1 bit for PM or DM; 4 bit for * memory ID; 8 bit for memory address (MS) * 2nd word --> 16 bit (LS) for memory address. With previous 8 bit memory * address is a 24 bit word * 3rd word --> length in SAU: 6 byte for PM and 4 byte for DM *Syntax: * int value = create_memory_header(unsigned int * data, memory_header * p_header, unsigned int length_to_check) *Input: * p_tc pointer to the data field in the TC * length_to_check (p_tc->packet_length - 13) for memory load, 0 otherwise *Output: * p_header pointer to the structure (allocated by the calling function) * that contains the memory info (see L4_MMLIB.h for details) *Return: * value 0: OK * INVALID_MEMID: mem ID is greater than largest defined value * INVALID_MEMLENGTH: number of SAU is zero * INVALID_MEMLENGTH (only for mem load): 3rd word incompatible with * packet length * INVALID_ADDRESS: start address (24 bit) or (start address + length) * is greater than the size of memory segment ******************************************************************************/ int create_memory_header (unsigned int * data, memory_header * p_header, unsigned int length_to_check) { unsigned int first_part, second_part, end_address; second_part = (data[0] & 0xFF) << 16; first_part = (data[0] >> 8) & 0xFF; p_header->subsystem = (first_part >> 5) & 7; p_header->memory_ID = first_part & 0xF; if (p_header->memory_ID >= NUmber_of_mem_segment) // is ID greater than largest defined iD? return INVALID_MEMID; // return INVALID_MEMID p_header->length_SAU = data[2]; if (p_header->length_SAU == 0) // is SAU zero? return INVALID_MEMLENGTH; // return INVALID_MEMLENGTH if (p_header->subsystem != 0) // is the command for a subsystem? return 0; // no other checks, return /* The start address (24 bit) is computed combining the 8 LS bit of p_tc->data[0] with the whole word p_tc->data[1]. The 16 MS bit of p_tc->data[1] are already masked at the moment of TC reception */ p_header->start_address = (second_part & 0xFF0000) + data[1]; if (p_header->start_address > MEmory_map[p_header->memory_ID].size) // is start_address greater than size? return INVALID_ADDRESS; // return INVALID_ADDRESS if (first_part & 0x10) // DRAM ? { /* RAM_type is DRAM; SAU is 4 bytes */ p_header->RAM_type = 1; /* DRAM */ p_header->length_bytes = p_header->length_SAU * 4; } else { /* RAM_type is PRAM; SAU is 6 bytes */ p_header->RAM_type = 0; /* PRAM */ p_header->length_bytes = p_header->length_SAU * 6; } /* For Memory Load we check the consistency between number of SAU and packet length as written in p_tc->packet_length; in particular (packet_length + 1)/2 is the number of 16bits words of the application data field; then we have 1 word for: data_field_header[0], data_field_header[1], memory ID, start address, length, crc of the data and crc of the packet (ie 7 words). The length in bytes is then ((packet_length + 1)/2-7)*2 = packet_length-13 */ if (length_to_check != 0) // memory LOAD? { if (length_to_check != p_header->length_bytes) // is number of SAU compatible with packet length? return INVALID_MEMLENGTH; // if not return INVALID_MEMLENGTH } end_address = p_header->start_address + p_header->length_SAU - 1; if (end_address > MEmory_map[p_header->memory_ID].size) // is end_address greater than size? return INVALID_ADDRESS;// return INVALID_ADDRESS return 0; } /****************************************************************************** *Function name : memory_load *Purpose: * This function executes the memory load service (6,2) *Syntax: * int value = memory_load(unsigned int * data, memory_header * p_head, int * err) *Input: * data pointer to the data field structure of the TC (starting from data[3]) * p_head pointer to the structure filled in by create_memory_header *Output: * err pointer to a int variable that contains the error value, if any *Return: * value 0: OK * in case of CRC error, it contains the computed checksum ******************************************************************************/ unsigned int memory_load(unsigned int * data, memory_header * p_head, int * err) { /* In mem_buffer the previous memory content is copied. Its size must then be large enough to contain either DM or PM words. This implies that its dimension is the largest between MAX_NUMBER_DM_WORDS_TC and 3*MAX_NUMBER_PM_WORDS_TC (see step 2 below) */ unsigned int mem_buffer[3*MAX_NUMBER_PM_WORDS_TC], i; unsigned int word1, word2, word3, crc, length_in_words, checksum; unsigned int * p_start_address; if (MEmory_map[p_head->memory_ID].is_writeable == 0) { *err = INVALID_MEMID; return 0; } p_start_address = (unsigned int *) (p_head->start_address + MEmory_map[p_head->memory_ID].offset); /* Sequence: 1) verify checksum as written in the packet; if fails return INVALID_CRC_1ST_CHK 2) save the old content of memory 2a) for DRAM we simply use adicpy; 2b) for PRAM we use from_PM_to_DM which copies N PM words in 3N DM words; 3) copy data from TC to memory 3a) for DRAM we use from_2DM_to_1DM which takes N 16 bit words and writes them in N/2 32 bit words 3b) for PRAM we use from_DM_to_PM which copies N DM words in N/3 PM words; 4) compute again checksum; if OK return 5) if check fails restore old memory content and return INVALID_CRC_2ND_CHK */ //length_in_words = p_head->length_bytes/2; length_in_words = p_head->length_bytes >> 1; crc = 0xFFFFFFFF; crc = memcrc16(data,length_in_words,crc); checksum = data[length_in_words]; if (crc != checksum) { *err = INVALID_CRC_1ST_CHK; return crc; } crc = 0xFFFFFFFF; if (p_head->RAM_type) { adicpy(mem_buffer,p_start_address,length_in_words); from_2DM_to_1DM(p_start_address,data,p_head->length_SAU); crc = memcrc32(p_start_address,p_head->length_SAU,crc); if (crc != checksum) { adicpy(p_start_address,mem_buffer,length_in_words); *err = INVALID_CRC_2ND_CHK; return crc; } } else { from_PM_to_DM(p_start_address,mem_buffer,p_head->length_SAU); from_DM_to_PM(p_start_address,data,p_head->length_SAU); for (i=0; ilength_SAU; i++) { one_PM_to_DM(&word1,&word2,&word3,p_start_address+i); crc = crc16(word1, crc); crc = crc16(word2, crc); crc = crc16(word3, crc); } if (crc != checksum) { from_DM_to_PM(p_start_address,mem_buffer,length_in_words); *err = INVALID_CRC_2ND_CHK; return crc; } } *err = MEM_LOAD_OK; return 0; } /****************************************************************************** *Function name : memory_dump *Purpose: * This function executes the memory dump service (6,5) *Syntax: * int value = memory_dump(memory_header * p_head, unsigned int * data_dumped, unsigned int * start_address) *Input: * p_head pointer to the structure filled in by create_memory_header *Output: * data_dumped pointer to the array containing length (first value) and * data dumped. The first time this function is called, this * pointer should be set to NULL. In this case the function * returns the number of TM packets (6,6) required to dump the * requested number of memory cells * start_address pointer to an unsigned int variable that contains the start * address for the current TM packet *Return: * value n: if (data_dumped == NULL) then n is the required number of (6,6) * packets * crc: if (data_dumped != NULL) then the CRC computed on the dumped * memory area ******************************************************************************/ unsigned int memory_dump(memory_header * p_head, unsigned int * data_dumped, unsigned int * start_address) { static unsigned int SAU_left; unsigned int crc, limit, real_address, index, i, buffer; unsigned int pm * p_start_address_pm; unsigned int result_quot, result_rem; if (data_dumped == NULL) { SAU_left = p_head->length_SAU; if (p_head->RAM_type) { result_quot = IFSI_DIV(SAU_left, MAX_NUMBER_DM_WORDS_TM); result_rem = IFSI_MOD(SAU_left, MAX_NUMBER_DM_WORDS_TM); } else { result_quot = IFSI_DIV(SAU_left, MAX_NUMBER_PM_WORDS_TM); result_rem = IFSI_MOD(SAU_left, MAX_NUMBER_PM_WORDS_TM); } if (result_rem == 0) return result_quot; else return (result_quot + 1); } crc = 0xFFFFFFFF; if (p_head->RAM_type) limit = MAX_NUMBER_DM_WORDS_TM; else limit = MAX_NUMBER_PM_WORDS_TM; if (SAU_left <= limit) limit = SAU_left; data_dumped[0] = limit; real_address = MEmory_map[p_head->memory_ID].offset + (*start_address); if (p_head->RAM_type) { if (MEmory_map[p_head->memory_ID].ID == MEMORY_DM_IN_PM_ID) { p_start_address_pm = (unsigned int pm *)real_address; index = 1; for (i=0;imemory_ID].offset + p_head->start_address; if (p_head->RAM_type) { if (MEmory_map[p_head->memory_ID].ID == MEMORY_DM_IN_PM_ID) { p_start_address_pm = (unsigned int pm *)real_address; crc = memcrc32_pm(p_start_address_pm,p_head->length_SAU,crc); } else crc = memcrc32((unsigned int *)(real_address),p_head->length_SAU,crc); } else { /* Case for PRAM */ for (i=0; ilength_SAU; i++) { one_PM_to_DM(&word1,&word2,&word3,(unsigned int *)(real_address)+i); crc = crc16(word1, crc); crc = crc16(word2, crc); crc = crc16(word3, crc); } } return crc; } /****************************************************************************** *Function name : copy_OBSW_image *Purpose: * This function implements a copy of OBSW from LOW_PM to HIGH_PM (before * patching) and from HIGH_PM to LOW_PM (after patching) * *Syntax: * copy_OBSW_image (unsigned int direction, unsigned int StartDestAddr, unsigned int NumOfWords); *Input: * parameter direction = 1 perform LOW_PM to HIGH_PM copy * StartDestAddr: unsigned int that is the start address of DESTINATION image * of OBSW in HIGH_PM * NumOfWords: unsigned int that is the number of words in LOW_PM * to be copied in HIGH_PM. *** * parameter direction = 2 perform HIGH_PM to LOW_PM copy * StartDestAddr: unsigned int that is the start address of source OBSW image * patched in HIGH_PM (it MUST BE equal to that used at the call * with direction = 1) * NumOfWords: unsigned int that is the number of words of source OBSW * image patched in HIGH_PM to be copied in LOW_PM. *Output: * none *Return: * 0 if no error occurres * 1 if error on parameter NumOfWords occurres with direction=1 (NumOfWords >= (StartDestAddr - adicpy_len) OR NumOfWords = 0) * 2 if error on parameter end_address occurres with direction=2 (NumOfWords >= (0x80000 - StartDestAddr) OR NumOfWords = 0 OR NumOfWords >= (StartDestAddr - adicpy_len)) * 3 if error on parameter direction occurres ******************************************************************************/ unsigned int copy_OBSW_image (unsigned int direction, unsigned int StartDestAddr, unsigned int NumOfWords) { //DECLARATION switch (direction) //switch by direction { case LOW_PM2HIGH_PM: //direction=1 perform LOW_PM to HIGH_PM copy if ((NumOfWords >= (StartDestAddr - adicpy_len)) || (NumOfWords == 0)) return NUM_OF_WORDS_WRONG; //return error code 1; // copies NumOfWords PM_LOW data to StartDestAddr PM_HIGH adicpyPM((unsigned int pm *)StartDestAddr, (unsigned int pm *)0, NumOfWords); return COPY_OBSW_IMAGE_OK; break; case HIGH_PM2LOW_PM: //direction=2 perform HIGH_PM to LOW_PM copy if ((NumOfWords >= (0x80000 - StartDestAddr)) || (NumOfWords == 0) || (NumOfWords >= (StartDestAddr - adicpy_len))) return NUM_OF_WORDS_WRONG; //return error code 1; // in case we upload the full image this command can be called directly // with direction=2. In order to preserve boot SW a first call to adicpyPM // is performed: it has no net effect if direction=1 has been sent before; // otherwise it copies boot SW in high memory adicpyPM((unsigned int pm *)(StartDestAddr+256), (unsigned int pm *)256, 0x1555); //adicpyPM moves itself to PM_HIGH to allow calling direction 2 adicpyPM((unsigned int pm *)(StartDestAddr - adicpy_len), (unsigned int pm *)adicpyPM, adicpy_len); copyPatched_AndReset((unsigned int pm *)0, (unsigned int pm *)StartDestAddr, NumOfWords); return COPY_OBSW_IMAGE_OK; break; default: return ILLEGAL_DIRECTION; //return error code3; } }