예제 #1
0
파일: flash.c 프로젝트: open-power/skiboot
int flash_register(struct blocklevel_device *bl)
{
	uint64_t size;
	uint32_t block_size;
	struct ffs_handle *ffs;
	struct dt_node *node;
	struct flash *flash;
	const char *name;
	int rc;

	rc = blocklevel_get_info(bl, &name, &size, &block_size);
	if (rc)
		return rc;

	if (!name)
		name = "(unnamed)";

	prlog(PR_INFO, "FLASH: registering flash device %s "
			"(size 0x%llx, blocksize 0x%x)\n",
			name, size, block_size);

	flash = malloc(sizeof(struct flash));
	if (!flash) {
		prlog(PR_ERR, "FLASH: Error allocating flash structure\n");
		return OPAL_RESOURCE;
	}

	flash->busy = false;
	flash->bl = bl;
	flash->no_erase = !(bl->flags & WRITE_NEED_ERASE);
	flash->size = size;
	flash->block_size = block_size;
	flash->id = num_flashes();

	rc = ffs_init(0, flash->size, bl, &ffs, 1);
	if (rc) {
		/**
		 * @fwts-label NoFFS
		 * @fwts-advice System flash isn't formatted as expected.
		 * This could mean several OPAL utilities do not function
		 * as expected. e.g. gard, pflash.
		 */
		prlog(PR_WARNING, "FLASH: No ffs info; "
				"using raw device only\n");
		ffs = NULL;
	}

	node = flash_add_dt_node(flash, flash->id);

	setup_system_flash(flash, node, name, ffs);

	if (ffs)
		ffs_close(ffs);

	lock(&flash_lock);
	list_add(&flashes, &flash->list);
	unlock(&flash_lock);

	return OPAL_SUCCESS;
}
예제 #2
0
static void lookup_partition(const char *name)
{
    int rc;

    if (flash_side == 1) {
        uint32_t other_side_offset;

        rc = open_partition("OTHER_SIDE");
        if (rc == FFS_ERR_PART_NOT_FOUND)
            fprintf(stderr, "side 1 was specified but there doesn't appear"
                    " to be a second side to this flash\n");
        if (rc)
            exit(1);

        /* Just need to know where it starts */
        rc = ffs_part_info(ffsh, ffs_index, NULL, &other_side_offset, NULL, NULL, NULL);
        if (rc)
            exit(1);

        ffs_close(ffsh);
        ffsh = NULL;

        ffs_toc = other_side_offset;
    }

    rc = open_partition(name);
    if (rc)
        exit(1);
}
예제 #3
0
static void
flash_access_cleanup_bmc(void)
{
	if(ffsh)
		ffs_close(ffsh);
	flash_exit(fl_chip);
	ast_sf_close(fl_ctrl);
	close_devs();
}
예제 #4
0
static void print_ffs_info(uint32_t toc_offset)
{
    struct ffs_handle *ffs_handle;
    uint32_t other_side_offset = 0;
    int rc;
    uint32_t i;

    rc = ffs_init(toc_offset, fl_total_size, bl, &ffs_handle, 0);
    if (rc) {
        fprintf(stderr, "Error %d opening ffs !\n", rc);
        return;
    }

    printf("\n");
    printf("TOC@0x%08x Partitions:\n", toc_offset);
    printf("-----------\n");

    for (i = 0;; i++) {
        uint32_t start, size, act, end;
        bool ecc;
        char *name;

        rc = ffs_part_info(ffs_handle, i, &name, &start, &size, &act, &ecc);
        if (rc == FFS_ERR_PART_NOT_FOUND)
            break;
        if (rc) {
            fprintf(stderr, "Error %d scanning partitions\n", rc);
            break;
        }
        end = start + size;
        printf("ID=%02d %15s %08x..%08x (actual=%08x) %s\n",
               i, name, start, end, act, ecc ? "[ECC]" : "");

        if (strcmp(name, "OTHER_SIDE") == 0)
            other_side_offset = start;

        free(name);
    }

    ffs_close(ffs_handle);

    if (other_side_offset)
        print_ffs_info(other_side_offset);
}
예제 #5
0
static void
flash_access_cleanup_pnor(void)
{
	/* Re-lock flash */
	if(need_relock)
		set_wrprotect(true);

	if(ffsh)
		ffs_close(ffsh);
	flash_exit(fl_chip);
#ifdef __powerpc__
	if(using_sfc)
		sfc_close(fl_ctrl);
	else
		ast_sf_close(fl_ctrl);
#else
	ast_sf_close(fl_ctrl);
#endif
	close_devs();
}
예제 #6
0
파일: flash.c 프로젝트: open-power/skiboot
/*
 * load a resource from FLASH
 * buf and len shouldn't account for ECC even if partition is ECCed.
 *
 * The API here is a bit strange.
 * If resource has a STB container, buf will contain it
 * If loading subpartition with STB container, buff will *NOT* contain it
 * For trusted boot, the whole partition containing the subpart is measured.
 *
 * Additionally, the logic to work out how much to read from flash is insane.
 */
