static int open_partition(const char *name) { uint32_t index; int rc; /* Open libffs if needed */ if (!ffsh) { rc = ffs_init(ffs_toc, fl_total_size, bl, &ffsh, 0); if (rc) { fprintf(stderr, "Error %d opening ffs !\n", rc); if (ffs_toc) fprintf(stderr, "You specified 0x%08x as the libffs TOC" " looks like it doesn't exist\n", ffs_toc); return rc; } } /* Find partition */ rc = ffs_lookup_part(ffsh, name, &index); if (rc == FFS_ERR_PART_NOT_FOUND) { fprintf(stderr, "Partition '%s' not found !\n", name); return rc; } if (rc) { fprintf(stderr, "Error %d looking for partition '%s' !\n", rc, name); return rc; } ffs_index = index; return 0; }
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; }
/* * Memory based filesystem initialization. */ void mfs_init(void) { if (mfs_initcnt++ == 0) { mutex_init(&mfs_lock, MUTEX_DEFAULT, IPL_NONE); ffs_init(); } }
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); }
int ffs_next_side(struct ffs_handle *ffs, struct ffs_handle **new_ffs, bool mark_ecc) { int rc; uint32_t index, offset, max_size; if (!ffs || !new_ffs) return FLASH_ERR_PARM_ERROR; *new_ffs = NULL; rc = ffs_lookup_part(ffs, "OTHER_SIDE", &index); if (rc) return rc; rc = ffs_part_info(ffs, index, NULL, &offset, &max_size, NULL, NULL); if (rc) return rc; return ffs_init(offset, max_size, ffs->bl, new_ffs, mark_ecc); }
/*! initialize thread structures and create idle thread */ void kthreads_init () { extern kprog_t prog; int prio; list_init ( &all_threads ); active_thread = NULL; ksched_init (); /* initially create 'idle thread' */ kernel_proc.prog = NULL; kernel_proc.stack_pool = NULL; /* use kernel pool */ kernel_proc.m.start = NULL; kernel_proc.m.size = (size_t) 0xffffffff; (void) kthread_create ( idle_thread, NULL, 0, SCHED_FIFO, 0, NULL, NULL, 0, &kernel_proc ); /* user_proc */ user_proc.prog = &prog; user_proc.m.size = prog.m->size; user_proc.m.start = user_proc.pi = prog.pi; /* initialize memory pool for threads stacks */ user_proc.stack_pool = ffs_init ( U2K_GET_ADR ( user_proc.pi->stack, &user_proc ), (size_t) prog.pi->end_adr - (size_t) prog.pi->stack + 1 ); prio = prog.pi->prio; if ( !prio ) prio = THREAD_DEF_PRIO; kthread_create ( user_proc.pi->init, NULL, 0, SCHED_FIFO, prio, NULL, NULL, 0, &user_proc ); kthreads_schedule (); }
/* * Memory based filesystem initialization. */ int mfs_init(struct vfsconf *vfsp) { return (ffs_init(vfsp)); }
/* * 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; }
static struct dt_node *flash_add_dt_node(struct flash *flash, int id) { int i; int rc; const char *name; bool ecc; struct ffs_handle *ffs; int ffs_part_num, ffs_part_start, ffs_part_size; struct dt_node *flash_node; struct dt_node *partition_container_node; struct dt_node *partition_node; flash_node = dt_new_addr(opal_node, "flash", id); dt_add_property_strings(flash_node, "compatible", "ibm,opal-flash"); dt_add_property_cells(flash_node, "ibm,opal-id", id); dt_add_property_u64(flash_node, "reg", flash->size); dt_add_property_cells(flash_node, "ibm,flash-block-size", flash->block_size); if (flash->no_erase) dt_add_property(flash_node, "no-erase", NULL, 0); /* we fix to 32-bits */ dt_add_property_cells(flash_node, "#address-cells", 1); dt_add_property_cells(flash_node, "#size-cells", 1); /* Add partition container node */ partition_container_node = dt_new(flash_node, "partitions"); dt_add_property_strings(partition_container_node, "compatible", "fixed-partitions"); /* we fix to 32-bits */ dt_add_property_cells(partition_container_node, "#address-cells", 1); dt_add_property_cells(partition_container_node, "#size-cells", 1); /* Add partitions */ for (i = 0, name = NULL; i < ARRAY_SIZE(part_name_map); i++) { name = part_name_map[i].name; rc = ffs_init(0, flash->size, flash->bl, &ffs, 1); if (rc) { prerror("FLASH: Can't open ffs handle\n"); continue; } 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); continue; } 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); continue; } partition_node = dt_new_addr(partition_container_node, "partition", ffs_part_start); dt_add_property_strings(partition_node, "label", name); dt_add_property_cells(partition_node, "reg", ffs_part_start, ffs_part_size); if (part_name_map[i].id != RESOURCE_ID_KERNEL_FW) { /* Mark all partitions other than the full PNOR and the boot kernel * firmware as read only. These two partitions are the only partitions * that are properly erase block aligned at this time. */ dt_add_property(partition_node, "read-only", NULL, 0); } } partition_node = dt_new_addr(partition_container_node, "partition", 0); dt_add_property_strings(partition_node, "label", "PNOR"); dt_add_property_cells(partition_node, "reg", 0, flash->size); return flash_node; }
/*! * Start program defined by 'prog' (loaded as module) as new process: * - initialize environment (stack area for threads, stdin, stdout) and start * it's first thread * \param prog_name Program name (as given with module) * \param param Command line arguments for starting thread (if not NULL) * \param prio Priority for starting thread * \return Pointer to descriptor of created process */ kthread_t *k_proc_start ( char *prog_name, void *param, int prio ) { extern kdevice_t *u_stdin, *u_stdout; extern list_t progs; kprog_t *prog; kprocess_t *proc; kthread_t *kthr; char **args = NULL, *arg, *karg, **kargs; size_t argsize; int i; prog = list_get ( &progs, FIRST ); while ( prog && strcmp ( prog->prog_name, prog_name ) ) prog = list_get_next ( &prog->all ); if ( !prog ) return NULL; if ( prog->started ) return NULL; /* create new process */ proc = kmalloc ( sizeof ( kprocess_t) ); ASSERT ( proc ); proc->prog = prog; proc->m.size = prog->m.size; proc->m.start = proc->pi = prog->pi; proc->pi->stdin = u_stdin; proc->pi->stdout = u_stdout; /* initialize memory pool for threads stacks */ proc->stack_pool = ffs_init ( U2K_GET_ADR ( proc->pi->stack, proc ), prog->pi->stack_size ); proc->thr_count = 0; if ( !prio ) prio = proc->pi->prio; if ( !prio ) prio = THR_DEFAULT_PRIO; if ( param ) /* have arguments? */ { /* copy command line arguments from kernel space to process; (use process stack space for arguments) */ kargs = param; for ( i = 0; kargs[i]; i++ ) ; argsize = ( (size_t) kargs[i-1] + strlen( kargs[i-1] ) + 1 ) - (size_t) param; if ( argsize > 0 ) { args = ffs_alloc ( proc->stack_pool, argsize ); arg = (void *) args + (i + 1) * sizeof (void *); kargs = param; i = 0; do { karg = kargs[i]; strcpy ( arg, karg ); args[i++] = K2U_GET_ADR ( arg, proc ); arg += strlen ( arg ) + 1; } while ( kargs[i] ); args[i] = NULL; args = K2U_GET_ADR ( args, proc ); } kfree ( param ); } kthr = k_create_thread ( proc->pi->init, args, NULL, prio, NULL, 0, 1, proc ); list_append ( &procs, proc, &proc->all ); prog->started = 1; k_schedule_threads (); return kthr; }