/** * \brief Unlock all the regions in the given address range. The actual unlock * range is reported through two output parameters. * * \param ul_start Start address of unlock range. * \param ul_end End address of unlock range. * \param pul_actual_start Start address of the actual unlock range (optional). * \param pul_actual_end End address of the actual unlock range (optional). * * \return 0 if successful, otherwise returns an error code. */ uint32_t flash_unlock(uint32_t ul_start, uint32_t ul_end, uint32_t *pul_actual_start, uint32_t *pul_actual_end) { Efc *p_efc; uint32_t ul_actual_start, ul_actual_end; uint16_t us_start_page, us_end_page; uint32_t ul_error; uint16_t us_num_pages_in_region = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; /* Compute actual unlock range and store it */ compute_lock_range(ul_start, ul_end, &ul_actual_start, &ul_actual_end); if (pul_actual_start != NULL) { *pul_actual_start = ul_actual_start; } if (pul_actual_end != NULL) { *pul_actual_end = ul_actual_end; } /* Compute page numbers */ translate_address(&p_efc, ul_actual_start, &us_start_page, 0); translate_address(0, ul_actual_end, &us_end_page, 0); /* Unlock all pages */ while (us_start_page < us_end_page) { ul_error = efc_perform_command(p_efc, EFC_FCMD_CLB, us_start_page); if (ul_error) { return ul_error; } us_start_page += us_num_pages_in_region; } return FLASH_RC_OK; }
/** * \brief Get the number of locked regions inside the given address range. * * \param ul_start Start address of range * \param ul_end End address of range. * * \return The number of locked regions inside the given address range. */ uint32_t flash_is_locked(uint32_t ul_start, uint32_t ul_end) { Efc *p_efc; uint16_t us_start_page, us_end_page; uint8_t uc_start_region, uc_end_region; uint16_t us_num_pages_in_region; uint32_t ul_status; uint32_t ul_error; uint32_t ul_num_locked_regions = 0; uint32_t ul_count = 0; uint32_t ul_bit = 0; /* Compute page numbers */ translate_address(&p_efc, ul_start, &us_start_page, 0); translate_address(0, ul_end, &us_end_page, 0); /* Compute region numbers */ us_num_pages_in_region = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; uc_start_region = us_start_page / us_num_pages_in_region; uc_end_region = us_end_page / us_num_pages_in_region; /* Retrieve lock status */ ul_error = efc_perform_command(p_efc, EFC_FCMD_GLB, 0); /* Skip unrequested regions (if necessary) */ ul_status = efc_get_result(p_efc); while (!(ul_count <= uc_start_region && uc_start_region < (ul_count + 32))) { ul_status = efc_get_result(p_efc); ul_count += 32; } /* Check status of each involved region */ ul_bit = uc_start_region - ul_count; /* Number of region to check (must be > 0) */ ul_count = uc_end_region - uc_start_region + 1; while (ul_count > 0) { if (ul_status & (1 << (ul_bit))) { ul_num_locked_regions++; } ul_count -= 1; ul_bit += 1; if (ul_bit == 32) { ul_status = efc_get_result(p_efc); ul_bit = 0; } } return ul_num_locked_regions; }
/** * \brief Get flash descriptor. * * \param ul_address Flash bank start address. * \param pul_flash_descriptor Pointer to a data buffer to store flash descriptor. * \param ul_size Data buffer size in DWORD. * * \return The actual descriptor length. */ uint32_t flash_get_descriptor(uint32_t ul_address, uint32_t *pul_flash_descriptor, uint32_t ul_size) { Efc *p_efc; uint32_t ul_tmp; uint32_t ul_cnt; translate_address(&p_efc, ul_address, NULL, NULL); /* Command fails */ if (FLASH_RC_OK != efc_perform_command(p_efc, EFC_FCMD_GETD, 0)) { return 0; } else { /* Read until no result */ for (ul_cnt = 0;; ul_cnt++) { ul_tmp = efc_get_result(p_efc); if ((ul_size > ul_cnt) && (ul_tmp != 0)) { *pul_flash_descriptor++ = ul_tmp; } else { break; } } } return ul_cnt; }
/** * \brief Get flash wait state. * * \param ul_address Flash bank start address. * * \return The number of wait states in cycle (no shift). */ uint32_t flash_get_wait_state(uint32_t ul_address) { Efc *p_efc; translate_address(&p_efc, ul_address, NULL, NULL); return efc_get_wait_state(p_efc); }
/** * \brief Set flash wait state. * * \param ul_address Flash bank start address. * \param ul_fws The number of wait states in cycle (no shift). * * \return 0 if successful; otherwise returns an error code. */ uint32_t flash_set_wait_state(uint32_t ul_address, uint32_t ul_fws) { Efc *p_efc; translate_address(&p_efc, ul_address, NULL, NULL); efc_set_wait_state(p_efc, ul_fws); return FLASH_RC_OK; }
uintptr_t mcall_query_memory(uintptr_t id, memory_block_info *p) { uintptr_t physicalAddr = translate_address((uintptr_t) p); memory_block_info *info = (memory_block_info*) physicalAddr; if (id == 0) { info->base = 0x1000000; // hard coded for now, but we can put these values somewhere later info->size = 0x7F000000 - info->base; return 0; } return -1; }
/** * \brief Erase the entire flash. * * \note Only the flash bank including ul_address will be erased. If there are * two flash banks, we need to call this function twice with each bank start * address. * * \param ul_address Flash bank start address. * * \return 0 if successful; otherwise returns an error code. */ uint32_t flash_erase_all(uint32_t ul_address) { Efc *p_efc; translate_address(&p_efc, ul_address, NULL, NULL); if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_EA, 0)) { return FLASH_RC_ERROR; } return FLASH_RC_OK; }
/** * \brief Erase the flash sector. * * \note Erase sector command needs a page number parameter which belongs to * the sector to be erased. * * \param ul_address Flash sector start address. * * \return 0 if successful; otherwise returns an error code. */ uint32_t flash_erase_sector(uint32_t ul_address) { Efc *p_efc; uint16_t us_page; translate_address(&p_efc, ul_address, &us_page, NULL); if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_ES, us_page)) { return FLASH_RC_ERROR; } return FLASH_RC_OK; }
static page * get_page_wrapper(unsigned a, unsigned *offset) { if (!globals.active) { errno = ENOPROTOOPT; return NULL; } unsigned page_num; if (translate_address(a, &page_num, offset) == ERROR) { errno = EFAULT; return NULL; } if (update_act_queries(INC) == ERROR) return NULL; callback_wrapper(1, page_num, 0); return get_page(page_num); }
/** * \brief Set flash wait state. * * \param ul_address Flash bank start address. * \param ul_fws The number of wait states in cycle (no shift). * * \return 0 if successful; otherwise returns an error code. */ uint32_t flash_set_wait_state_adaptively(uint32_t ul_address) { Efc *p_efc; uint32_t clock = SystemCoreClock; translate_address(&p_efc, ul_address, NULL, NULL); /* Set FWS for embedded Flash access according to operating frequency */ if (clock < CHIP_FREQ_FWS_0) { efc_set_wait_state(p_efc, 0); } else if (clock < CHIP_FREQ_FWS_1) { efc_set_wait_state(p_efc, 1); } else if (clock < CHIP_FREQ_FWS_2) { efc_set_wait_state(p_efc, 2); } else if (clock < CHIP_FREQ_FWS_3) { efc_set_wait_state(p_efc, 3); } else { efc_set_wait_state(p_efc, 4); } return FLASH_RC_OK; }
/** * \brief Erase the specified pages of flash. * * \param ul_address Flash bank start address. * * \return 0 if successful; otherwise returns an error code. */ uint32_t flash_erase_page(uint32_t ul_address, uint8_t uc_page_num) { Efc *p_efc; uint16_t us_page; if (uc_page_num >= IFLASH_ERASE_PAGES_INVALID) { return FLASH_RC_INVALID; } if (ul_address & (IFLASH_PAGE_SIZE - 1)) { return FLASH_RC_INVALID; } translate_address(&p_efc, ul_address, &us_page, NULL); if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_EPA, (us_page | uc_page_num))) { return FLASH_RC_ERROR; } return FLASH_RC_OK; }
/** * \brief Set flash wait state. * * \param ul_address Flash bank start address. * \param ul_fws The number of wait states in cycle (no shift). * * \return 0 if successful; otherwise returns an error code. */ uint32_t flash_set_wait_state_adaptively(uint32_t ul_address) { Efc *p_efc; uint32_t clock = sysclk_get_cpu_hz(); translate_address(&p_efc, ul_address, NULL, NULL); /* Set FWS for embedded Flash access according to operating frequency */ if (clock < CHIP_FREQ_FWS_0) { efc_set_wait_state(p_efc, 0); } else if (clock < CHIP_FREQ_FWS_1) { efc_set_wait_state(p_efc, 1); } else if (clock < CHIP_FREQ_FWS_2) { efc_set_wait_state(p_efc, 2); #if (SAM3XA || SAM3U) } else if (clock < CHIP_FREQ_FWS_3) { efc_set_wait_state(p_efc, 3); } else { efc_set_wait_state(p_efc, 4); } #elif (SAM4S || SAM4E || SAM4N || SAM4C || SAM4CP || SAM4CM) } else if (clock < CHIP_FREQ_FWS_3) {
/* pointer into a kernel-virtual-address pointer in physical space... */ static dinode_t *make_dinode (u_int uva) { dinode_t *dinode = (dinode_t *) translate_address (uva, CFFS_DINODE_SIZE); assert ((dinode == NULL) || ((((u_int) dinode) % NBPG) == (uva % NBPG))); return (dinode); }
/** * \brief Write a data buffer on flash. * * \note This function works in polling mode, and thus only returns when the * data has been effectively written. * \note For dual bank flash, this function doesn't support cross write from * bank 0 to bank 1. In this case, flash_write must be called twice (ie for * each bank). * * \param ul_address Write address. * \param p_buffer Data buffer. * \param ul_size Size of data buffer in bytes. * \param ul_erase_flag Flag to set if erase first. * * \return 0 if successful, otherwise returns an error code. */ uint32_t flash_write(uint32_t ul_address, const void *p_buffer, uint32_t ul_size, uint32_t ul_erase_flag) { Efc *p_efc; uint32_t ul_fws_temp; uint16_t us_page; uint16_t us_offset; uint32_t writeSize; uint32_t ul_page_addr; uint16_t us_padding; uint32_t ul_error; uint32_t ul_idx; uint32_t *p_aligned_dest; uint8_t *puc_page_buffer = (uint8_t *) gs_ul_page_buffer; translate_address(&p_efc, ul_address, &us_page, &us_offset); /* According to the errata, set the wait state value to 6. */ ul_fws_temp = efc_get_wait_state(p_efc); efc_set_wait_state(p_efc, 6); /* Write all pages */ while (ul_size > 0) { /* Copy data in temporary buffer to avoid alignment problems. */ writeSize = Min((uint32_t) IFLASH_PAGE_SIZE - us_offset, ul_size); compute_address(p_efc, us_page, 0, &ul_page_addr); us_padding = IFLASH_PAGE_SIZE - us_offset - writeSize; /* Pre-buffer data */ memcpy(puc_page_buffer, (void *)ul_page_addr, us_offset); /* Buffer data */ memcpy(puc_page_buffer + us_offset, p_buffer, writeSize); /* Post-buffer data */ memcpy(puc_page_buffer + us_offset + writeSize, (void *)(ul_page_addr + us_offset + writeSize), us_padding); /* Write page. * Writing 8-bit and 16-bit data is not allowed and may lead to * unpredictable data corruption. */ p_aligned_dest = (uint32_t *) ul_page_addr; for (ul_idx = 0; ul_idx < (IFLASH_PAGE_SIZE / sizeof(uint32_t)); ++ul_idx) { *p_aligned_dest++ = gs_ul_page_buffer[ul_idx]; } if (ul_erase_flag) { ul_error = efc_perform_command(p_efc, EFC_FCMD_EWP, us_page); } else { ul_error = efc_perform_command(p_efc, EFC_FCMD_WP, us_page); } if (ul_error) { return ul_error; } /* Progression */ p_buffer = (void *)((uint32_t) p_buffer + writeSize); ul_size -= writeSize; us_page++; us_offset = 0; } /* According to the errata, restore the wait state value. */ efc_set_wait_state(p_efc, ul_fws_temp); return FLASH_RC_OK; }
void* operator()(void* p) const { return translate_address(p); }
// CLASS METHOD: Interpreter::exec_load_store_instr() // PURPOSE: Load/store instructions move data between memory and the // general registers. They are all encoded as "I-Type" // instructions, and the only addressing mode implemented is base // register plus signed, immediate offset. This directly enables // the use of three distinct addressing modes: register plus // offset; register direct; and immediate. // // ARGUMENTS: None. // RETURNS: None. void Interpreter::exec_load_store_instr(void) { Word vaddr, paddr; switch (op(curr_instr)) { // LB -- Load Byte // // Sign-extend 16-bit `offset` and add to contents of register `base` to // form address. Sign-extend contents of addressed byte and load into // `rt`. case LB: vaddr = gpr[base(curr_instr)] + sign_ext(curr_instr); paddr = translate_address(align(vaddr)); do_load(LOADREG, rt(curr_instr), sign_ext_byte(mem->read(vaddr, paddr), bytepos(vaddr))); break; // LBU -- Load Byte Unsigned // // Sign-extend 16-bit `offse` and add to contents of register `base` to // form address. Zero-extend contents of addressed byte and load into // `rt`. case LBU: vaddr = gpr[base(curr_instr)] + sign_ext(curr_instr); paddr = translate_address(align(vaddr)); do_load(LOADREG, rt(curr_instr), zero_ext_byte(mem->read(vaddr, paddr), bytepos(vaddr))); break; // LH -- Load Halfword // // Sign-extend 16-bit `offset` and add to contents of register `base` to // form address. Sign-extend contents of addressed byte and load into // `rt`. case LH: vaddr = gpr[base(curr_instr)] + sign_ext(curr_instr); paddr = translate_address(align(vaddr)); do_load(LOADREG, rt(curr_instr), sign_ext_hword(mem->read(vaddr, paddr), hwordpos(vaddr))); break; // LHU -- Load Halfword Unsigned // // Sign-extend 16-bit `offset` and add to contents of register `base` to // form address. Zero-extend contents of addressed byte and load into // `rt`. case LHU: vaddr = gpr[base(curr_instr)] + sign_ext(curr_instr); paddr = translate_address(align(vaddr)); do_load(LOADREG, rt(curr_instr), zero_ext_hword(mem->read(vaddr, paddr), hwordpos(vaddr))); break; // LW -- Load Word // // Sign-extend 16-bit `offset` and add to contents of register `base` to // form address. Load contents of addressed word into register `rt`. case LW: vaddr = gpr[base(curr_instr)] + sign_ext(curr_instr); paddr = translate_address(align(vaddr)); do_load(LOADREG, rt(curr_instr), mem->read(vaddr, paddr)); break; // LWL -- Load Word Left // // Sign-extend 16-bit `offset` and add to contents of register `base` to // form address. Shift addressed word left so that addressed byte is // leftmost byte of a word. Merge bytes from memory with contents of // register `rt` and load result into register `rt`. case LWL: vaddr = gpr[base(curr_instr)] + sign_ext(curr_instr); paddr = translate_address(align(vaddr)); do_load(LOADREG, rt(curr_instr), merge(gpr[rt(curr_instr)], mem->read(vaddr, paddr), bytepos(vaddr), true)); break; // LWR -- Load Word Right // // Sign-extend 16-bit `offset` and add to contents of register `base` to // form address. Shfit addressed word right so that addressed byte is // rightmost byte of a word. Merge bytes from memory with contents of // register `rt` and load result into register `rt`. case LWR: vaddr = gpr[base(curr_instr)] + sign_ext(curr_instr); paddr = translate_address(align(vaddr)); do_load(LOADREG, rt(curr_instr), merge(gpr[rt(curr_instr)], mem->read(vaddr, paddr), bytepos(vaddr), false)); break; // SB -- Store Byte // // Sign-extend 16-bit `offset` and add to contents of register `base` to // form address. Store least significant byte of register `rt` at // addressed location. } }
// int cffsd_fsupdate_dinode (u_int sn, int action, struct dinode *d, u_int param1, u_int param2, u_int param3) int serv_fsupdate_dinode (u_int client_eid, int action, struct cffsd_fsupdate_dinode_arg *arg) { int i; char *indirblock; struct dinode *d; u_int param1 = arg->param1; u_int param2 = arg->param2; u_int param3 = arg->param3; dinode_t *dinode; debug_request = 1; dinode = d = translate_address (&arg->dinode); if (dinode == NULL) { kprintf ("sys_fsupdate_dinode: bad address supplied\n"); return (-E_INVAL); } StaticAssert (sizeof(dinode_t) == CFFS_DINODE_SIZE); /* printf ("sys_fsupdate_dinode: action %d, param1 %d (%x), param2 %d\n", action, param1, param1, (u_int)param2); printf ("dinodeNum %d\n", dinode->dinodeNum); */ switch (action) { case CFFS_DINODE_SETMASK: cffs_dinode_setMask (dinode, (mode_t)param1); break; case CFFS_DINODE_SETUID: cffs_dinode_setUid (dinode, (uid_t)param1); break; case CFFS_DINODE_SETGID: cffs_dinode_setGid (dinode, (gid_t)param1); break; case CFFS_DINODE_SETACCTIME: cffs_dinode_setAccTime (dinode, param1); break; case CFFS_DINODE_SETMODTIME: cffs_dinode_setModTime (dinode, param1); break; case CFFS_DINODE_SETCRETIME: cffs_dinode_setCreTime (dinode, param1); break; case CFFS_DINODE_SETLENGTH: cffs_dinode_setLength (dinode, param2); assert (dinode->length == param2); break; case CFFS_DINODE_SETTYPE: if (dinode->type == param1) { return (0); } if ((dinode->dinodeNum != 0) && ((cffs_dinode_isDir(dinode)) || (param1 == S_IFDIR))) { printf ("sys_fsupdate_dinode (%d): trying to change type to or from directory (%d -> %d)\n", action, dinode->type, param1); return (-E_INVAL); } cffs_dinode_setType (dinode, (u_int16_t)param1); break; case CFFS_DINODE_SETLINKCOUNT: if ((dinode->dinodeNum != 0) && (dinode->linkCount != param1)) { printf ("sys_fsupdate_dinode (%d): changing link count directly (%d -> %d)\n", action, dinode->linkCount, param1); //return (-E_INVAL); } cffs_dinode_setLinkCount (dinode, (nlink_t)param1); break; case CFFS_DINODE_SETOPENCOUNT: cffs_dinode_setOpenCount (dinode, param1); break; case CFFS_DINODE_SETDIRNUM: if (cffs_dinode_isDir(dinode)) { printf ("sys_fsupdate_dinode (%d): trying to change dirNum of directory directly (%d -> %d) requested\n", action, dinode->dirNum, param1); return (-E_INVAL); } cffs_dinode_setDirNum (dinode, param1); break; case CFFS_DINODE_SETDIRECT: cffs_dinode_setDirect (dinode, param1, (u_int)param2); break; case CFFS_DINODE_SETINDIRECT: cffs_dinode_setIndirect (dinode, param1, (u_int)param2); break; case CFFS_DINODE_SETGROUPSTART: cffs_dinode_setGroupstart (dinode, param1); break; case CFFS_DINODE_SETGROUPSIZE: cffs_dinode_setGroupsize (dinode, param1); break; case CFFS_DINODE_CLEARBLOCKPOINTERS: cffs_dinode_clearBlockPointers(dinode, param2); break; case CFFS_DINODE_DELAYEDFREE: if ((dinode->linkCount > (cffs_dinode_isDir(dinode))) || (dinode->openCount != 0)) { printf ("sys_fsupdate_dinode (%d): can't free dinode with links or opens (%d, %d) requested\n", action, dinode->linkCount, dinode->openCount); return (-E_INVAL); } for (i=0; i<NUM_DIRECT; i++) { if (dinode->directBlocks[i] != 0) { printf ("sys_fsupdate_dinode (%d): can't free dinode with direct blocks (%d == %d) requested\n", action, i, dinode->directBlocks[i]); return (-E_INVAL); } } for (i=0; i<NUM_INDIRECT; i++) { if (dinode->indirectBlocks[i] != 0) { printf ("sys_fsupdate_dinode (%d): can't free dinode with indirect blocks (%d == %d) requested\n", action, i, dinode->indirectBlocks[i]); return (-E_INVAL); } } /* In the real system, this wants to occur only after the block is written (unless it is not dirty) */ dinode->dinodeNum = 0; break; case CFFS_DINODE_INITINDIRBLOCK: indirblock = (char *) dinode; /* XXX % */ if ((indirblock == NULL) || ((u_int)indirblock % BLOCK_SIZE)) { printf ("sys_fsupdate_dinode (%d): bad indirblock address supplied (%p)\n", action, indirblock); return (-E_INVAL); } bzero (indirblock, BLOCK_SIZE); break; case CFFS_DINODE_INITDINODE: bzero ((char *)dinode, CFFS_DINODE_SIZE); dinode->memory_sanity = CFFS_DINODE_MEMORYSANITY; dinode->type = param1; dinode->linkCount = (cffs_dinode_isDir(dinode)) ? 2 : 1; dinode->dinodeNum = param2; dinode->dirNum = param3; break; default: printf ("sys_fsupdate_dinode: unknown action (%d) requested\n", action); return (-E_INVAL); } return (0); }
// int cffsd_fsupdate_directory (u_int sn, int action, struct embdirent *dirent, u_int param2, u_int param3, u_int param4, u_int param5) int serv_fsupdate_directory (u_int client_eid, int action, struct cffsd_fsupdate_directory_arg *arg) { struct embdirent *dirent; u_int param2 = arg->param2; u_int param3 = arg->uint_param3; // u_int param4 = arg->uint_param4; u_int param5 = arg->param5; u_int param1; /* XXX % */ // char *dirBlock = (char *) translate_address ((param1 - (param1 % BLOCK_SIZE)), BLOCK_SIZE); char *dirBlock; debug_request = 3; dirent = translate_address (&arg->dirent); param1 = (u_int) dirent; dirBlock = (char *)((param1 - (param1 % BLOCK_SIZE))); if (dirBlock == NULL) { return (-E_INVAL); } /* XXX % */ dirent = (embdirent_t *) (dirBlock + (param1 % BLOCK_SIZE)); /* GROK -- need to check for write permission on directory. The relevant */ /* inode should be provided automatically by base disk protection software */ if (!isValidDirent(dirBlock, dirent)) { printf ("sys_fsupdate_directory (%d): invalid dirent specified (%x)\n", action, param1); return (-E_INVAL); } /************************** CFFS_DIRECTORY_INITDIRBLOCK ***********************/ if (action == CFFS_DIRECTORY_INITDIRBLOCK) { int i; dinode_t *dinode; /* XXX */ if ((u_int)dirent % BLOCK_SIZE) { printf ("sys_fsupdate_directory (%d): dirent not start of block (%p)\n", action, dirent); return (-E_INVAL); } bzero ((char *)dirent, BLOCK_SIZE); for (i=0; i<(BLOCK_SIZE/CFFS_EMBDIR_SECTOR_SIZE); i++) { dirent->type = (char) 0; dirent->entryLen = CFFS_EMBDIR_SECTOR_SPACEFORNAMES; dirent->preventryLen = 0; dinode = (dinode_t *) ((char *)dirent + CFFS_DINODE_SIZE); dinode->dinodeNum = 0; dinode = (dinode_t *) ((char *)dirent + (2*CFFS_DINODE_SIZE)); dinode->dinodeNum = 0; dinode = (dinode_t *) ((char *)dirent + (3*CFFS_DINODE_SIZE)); dinode->dinodeNum = 0; dirent = (embdirent_t *) ((char *) dirent + CFFS_EMBDIR_SECTOR_SIZE); } /*************************** CFFS_DIRECTORY_SPLITENTRY ************************/ } else if (action == CFFS_DIRECTORY_SPLITENTRY) { embdirent_t *newDirent; int splitspace = param2; int extraspace; extraspace = (dirent->type == (char)0) ? dirent->entryLen : (dirent->entryLen - embdirentsize(dirent)); if ((extraspace < SIZEOF_EMBDIRENT_T) || (extraspace < splitspace)) { printf ("sys_fsupdate_directory (%d): not enough extra space (%d) (wanted %d)\n", action, extraspace, splitspace); return (-E_INVAL); } if (splitspace == 0) { printf ("sys_fsupdate_directory (%d): bad splitspace (%d) (extraspace %d)\n", action, splitspace, extraspace); return (-E_INVAL); } dirent->entryLen -= splitspace; newDirent = (embdirent_t *) ((u_int)dirent + dirent->entryLen); if (newDirent != dirent) { newDirent->preventryLen = dirent->entryLen; } newDirent->entryLen = splitspace; newDirent->type = 0; newDirent->nameLen = 0; newDirent->name[0] = (char) 0; if (((u_int)newDirent + newDirent->entryLen) % CFFS_EMBDIR_SECTOR_SPACEFORNAMES) { dirent = (embdirent_t *) ((char *)newDirent + newDirent->entryLen); dirent->preventryLen = splitspace; } /* XXX % */ // ret = (param1 - (param1 % BLOCK_SIZE)) + ((u_int)newDirent - (u_int)dirBlock); return ((u_int )newDirent); /*************************** CFFS_DIRECTORY_SETNAME ************************/ } else if (action == CFFS_DIRECTORY_SETNAME) { // char *name = (char *) trup(param2); /* XXX */ char name[256]; u_int namelen = param3; dinode_t *dirDInode = translate_address (&arg->ref_param4); /* XXX -- I thought we only reserved < 128 bytes for names? */ if (namelen > 256) { printf ("sys_fsupdate_directory (%d): name too long (%d)\n", action, namelen); return (-E_INVAL); } if (cffsd_copyin (client_eid, param2, (uint )name, namelen) == -1) return (-E_INVAL); if ((dirDInode == NULL) || (dirDInode->dinodeNum == 0)) { return (-E_INVAL); } /* Note: param5 is fsdev in this case, which should be discoverable */ /* from the dinode's identity... */ if ((dirent->type != 0) && (!isNameUnique(param5, dirDInode, name, namelen))) { printf ("sys_fsupdate_directory (%d): non-unique name specified (%d)\n", action, namelen); return (-E_INVAL); } bcopy(name, dirent->name, namelen); // dirent->name[namelen] = (char) 0; dirent->nameLen = namelen; /*************************** CFFS_DIRECTORY_MERGEENTRY ************************/ } else if (action == CFFS_DIRECTORY_MERGEENTRY) { embdirent_t *next = NULL; int maxleft = CFFS_EMBDIR_SECTOR_SPACEFORNAMES - (param1 % CFFS_EMBDIR_SECTOR_SIZE); int extraspace = 0; while ((extraspace < param2) && (extraspace < maxleft)) { next = (embdirent_t *) ((char *)dirent + dirent->entryLen); if (next->type != 0) { break; } extraspace += next->entryLen; } if (extraspace != param2) { printf ("sys_fsupdate_directory (%d): mismatched extraspaces (%d != %d) (maxleft %d)\n", action, extraspace, param2, maxleft); printf ("next %p, next->entryLen %d\n", next, ((next) ? (next->entryLen) : -1)); return (-E_INVAL); } dirent->entryLen += extraspace; next = (embdirent_t *) ((char *)dirent + dirent->entryLen); if ((u_int) next % CFFS_EMBDIR_SECTOR_SPACEFORNAMES) { next->preventryLen = dirent->entryLen; } /*************************** CFFS_DIRECTORY_SHIFTENTRY ************************/ } else if (action == CFFS_DIRECTORY_SHIFTENTRY) { /********* Not currently supported! ************/ assert (0); #if 0 embdirent_t *tmp; int extraspace; if ((-param2 > (param1 % CFFS_EMBDIR_SECTOR_SIZE)) || ((param2 + (param1 % CFFS_EMBDIR_SECTOR_SIZE)) >= (CFFS_EMBDIR_SECTOR_SPACEFORNAMES - SIZEOF_EMBDIRENT_T))) { printf ("sys_fsupdate_directory (%d): sizes don't work (currOff %d, move %d)\n", action, (param1 % BLOCK_SIZE), param2); return (-E_INVAL); } if (param2 <= 0) { tmp = (embdirent_t *) ((char *)dirent - dirent->preventryLen); extraspace = (tmp->type == (char)0) ? tmp->entryLen : tmp->entryLen - embdirentsize(tmp); if (extraspace < (-param2)) { printf ("sys_fsupdate_directory (%d): not enough extra space (%d < %d)\n", action, extraspace, param2); return (-E_INVAL); } tmp->entryLen -= (-param2); dirent->preventryLen = tmp->entryLen; dirent->entryLen += (-param2); bcopy ((char *) dirent, ((char *)dirent - (-param2)), embdirentsize(dirent)); tmp = (embdirent_t *) ((char *)dirent + dirent->entryLen); if ((u_int) tmp % CFFS_EMBDIR_SECTOR_SPACEFORNAMES) { tmp->preventryLen = dirent->entryLen; } } else { tmp = (embdirent_t *) ((char *)dirent - dirent->preventryLen); extraspace = dirent->entryLen - embdirentsize(dirent); if (extraspace < param2) { printf ("sys_fsupdate_directory (%d): not enough extra space (%d < %d)\n", action, extraspace, param2); return (-E_INVAL); } tmp->entryLen += param2; dirent->preventryLen = tmp->entryLen; dirent->entryLen -= param2; bcopy ((char *)dirent, ((char *)dirent + param2), embdirentsize(dirent)); dirent = (embdirent_t *) ((char *)dirent + tmp->entryLen); tmp = (embdirent_t *) ((char *)dirent + dirent->entryLen); if ((u_int) tmp % CFFS_EMBDIR_SECTOR_SPACEFORNAMES) { tmp->preventryLen = dirent->entryLen; } } #endif /*************************** CFFS_DIRECTORY_SETINODENUM ***********************/ } else if (action == CFFS_DIRECTORY_SETINODENUM) { u_int inodeNum = param2; /* no restrictions is directory entry is not currently live */ if (dirent->type == 0) { dirent->inodeNum = inodeNum; /* this case causes a change in which inode a dirent points to. */ /* because the dirent is live, it must always point to a live inode. */ } else { dinode_t *olddinode; dinode_t *newdinode; if (inodeNum == 0) { printf ("sys_fsupdate_directory (%d): can't set inodeNum to 0 is live dirent\n", action); return (-E_INVAL); } /* if ((param3 == 0) || (param4 == 0)) { printf ("sys_fsupdate_directory (%d): passed NULL for a cheat variable (%d, %d)\n", action, param3, param4); return (-E_INVAL); } */ /* it is a bug in FS code to have valid dirent with 0 for an inodeNum */ assert (dirent->inodeNum != 0); /* this should be retrievable from dirent->inodeNum, which identifies */ /* the containing disk block -- which must be a directory block. */ olddinode = translate_address (&arg->ref_param3); if (olddinode->dinodeNum != dirent->inodeNum) { printf ("sys_fsupdate_directory (%d): mismatching old inodeNums (%d != %d)\n", action, olddinode->dinodeNum, dirent->inodeNum); return (-E_INVAL); } /* this should be retrievable from inodeNum, which identifies the */ /* containing disk block -- which must be a directory block. */ newdinode = translate_address (&arg->ref_param4); if (newdinode->dinodeNum != inodeNum) { printf ("sys_fsupdate_directory (%d): mismatching old inodeNums (%d != %d)\n", action, newdinode->dinodeNum, inodeNum); return (-E_INVAL); } if ((olddinode->type != newdinode->type) && ((cffs_dinode_isDir(olddinode)) || (cffs_dinode_isDir(newdinode)))) { printf ("sys_fsupdate_directory (%d): can't interchange a directory and non-directory (%x != %x)\n", action, olddinode->type, newdinode->type); return (-E_INVAL); } /* this rule helps get us around an ordering requirement!! */ /* (i.e., if we handle ordering in some other way, it can */ /* go away... */ if (newdinode->linkCount < (cffs_dinode_isDir(newdinode) ? 2 : 1)) { printf ("sys_fsupdate_directory (%d): can't link up to disowned inode\n", action); return (-E_INVAL); } /* the big stickler here is that we need to be able to check whether */ /* the caller has the ability to look at newdinode. In particular, */ /* this requires execute permission on a directory that already */ /* contains an existing link. */ if ((olddinode) && (cffs_dinode_isDir(olddinode))) { /* must check that directory is actually empty... */ } /* GROK - I'm pretty sure I've designed away all need for ordering here */ olddinode->linkCount--; newdinode->linkCount++; dirent->inodeNum = inodeNum; dirent->type = newdinode->type >> 8; } /**************************** CFFS_DIRECTORY_SETTYPE **************************/ } else if (action == CFFS_DIRECTORY_SETTYPE) {
// int cffsd_fsupdate_superblock (u_int sn, int action, struct superblock *superblock, u_int param1, u_int param2) int serv_fsupdate_superblock (u_int client_eid, int action, struct cffsd_fsupdate_superblock_arg *arg) { struct superblock *superblock; u_int param1 = arg->param1; u_int param2 = arg->param2; debug_request = 2; superblock = translate_address (&arg->superblock); StaticAssert (sizeof(struct superblock) == NBPG); StaticAssert (BLOCK_SIZE == NBPG); // superblock = (struct superblock *) translate_address ((uint)superblock, NBPG); if (superblock == NULL) { return (-E_INVAL); } if (action == CFFS_SUPERBLOCK_SETDIRTY) { /* allow anyone to set dirty to a non-zero value at any time. */ /* However, must verify that there are no dirty blocks from this */ /* file system before allowing anyone to set dirty to 0. */ superblock->dirty = param1; } else if (action == CFFS_SUPERBLOCK_SETROOTDINODENUM) { /* verify that the provided rootDInodeNum is in fact the correct */ /* system value -- we should know this based on the superblocks addr */ superblock->rootDInodeNum = param1; } else if (action == CFFS_SUPERBLOCK_SETFSNAME) { /* verify that the provided fsname is in fact the correct value */ /* -- should match XN's expectation... */ /* Also, don't allow it to go out of bounds in superblock... */ // char *str = (char *) trup(param1); /* XXX */ strcpy (superblock->fsname, CFFS_FSNAME); } else if (action == CFFS_SUPERBLOCK_DELETE) { superblock->fsname[0] = 0; /* just clear the name for now */ } else if (action == CFFS_SUPERBLOCK_SETFSDEV) { /* verify that the provided fsdev is in fact the correct system value */ /* -- XN should certainly know this... */ superblock->fsdev = param1; } else if (action == CFFS_SUPERBLOCK_SETALLOCMAP) { /* this is a totally temporary call. This field should be maintained */ /* solely by XN... */ superblock->allocMap = param1; } else if (action == CFFS_SUPERBLOCK_SETNUMBLOCKS) { /* this is a totally temporary call. This field should be maintained */ /* solely by XN... */ superblock->numblocks = param1; } else if (action == CFFS_SUPERBLOCK_SETSIZE) { /* this is a totally temporary call. This field should be maintained */ /* solely by XN... */ superblock->size = param1; } else if (action == CFFS_SUPERBLOCK_SETNUMALLOCED) { /* this is a totally temporary call. This field should be maintained */ /* by the ALLOCATE and DEALLOCATE methods... */ superblock->numalloced = param1; } else if (action == CFFS_SUPERBLOCK_SETXNTYPE) { /* this is a totally temporary call. This field should be maintained */ /* and updated only by newfs!!... */ if ((param1 < 0) || (param1 >= CFFS_MAX_XNTYPES)) { printf ("sys_fsupdate_superblock (%d): bad typeno %d (NUM %d)\n", action, param1, CFFS_MAX_XNTYPES); return -E_INVAL; } superblock->xntypes[param1] = param2; } else if (action == CFFS_SUPERBLOCK_INIT) { /* this is a totally temporary call. Just for when not using XN */ bzero (superblock, BLOCK_SIZE); } else if (action == CFFS_SUPERBLOCK_SETBLK) { superblock->blk = param1; } else if (action == CFFS_SUPERBLOCK_SETQUOTA) { if (param1 > superblock->numblocks) { printf ("sys_fsupdate_superblock (%d): quota (%d) is bigger than available space (%d)\n", action, param1, superblock->numblocks); return -E_INVAL; } superblock->quota = param1; } else { printf ("sys_fsupdate_superblock: unknown action requested (%d)\n", action); return (-E_INVAL); } return (0); }