static int flash_load_resource(enum resource_id id, uint32_t subid,
			       void *buf, size_t *len)
{
	int i;
	int rc = OPAL_RESOURCE;
	struct ffs_handle *ffs;
	struct flash *flash;
	const char *name;
	bool status = false;
	bool ecc;
	bool part_signed = false;
	void *bufp = buf;
	size_t bufsz = *len;
	int ffs_part_num, ffs_part_start, ffs_part_size;
	int content_size = 0;
	int offset = 0;

	lock(&flash_lock);

	if (!system_flash) {
		/**
		 * @fwts-label SystemFlashNotFound
		 * @fwts-advice No system flash was found. Check for missing
		 * calls flash_register(...).
		 */
		prlog(PR_WARNING, "FLASH: Can't load resource id:%i. "
		      "No system flash found\n", id);
		goto out_unlock;
	}

	flash = system_flash;

	if (flash->busy)
		goto out_unlock;

	for (i = 0, name = NULL; i < ARRAY_SIZE(part_name_map); i++) {
		if (part_name_map[i].id == id) {
			name = part_name_map[i].name;
			break;
		}
	}
	if (!name) {
		prerror("FLASH: Couldn't find partition for id %d\n", id);
		goto out_unlock;
	}
	/*
	 * If partition doesn't have a subindex but the caller specifies one,
	 * we fail.  eg. kernel partition doesn't have a subindex
	 */
	if ((part_name_map[i].subid == RESOURCE_SUBID_NONE) &&
	    (subid != RESOURCE_SUBID_NONE)) {
		prerror("PLAT: Partition %s doesn't have subindex\n", name);
		goto out_unlock;
	}

	rc = ffs_init(0, flash->size, flash->bl, &ffs, 1);
	if (rc) {
		prerror("FLASH: Can't open ffs handle: %d\n", rc);
		goto out_unlock;
	}

	rc = ffs_lookup_part(ffs, name, &ffs_part_num);
	if (rc) {
		/* This is not an error per-se, some partitions
		 * are purposefully absent, don't spam the logs
		 */
	        prlog(PR_DEBUG, "FLASH: No %s partition\n", name);
		goto out_free_ffs;
	}
	rc = ffs_part_info(ffs, ffs_part_num, NULL,
			   &ffs_part_start, NULL, &ffs_part_size, &ecc);
	if (rc) {
		prerror("FLASH: Failed to get %s partition info\n", name);
		goto out_free_ffs;
	}
	prlog(PR_DEBUG,"FLASH: %s partition %s ECC\n",
	      name, ecc  ? "has" : "doesn't have");

	if (ffs_part_size < SECURE_BOOT_HEADERS_SIZE) {
		prerror("FLASH: secboot headers bigger than "
			"partition size 0x%x\n", ffs_part_size);
		goto out_free_ffs;
	}

	rc = blocklevel_read(flash->bl, ffs_part_start, bufp,
			SECURE_BOOT_HEADERS_SIZE);
	if (rc) {
		prerror("FLASH: failed to read the first 0x%x from "
			"%s partition, rc %d\n", SECURE_BOOT_HEADERS_SIZE,
			name, rc);
		goto out_free_ffs;
	}

	part_signed = stb_is_container(bufp, SECURE_BOOT_HEADERS_SIZE);

	prlog(PR_DEBUG, "FLASH: %s partition %s signed\n", name,
	      part_signed ? "is" : "isn't");

	/*
	 * part_start/size are raw pointers into the partition.
	 *  ie. they will account for ECC if included.
	 */

	if (part_signed) {
		bufp += SECURE_BOOT_HEADERS_SIZE;
		bufsz -= SECURE_BOOT_HEADERS_SIZE;
		content_size = stb_sw_payload_size(buf, SECURE_BOOT_HEADERS_SIZE);
		*len = content_size + SECURE_BOOT_HEADERS_SIZE;

		if (content_size > bufsz) {
			prerror("FLASH: content size > buffer size\n");
			rc = OPAL_PARAMETER;
			goto out_free_ffs;
		}

		ffs_part_start += SECURE_BOOT_HEADERS_SIZE;

		rc = blocklevel_read(flash->bl, ffs_part_start, bufp,
					  content_size);
		if (rc) {
			prerror("FLASH: failed to read content size %d"
				" %s partition, rc %d\n",
				content_size, name, rc);
			goto out_free_ffs;
		}

		if (subid == RESOURCE_SUBID_NONE)
			goto done_reading;

		rc = flash_subpart_info(bufp, content_size, ffs_part_size,
					NULL, subid, &offset, &content_size);
		if (rc) {
			prerror("FLASH: Failed to parse subpart info for %s\n",
				name);
			goto out_free_ffs;
		}
		bufp += offset;
		goto done_reading;
	} else /* stb_signed */ {
		/*
		 * Back to the old way of doing things, no STB header.
		 */
		if (subid == RESOURCE_SUBID_NONE) {
			if (id == RESOURCE_ID_KERNEL ||
				id == RESOURCE_ID_INITRAMFS) {
				/*
				 * Because actualSize is a lie, we compute the
				 * size of the BOOTKERNEL based on what the ELF
				 * headers say. Otherwise we end up reading more
				 * than we should
				 */
				content_size = sizeof_elf_from_hdr(buf);
				if (!content_size) {
					prerror("FLASH: Invalid ELF header part"
						" %s\n", name);
					rc = OPAL_RESOURCE;
					goto out_free_ffs;
				}
			} else {
				content_size = ffs_part_size;
			}
			if (content_size > bufsz) {
				prerror("FLASH: %s content size %d > "
					" buffer size %lu\n", name,
					content_size, bufsz);
				rc = OPAL_PARAMETER;
				goto out_free_ffs;
			}
			prlog(PR_DEBUG, "FLASH: computed %s size %u\n",
			      name, content_size);
			rc = blocklevel_read(flash->bl, ffs_part_start,
						  buf, content_size);
			if (rc) {
				prerror("FLASH: failed to read content size %d"
					" %s partition, rc %d\n",
					content_size, name, rc);
				goto out_free_ffs;
			}
			*len = content_size;
			goto done_reading;
		}
		BUILD_ASSERT(FLASH_SUBPART_HEADER_SIZE <= SECURE_BOOT_HEADERS_SIZE);
		rc = flash_subpart_info(bufp, SECURE_BOOT_HEADERS_SIZE,
					ffs_part_size, &ffs_part_size, subid,
					&offset, &content_size);
		if (rc) {
			prerror("FLASH: FAILED reading subpart info. rc=%d\n",
				rc);
			goto out_free_ffs;
		}

		*len = ffs_part_size;
		prlog(PR_DEBUG, "FLASH: Computed %s partition size: %u "
		      "(subpart %u size %u offset %u)\n", name, ffs_part_size,
		      subid, content_size, offset);
		/*
		 * For a sub partition, we read the whole (computed)
		 * partition, and then measure that.
		 * Afterwards, we memmove() things back into place for
		 * the caller.
		 */
		rc = blocklevel_read(flash->bl, ffs_part_start,
					  buf, ffs_part_size);

		bufp += offset;
	}

done_reading:
	/*
	 * Verify and measure the retrieved PNOR partition as part of the
	 * secure boot and trusted boot requirements
	 */
	secureboot_verify(id, buf, *len);
	trustedboot_measure(id, buf, *len);

	/* Find subpartition */
	if (subid != RESOURCE_SUBID_NONE) {
		memmove(buf, bufp, content_size);
		*len = content_size;
	}

	status = true;

out_free_ffs:
	ffs_close(ffs);
out_unlock:
	unlock(&flash_lock);
	return status ? OPAL_SUCCESS : rc;
}
예제 #7
0
uint32_t PNORInstruction::execute(ecmdDataBuffer & o_data, InstructionStatus & o_status, Handle ** io_handle) {
    uint32_t rc = 0;

    /* set the version of this instruction in the status */
    o_status.instructionVersion = version;

#if defined(CRONUS_SERVER_SIDE)
    /* check for any previous errors to report back */
    if (error) {
        rc = o_status.rc = error;
        return rc;
    }

    switch(command) 
    {
        /*
         * GET LIST OPERATION
         */
        case PNORGETLIST:
        {
#if defined(TESTING)
            printf("PNORGETLIST\n");
#endif
            std::string ffsDevice;
            ffsDevice = "/dev/mtdblock/sfc." + deviceString;

#if defined(TESTING)
            printf("ffsData = ffs_open( \"%s\", 0x%X );\n", ffsDevice.c_str(), partitionOffset );
#else
 #if !defined(NO_GFW)
            off_t ffsDeviceOffset = partitionOffset;
            ffs_t *ffs = NULL;
            ffs = ffs_open( ffsDevice.c_str(), ffsDeviceOffset );

            if ( ffs == NULL )
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute SERVER DEBUG: Unable to open device " << ffsDevice << std::endl;
                o_status.errorMessage.append(osse.str());
                osse.clear(); osse.str(std::string());
                osse << "PNORInstruction::execute SERVER DEBUG: Listing partitions in image failed" << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_DEVICE_FAIL_OPEN;
                break;
            }

            ffs_hdr_t *ffsHdr = ffs->hdr;
 #endif
#endif

            Pnor_ffs_hdr *objHolder = new Pnor_ffs_hdr();

#if defined(TESTING)
            printf("transposing ffsData to internal Pnor_ffs_hdr object holder\n");

            objHolder->magic = 0x1;
            objHolder->version = 0x2;
            objHolder->size = 1;
            objHolder->entry_size = 0x80;
            objHolder->entry_count = 2;
            objHolder->block_size = 0x1000;
            objHolder->block_count = 0x4000;
            objHolder->checksum = 0x3;
            Pnor_ffs_entry *objEntry = new Pnor_ffs_entry();
            objEntry->base = 0x1fff;
            objEntry->size = 4096;
            objEntry->pid = 0;
            objEntry->id = 3;
            objEntry->type = 1;
            objEntry->flags = 0x0;
            objEntry->actual = 4096;
            objEntry->checksum = 0x43;
            objEntry->name = "HBBtest";
            (objHolder->entries).push_back(objEntry);
            objEntry = new Pnor_ffs_entry();
            objEntry->base = 0x0fff;
            objEntry->size = 8192;
            objEntry->pid = 0;
            objEntry->id = 2;
            objEntry->type = 3;
            objEntry->flags = 0x1;
            objEntry->actual = 8192;
            objEntry->checksum = 0x51;
            objEntry->name = "PNORtest";
            (objHolder->entries).push_back(objEntry);
#else
 #if !defined(NO_GFW)
            objHolder->magic = ffsHdr->magic;
            objHolder->version = ffsHdr->version;
            objHolder->size = ffsHdr->size;
            objHolder->entry_size = ffsHdr->entry_size;
            objHolder->entry_count = ffsHdr->entry_count;
            objHolder->block_size = ffsHdr->block_size;
            objHolder->block_count = ffsHdr->block_count;
            objHolder->checksum = ffsHdr->checksum;

            for( uint32_t idx = 0; idx < objHolder->entry_count; idx++ )
            {
                Pnor_ffs_entry *objEntry = new Pnor_ffs_entry();
                ffs_entry *ffsEntry = &(ffsHdr->entries[idx]);

                objEntry->base = ffsEntry->base;
                objEntry->size = ffsEntry->size;
                objEntry->pid = ffsEntry->pid;
                objEntry->id = ffsEntry->id;
                objEntry->type = ffsEntry->type;
                objEntry->flags = ffsEntry->flags;
                objEntry->actual = ffsEntry->actual;
                objEntry->checksum = ffsEntry->checksum;
                objEntry->name = ffsEntry->name;

                (objHolder->entries).push_back(objEntry);
            }
 #endif
#endif

            uint32_t flattensize = objHolder->flattenSize();
            uint32_t *flattenedffsData = new uint32_t[flattensize];
            rc = objHolder->flatten( (uint8_t*) flattenedffsData, flattensize );

            if ( rc ) 
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute - flattenffsData failure" << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_ERROR;
                return rc;
            }
#if defined(TESTING)
            printf("Flattened objHolder of size %d\n", flattensize);
#endif

            rc = o_data.setWordLength( flattensize );
            if ( rc ) 
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute - o_data.setWordLength(" << flattensize << ") failure" << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_ERROR;
                return rc;
            }
