codemem.c

来自「嵌入式操作系统内核」· C语言 代码 · 共 567 行

C
567
字号
/** *  Routines for managing code space *  *  In most embedded system, code space is different from data space *  Code space has to be physically contineous  *  Writing to code space is typically constrainted by underlying Flash  *  Layout * *  This component keeps track of the status of underlying code space *  It also talks to sos_linker to fix the address *  It provides the storage for code *  It keeps track of the offset of code *   *  To use this component, protocol must first request a block *   */ #include <hardware.h>#include <sos_inttypes.h>#include <pid.h>#include <flash.h>#include <codemem.h>#include <malloc.h>#include <fntable.h>#include <string.h>#include <sos_sched.h>#include <random.h>#include <sos_logging.h>#ifdef SOS_HAS_EXFLASH#include <exflash.h>#endif#ifdef SOS_SIM#include <sim_interface.h>#endif#ifndef SOS_DEBUG_CODEMEM#undef DEBUG#define DEBUG(...)#endif#include <melfloader.h>#define CODEMEM_EXECUTABLE_FLAG  0x01/** * Internal data structure for opened flash space */typedef struct codemem_hdr_t {	uint32_t start_addr;          //!< starting address in the flash	uint16_t size;                //!< size of the allocation	uint8_t  salt;                //!< salt number to prevent 	uint8_t  flag;  } codemem_hdr_t;//// flash_start_page is used to compute the address //static uint16_t flash_start_page;static uint8_t* flash_alloc_bitmap;static uint8_t  flash_bitmap_length;static uint16_t flash_num_pages;static codemem_hdr_t* codemem_handle_list[CODEMEM_MAX_LOADABLE_MODULES];static uint8_t  codemem_salt;static mod_header_ptr compiled_modules[NUM_COMPILED_MODULES] = { 0 };static uint8_t compiled_header_ptr = 0;//// Cache to reduce number of flash writes//static uint8_t* flash_cache_page;      // A FLASHMEM_PAGE_SIZE worth of datastatic uint32_t flash_cache_addr;      // the starting address of the page// ================================================================================// Internal Helper Routines//static bool check_codemem_t( codemem_t cm ){	uint8_t real_h = (uint8_t)( cm & 0x00ff );	uint8_t salt   = (uint8_t)( cm >> 8 );		if( real_h > CODEMEM_MAX_LOADABLE_MODULES ) {		DEBUG("check_codemem_t: CODEMEM_MAX_LOADABLE_MODULES\n");		return false;	}		if( codemem_handle_list[ real_h ] == NULL ) {		DEBUG("check_codemem_t: codemem_handle_list[ real_h ] == NULL\n");		return false;	}		if( (codemem_handle_list[ real_h ]->salt) != salt ) {		DEBUG("codemem_handle_list[ real_h ]->salt) != salt\n");		return false;	}	return true;}static void codemem_do_killall( codemem_t h ){  mod_header_ptr p;  sos_code_id_t  cid;	  p = ker_codemem_get_header_address( h );  if( p == 0 ) return;  cid = sos_read_header_word(p, offsetof(mod_header_t, code_id));  cid = entohs(cid);  ker_killall(cid);}static mod_header_ptr match_cid(uint32_t addr, sos_code_id_t cid){  mod_header_ptr modptr;  sos_code_id_t  mod_cid;  modptr = (mod_header_ptr)FlashGetProgmem( addr );  mod_cid = sos_read_header_word(modptr, offsetof(mod_header_t, code_id));  mod_cid = entohs(mod_cid);  if(mod_cid == cid) {    return modptr;  }  return 0;}static void flash_setbitmap(uint16_t start, uint16_t length, bool val){	uint8_t i;	uint8_t j;	register uint8_t shift = 1;		i = start / 8;	j = start % 8;		shift = 1 << j;		for( ; j < 8 && length > 0; j++, shift <<= 1, length-- ) {		if( val ) {			flash_alloc_bitmap[i] |= shift;		} else {			flash_alloc_bitmap[i] &= ~shift;		}	}	i++;		for( ; i < flash_bitmap_length && length > 0; i++ ) {		shift = 1;		for( j = 0; j < 8 && length > 0; j++, shift <<= 1, length-- ) {			if( val ) {				flash_alloc_bitmap[i] |= shift;			} else {				flash_alloc_bitmap[i] &= ~shift;			}		}	}}static int8_t codemem_cache_alloc( void ){		if( flash_cache_page == NULL ) {		flash_cache_page = ker_malloc( FLASHMEM_PAGE_SIZE, KER_CODEMEM_PID );		if( flash_cache_page == NULL ) {			return -ENOMEM;		}		flash_cache_addr = 0;	}	return SOS_OK;}static inline void codemem_cache_flush( ){	if( flash_cache_page != NULL ) {		flash_erase( flash_cache_addr, FLASHMEM_PAGE_SIZE );		flash_write( flash_cache_addr, flash_cache_page, FLASHMEM_PAGE_SIZE );		ker_free( flash_cache_page );		flash_cache_page = NULL;		flash_cache_addr = 0;	}}//// Get the starting page address.  If the cache does not exist, allocate it.  // If the page address is the same as // flash_cache_addr, write to the cache.  If the page address is different // from flash_cache_addr, perform the following.// 1. store current page// 2. load new page// 3. save the content// WARNING: this rountine does not handle writes across page boundary.// WARNING: this rountine assumes the cache is already allocated.//static void codemem_cache_write( uint32_t addr, uint8_t* buf, uint16_t nbytes ){	uint16_t i;	uint32_t start_addr = addr & ~((uint32_t)(FLASHMEM_PAGE_SIZE - 1));	uint16_t offset = addr % FLASHMEM_PAGE_SIZE;		if( flash_cache_addr != start_addr ) {		if( flash_cache_addr != 0 ) {			flash_erase( flash_cache_addr, FLASHMEM_PAGE_SIZE );			flash_write( flash_cache_addr, flash_cache_page, FLASHMEM_PAGE_SIZE );		}		flash_cache_addr = start_addr;		flash_read( start_addr, flash_cache_page, FLASHMEM_PAGE_SIZE );	}		for( i = 0; i < nbytes; i++, offset++ ) {		flash_cache_page[offset] = buf[i];	}}static void codemem_cache_read( uint32_t addr, uint8_t* buf, uint16_t nbytes ){	uint16_t i = 0;	uint32_t start_addr = addr & ~((uint32_t)(FLASHMEM_PAGE_SIZE - 1));	uint16_t offset = addr % FLASHMEM_PAGE_SIZE;		if( flash_cache_addr == start_addr ) {		uint16_t tmp = (FLASHMEM_PAGE_SIZE - offset);		for( i = 0; (i < tmp) && (nbytes != 0); i++, offset++ ) {			*buf = flash_cache_page[offset];			buf++;			nbytes--;			addr++;		}	}	if( nbytes == 0 ) {		return;	}	flash_read( addr, buf, nbytes );	return;}//// Allocate flash memory according to the size// \return the address to the flash// \return zero for failure//static uint32_t flash_alloc( uint16_t size ){	uint8_t i, j;	uint8_t num_blocks;	uint8_t free_blocks = 0; 	uint32_t addr;		if( codemem_cache_alloc() != SOS_OK ) {		return -ENOMEM;	}		num_blocks = (uint8_t)((size + (FLASHMEM_PAGE_SIZE - 1)) / FLASHMEM_PAGE_SIZE);		//	// Address-ordered first fit	// Search from the beginning and find 	//	for( i = 0; i < flash_bitmap_length; i++ ) {		register uint8_t shift = 1;		register uint8_t tmp = flash_alloc_bitmap[i];		for( j = 0; j < 8; j++, shift <<= 1 ) {			if( tmp & shift ) {				free_blocks = 0;			} else {				free_blocks++;			}			if( free_blocks == num_blocks ) {				//				// set the bit map				//				flash_setbitmap(i*8 + j + 1 - num_blocks, num_blocks, true);				addr = (flash_start_page + i*8 + j + 1 - num_blocks) * FLASHMEM_PAGE_SIZE;				return addr;			}		}	}	return 0;}static void flash_free( uint32_t addr, uint16_t size ){	uint16_t b = (addr / FLASHMEM_PAGE_SIZE) - flash_start_page;	uint8_t num_blocks = (uint8_t)((size + FLASHMEM_PAGE_SIZE - 1) / FLASHMEM_PAGE_SIZE);	 	//	// Unset the bit map	//	flash_setbitmap(b, num_blocks, false);	flash_erase( addr, size );}// ================================================================================// Public Routines//codemem_t ker_codemem_alloc(uint16_t size, codemem_type_t type){	uint8_t i;	codemem_hdr_t *hdr;	codemem_t      ret;	//	// Allocate meta data  	//		for( i = 0; i < CODEMEM_MAX_LOADABLE_MODULES; i++ ) {		if( codemem_handle_list[i] == NULL ) {			break;		}	}		if( i == CODEMEM_MAX_LOADABLE_MODULES ) {		//		// Maximum file reached...		//		return CODEMEM_INVALID;	}		hdr = malloc_longterm( sizeof(codemem_hdr_t), KER_CODEMEM_PID );		if( hdr == NULL ) {		return CODEMEM_INVALID;	}		hdr->start_addr = flash_alloc( size );	//post_uart(KER_CODEMEM_PID, KER_CODEMEM_PID, 100, 4, &(hdr->start_addr), 0, BCAST_ADDRESS);	if( hdr->start_addr == 0 ) {		ker_free( hdr );		return CODEMEM_INVALID;	}	hdr->size = size;	codemem_handle_list[i] = hdr;		codemem_salt++;	hdr->salt = codemem_salt;	hdr->flag = 0;	ret = ((uint16_t)i) | (((uint16_t)codemem_salt) << 8);	//flash_erase( hdr->start_addr , size );	ker_log( SOS_LOG_CMEM_ALLOC, ker_get_current_pid(), size );		return ret;}int8_t ker_codemem_write(codemem_t h, sos_pid_t pid, void *buf, uint16_t nbytes, uint16_t offset){	uint8_t cmt = (uint8_t)(h & 0x00ff);	codemem_hdr_t *hdr;	uint8_t *b = buf;	uint32_t start_addr;	uint16_t size_written;	uint16_t remaining_size;		DEBUG("ker_codemem_write: nbytes = %d, offset = %d\n", nbytes, offset);	if( check_codemem_t( h ) == false ) {		return -ENOENT;	}		if( codemem_cache_alloc() != SOS_OK ) {		return -ENOMEM;	}		hdr = codemem_handle_list[cmt];		start_addr = hdr->start_addr + offset;	size_written = 0;	//	// Remaining size in the page	// FLASHMEM_PAGE_SIZE - (start_addr % FLASHMEM_PAGE_SIZE) 	//	remaining_size = FLASHMEM_PAGE_SIZE - (start_addr % FLASHMEM_PAGE_SIZE);	if( remaining_size < nbytes ) {		codemem_cache_write( start_addr, b, remaining_size );		size_written = remaining_size;		start_addr += remaining_size;		b += remaining_size;	}  		while( 1 ) {		if( (nbytes - size_written) > FLASHMEM_PAGE_SIZE ) {			codemem_cache_write( start_addr, b, FLASHMEM_PAGE_SIZE );			size_written +=  FLASHMEM_PAGE_SIZE;			start_addr += FLASHMEM_PAGE_SIZE;			b += FLASHMEM_PAGE_SIZE;		} else {			if( (nbytes - size_written) != 0 ) {				codemem_cache_write( start_addr, b, nbytes - size_written );			}			break;		}	}	ker_log( SOS_LOG_CMEM_WRITE, pid, nbytes );		return SOS_OK;}	int8_t ker_codemem_read(codemem_t h, sos_pid_t pid, void *buf, uint16_t nbytes, uint16_t offset){	uint8_t cmt = (uint8_t)(h & 0x00ff);	codemem_hdr_t *hdr;		if( check_codemem_t( h ) == false ) {		return -ENOENT;	}		hdr = codemem_handle_list[cmt];	codemem_cache_read( hdr->start_addr + offset, buf, nbytes );	ker_log( SOS_LOG_CMEM_READ, pid, nbytes );		return SOS_OK;}int8_t ker_codemem_free(codemem_t h){	uint8_t cmt = (uint8_t)(h & 0x00ff);	codemem_hdr_t *hdr;		if( check_codemem_t( h ) == false ) {		return -ENOENT;	}		hdr = codemem_handle_list[cmt];		if( hdr->flag & CODEMEM_EXECUTABLE_FLAG ) {		codemem_do_killall(h);	}		flash_free( hdr->start_addr, hdr->size );		codemem_handle_list[cmt] = NULL;		ker_log( SOS_LOG_CMEM_FREE, ker_get_current_pid(), hdr->size );		ker_free( hdr );	return SOS_OK;}//// //int8_t ker_codemem_flush(codemem_t h, sos_pid_t pid){	codemem_cache_flush();	return SOS_OK;}int8_t codemem_register_module( mod_header_ptr h ){  if (compiled_header_ptr >= NUM_COMPILED_MODULES) return -EINVAL;  compiled_modules[compiled_header_ptr++] = h;  return SOS_OK;}mod_header_ptr ker_codemem_get_header_from_code_id( sos_code_id_t cid ){  uint8_t i;  mod_header_ptr ret;    for( i = 0; i < CODEMEM_MAX_LOADABLE_MODULES; i++ ) {	if( (codemem_handle_list[i] != NULL) && 		(codemem_handle_list[i]->flag & CODEMEM_EXECUTABLE_FLAG) ) {		ret = match_cid( codemem_handle_list[i]->start_addr, cid ); 		if( ret != 0 ) {#ifndef SOS_SIM			return ret;#else			return get_header_from_sim( cid );#endif      }	}  }  	  for (i = 0; i < compiled_header_ptr; i++) {    sos_code_id_t code_id;    ret = compiled_modules[i];    code_id = sos_read_header_word(ret, offsetof(mod_header_t, code_id));    code_id = entohs( code_id );    if(cid == code_id){      return ret;    }  }	  return 0;}int8_t ker_codemem_mark_executable(codemem_t h){	uint8_t cmt = (uint8_t)(h & 0x00ff);	codemem_hdr_t *hdr;		if( check_codemem_t( h ) == false ) {		return -ENOENT;	}		hdr = codemem_handle_list[cmt];	hdr->flag |= CODEMEM_EXECUTABLE_FLAG;	return SOS_OK;}uint32_t ker_codemem_get_start_address( codemem_t h ){	uint8_t cmt = (uint8_t)(h & 0x00ff);	codemem_hdr_t *hdr;		if( check_codemem_t( h ) == false ) {		return (uint32_t)0;	}	hdr = codemem_handle_list[cmt];	return hdr->start_addr;	}mod_header_ptr ker_codemem_get_header_address( codemem_t h){#ifndef SOS_SIM	return melf_get_header_address( h );#else	mod_header_ptr p = melf_get_header_address( h );	sos_code_id_t cid =                                         		      sos_read_header_word( p, offsetof(mod_header_t, code_id) );	cid = entohs(cid);                                          	return get_header_from_sim( cid );        #endif}void codemem_init(void){	uint8_t i;		//	// Compute the starting page for programming	//	flash_start_page = flash_init();		flash_num_pages = (FLASHMEM_SIZE / FLASHMEM_PAGE_SIZE)  - flash_start_page;		flash_bitmap_length = (uint8_t)((flash_num_pages + 7) / 8);	//	// Allocate memory for bitmap	//	flash_alloc_bitmap = malloc_longterm( flash_bitmap_length, KER_CODEMEM_PID );		//	// Initialize bitmap	//	for( i = 0; i < flash_bitmap_length; i++ ) {		flash_alloc_bitmap[i] = 0;	}		for( i = 0; i < CODEMEM_MAX_LOADABLE_MODULES; i++ ) {		codemem_handle_list[i] = NULL;	}		codemem_salt = 0;		flash_cache_page = NULL;	flash_cache_addr = 0;}int8_t ker_sys_codemem_read(codemem_t h, void *buf, uint16_t nbytes, uint16_t offset){  sos_pid_t my_pid = ker_get_current_pid();  return ker_codemem_read(h, my_pid, buf, nbytes, offset);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?