#if defined(TESTING)
            printf("o_data.getBitLength is %d\n", o_data.getBitLength());
#endif

            rc = o_data.insert( (uint8_t *)flattenedffsData, 0, (flattensize * 32), 0 );
            if ( rc ) 
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute - o_data.insert failure" << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_ERROR;
                return rc;
            }
#if defined(TESTING)
            printf("o_data.insert completed\n");
            printf("\n%s\n", o_data.genHexLeftStr().c_str() );
#else
 #if !defined(NO_GFW)
            rc = ffs_close( ffs );
            if ( rc ) 
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute(" << InstructionCommandToString( command )<< ") - ffs_close failure rc(" << rc << ")" << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_DEVICE_FAIL_CLOSE;
                break;
            }
 #endif
#endif
            delete flattenedffsData;
            delete objHolder;

            rc = o_status.rc = SERVER_COMMAND_COMPLETE;
            break;
        }

        /*
         * GET OPERATION
         */
        case PNORGET:
        {
#if defined(TESTING)
            printf("PNORGET\n");
#endif

            std::string ffsDevice;
            ffsDevice = "/dev/mtdblock/sfc." + deviceString;

#if defined(TESTING)
            printf("ffsData = ffs_open( \"%s\", 0x%X );\n", ffsDevice.c_str(), partitionOffset );
#else
 #if !defined(NO_GFW)
            off_t ffsDeviceOffset = partitionOffset;
            ffs_t *ffsData = NULL;
            ffsData = ffs_open( ffsDevice.c_str(), ffsDeviceOffset );

            if ( ffsData == NULL )
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute SERVER DEBUG: Unable to open device " << ffsDevice << std::endl;
                o_status.errorMessage.append(osse.str());
                osse.clear(); osse.str(std::string());
                osse << "PNORInstruction::execute SERVER DEBUG: Listing partitions in image failed" << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_DEVICE_FAIL_OPEN;
                break;
            }
 #endif
#endif

#if defined(TESTING)
            printf("iterate over ffsData\n");
#else
 #if !defined(NO_GFW)
            //partitionEntry must match a partition entry within the ffsData, find it
            ffs_hdr_t *ffsHdr = ffsData->hdr;
            ffs_entry *myFoundEntry = NULL;
            for( uint32_t idx = 0; idx < ffsHdr->entry_count; idx++ )
            {
                ffs_entry *ffsEntry = &(ffsHdr->entries[idx]);
                std::string entryName = ffsEntry->name;
                if ( entryName == partitionEntry )
                {
                    myFoundEntry = ffsEntry;
                    break;
                }
            }
            
            if ( myFoundEntry == NULL )
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute Unable to find a matching partition with name " << partitionEntry << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_PARTITION_NOT_FOUND;
                break;
            }
 #endif
#endif

#if defined(TESTING)
            printf("matched partition, now get data\n");
#else
 #if !defined(NO_GFW)
            // myFoundEntry points to the specific entry we want to read out
            if (global_server_debug) printf("myFoundEntry->type=%d, myFoundEntry->checksum=%.16X\n", myFoundEntry->type, myFoundEntry->checksum );
            if ( myFoundEntry->type == FFS_TYPE_LOGICAL )
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute Unable to get data from a logical partition for name " << partitionEntry << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_PARTITION_TYPE_INVALID;
                break;
            }
            else if ( myFoundEntry->actual == 0 )
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute Size of partition is 0, not reading anything out for name " << partitionEntry << " size(" << myFoundEntry->actual << ")" << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_PARTITION_EMPTY;
                break;
            }
            else
            {
                uint32_t bufferSize = ffsHdr->block_size * ffsData->buf_count;
                uint32_t *buffer = new uint32_t[bufferSize];
                // uses partitionOffset
                uint32_t total = 0;
                uint32_t size = myFoundEntry->actual;
                off_t offset = 0;

                if (global_server_debug) printf("bufferSize(%d), total(%d), size(%d), offset(%d)\n", bufferSize, total, size, (uint32_t) offset);

                while ( 0 < size )
                {
                    size_t count = std::min( bufferSize, size );

                    if (global_server_debug) printf("name(%s), offset(%d), count(%d), size(%d), total(%d)\n", partitionEntry.c_str(), (uint32_t) offset, count, size, total);

                    uint32_t bytesRead = ffs_entry_read( ffsData, partitionEntry.c_str(), buffer, offset, count ); 

                    if (global_server_debug) printf("post ffs_entry_read bytesRead=%d\n", bytesRead);
                    if ( bytesRead < 0 ) 
                    {
                        std::ostringstream osse;
                        osse << "PNORInstruction::execute failure in ffs_entry_read " << partitionEntry << " offset(" << offset << ") count(" << count << ")" << std::endl;
                        o_status.errorMessage.append(osse.str());
                        rc = o_status.rc = SERVER_PNOR_READ_ERROR;
                        break;
                    }
                    else if ( bytesRead != count )
                    {
                        std::ostringstream osse;
                        osse << "PNORInstruction::execute failure to read enough data from partition " << partitionEntry << " expected(" << count << ") bytesRead(" << bytesRead << ")" << std::endl;
                        o_status.errorMessage.append(osse.str());
                        rc = o_status.rc = SERVER_PNOR_READ_ERROR;
                        break;
                    }

                    o_data.growBitLength( o_data.getBitLength() + (count*32) );
                    o_data.insert( buffer, total*32, count*32, 0 );

                    size -= count; 
                    total += count;
                    offset += count;
                }

                // always attempt to close and only fallout on close if it fails
                // otherwise fallout on rc generated earlier
                rc = ffs_close( ffsData );
                if (global_server_debug) printf("post ffs_close rc=%d\n", rc);
                if ( rc ) 
                {
                    std::ostringstream osse;
                    osse << "PNORInstruction::execute(" << InstructionCommandToString( command )<< ") - ffs_close failure rc(" << rc << ")" << std::endl;
                    o_status.errorMessage.append(osse.str());
                    rc = o_status.rc = SERVER_PNOR_DEVICE_FAIL_CLOSE;
                    break;
                }
            }
 #endif
#endif
            // make sure to set rc to COMMAND_COMPLETE if not already set
            // otherwise leave rc as is so it can be returned
            if ( rc == 0 )
            {
                rc = o_status.rc = SERVER_COMMAND_COMPLETE;
            }
            break;
        }

        /*
         * PUT OPERATION
         */
        case PNORPUT:
        {
#if defined(TESTING)
            printf("PNORPUT\n");
#endif

            std::string ffsDevice;
            ffsDevice = "/dev/mtdblock/sfc." + deviceString;

#if defined(TESTING)
            printf("ffsData = ffs_open( \"%s\", 0x%X );\n", ffsDevice.c_str(), partitionOffset );
#else
 #if !defined(NO_GFW)
            off_t ffsDeviceOffset = partitionOffset;
            ffs_t *ffsData = NULL;
            ffsData = ffs_open( ffsDevice.c_str(), ffsDeviceOffset );

            if ( ffsData == NULL )
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute SERVER DEBUG: Unable to open device " << ffsDevice << std::endl;
                o_status.errorMessage.append(osse.str());
                osse.clear(); osse.str(std::string());
                osse << "PNORInstruction::execute SERVER DEBUG: Listing partitions in image failed" << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_DEVICE_FAIL_OPEN;
                break;
            }
 #endif
#endif

#if defined(TESTING)
            printf("iterate over ffsData\n");
#else
 #if !defined(NO_GFW)
            //partitionEntry must match a partition entry within the ffsData, find it
            ffs_hdr_t *ffsHdr = ffsData->hdr;
            ffs_entry *myFoundEntry = NULL;
            for( uint32_t idx = 0; idx < ffsHdr->entry_count; idx++ )
            {
                ffs_entry *ffsEntry = &(ffsHdr->entries[idx]);
                std::string entryName = ffsEntry->name;
                if ( entryName == partitionEntry )
                {
                    myFoundEntry = ffsEntry;
                    break;
                }
            }
            
            if ( myFoundEntry == NULL )
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute Unable to find a matching partition with name " << partitionEntry << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_PARTITION_NOT_FOUND;
                break;
            }
 #endif
#endif

#if defined(TESTING)
            printf("matched partition, now get data\n");
#else
 #if !defined(NO_GFW)
            // myFoundEntry points to the specific entry we want to read out
            if (global_server_debug) printf("myFoundEntry->type=%d, myFoundEntry->checksum=%.16X\n", myFoundEntry->type, myFoundEntry->checksum );
            if ( myFoundEntry->type == FFS_TYPE_LOGICAL )
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute Unable to get data from a logical partition for name " << partitionEntry << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_PARTITION_TYPE_INVALID;
                break;
            }
            else if ( myFoundEntry->actual == 0 )
            {
                std::ostringstream osse;
                osse << "PNORInstruction::execute Size of partition is 0, not reading anything out for name " << partitionEntry << " size(" << myFoundEntry->actual << ")" << std::endl;
                o_status.errorMessage.append(osse.str());
                rc = o_status.rc = SERVER_PNOR_PARTITION_EMPTY;
                break;
            }
            else
            {
                uint32_t bufferSize = ffsHdr->block_size * ffsData->buf_count;
                if ( blockSize != 0 )
                {
                    bufferSize = blockSize;
                }
                uint32_t *buffer = new uint32_t[bufferSize];
                
                uint32_t total = 0;
                uint32_t size = myFoundEntry->actual;
                off_t offset = 0;   

                if (global_server_debug) printf("bufferSize(%d), total(%d), size(%d), offset(%d), o_data.getWordLength()(%d)\n", bufferSize, total, size, (uint32_t) offset, o_data.getWordLength());

                if ( pnorFlags & INSTRUCTION_PNOR_FLAG_ERASE_PARTITION )
                {
                    // get first word from o_data (most likely 0)
                    uint32_t myWord = o_data.getWord(0);
                    // set the data buffer to the size of the partition
                    o_data.setWordLength(size);
                    // set each word in the buffer to myWord
                    for( uint32_t idx=0; idx < size; idx++ )
                    {
                        o_data.setWord( idx, myWord );
                    }
                    if (global_server_debug) printf("erasing buffer with value (%d) for each word\n", myWord);
                } 

                if ( o_data.getWordLength() != size )
                {
                    std::ostringstream osse;
                    osse << "PNORInstruction::execute size mismatch for " << partitionEntry << " size(" << size << ") is not equal to input size(" << o_data.getWordLength() << ")" << std::endl;
                    o_status.errorMessage.append(osse.str());
                    rc = o_status.rc = SERVER_PNOR_WRITE_ERROR;
                    break;
                }

                while ( 0 < size )
                {
                    size_t count = std::min( bufferSize, size );

                    if (global_server_debug) printf("name(%s), offset(%d), count(%d), size(%d), total(%d)\n", partitionEntry.c_str(), (uint32_t) offset, count, size, total);

                    // copy data from the ecmdDataBuffer into buffer for count (uint32_t's)
                    memset( buffer, 0x0, bufferSize );
                    o_data.extract( buffer, total * 32, count * 32 );

                    uint32_t bytesWritten = ffs_entry_write( ffsData, partitionEntry.c_str(), buffer, offset, count ); 

                    uint32_t fsyncRc = ffs_fsync( ffsData );

                    if (global_server_debug) printf("post ffs_entry_write bytesWritten=%d\n", bytesWritten);
                    if ( bytesWritten < 0 ) 
                    {
                        std::ostringstream osse;
                        osse << "PNORInstruction::execute failure in ffs_entry_write " << partitionEntry << " offset(" << offset << ") count(" << count << ")" << std::endl;
                        o_status.errorMessage.append(osse.str());
                        rc = o_status.rc = SERVER_PNOR_WRITE_ERROR;
                        break;
                    }
                    else if ( bytesWritten != count )
                    {
                        std::ostringstream osse;
                        osse << "PNORInstruction::execute failure to read enough data from partition " << partitionEntry << " expected(" << count << ") bytesWritten(" << bytesWritten << ")" << std::endl;
                        o_status.errorMessage.append(osse.str());
                        rc = o_status.rc = SERVER_PNOR_WRITE_ERROR;
                        break;
                    }
                    if ( fsyncRc < 0 )
                    {
                        std::ostringstream osse;
                        osse << "PNORInstruction::execute failure in ffs_fsync " << partitionEntry << " fsyncRc(" << fsyncRc << ")" << std::endl;
                        o_status.errorMessage.append(osse.str());
                        rc = o_status.rc = SERVER_PNOR_FSYNC_ERROR;
                        break;
                    }
                    
                    size -= count;
                    total += count;
                    offset += count;
                }
                // always attempt to close and only fallout on close if it fails
                // otherwise fallout on rc generated earlier
                rc = ffs_close( ffsData );
                if (global_server_debug) printf("post ffs_close rc=%d\n", rc);
                if ( rc ) 
                {
                    std::ostringstream osse;
                    osse << "PNORInstruction::execute(" << InstructionCommandToString( command )<< ") - ffs_close failure rc(" << rc << ")" << std::endl;
                    o_status.errorMessage.append(osse.str());
                    rc = o_status.rc = SERVER_PNOR_DEVICE_FAIL_CLOSE;
                    break;
                }
            } 
 #endif
#endif

            // make sure to set rc to COMMAND_COMPLETE if not already set
            // otherwise leave rc as is so it can be returned
            if ( rc == 0 )
            {
                rc = o_status.rc = SERVER_COMMAND_COMPLETE;
            }
            break;
        }
        default:
            rc = o_status.rc = SERVER_COMMAND_NOT_SUPPORTED;
            break;
    }

#endif // CRONUS_SERVER_SIDE

  return rc;
}