static void hw_eeprom_init_data(device *me) { hw_eeprom_device *eeprom = (hw_eeprom_device*)device_data(me); /* have we any input or output files */ if (device_find_property(me, "input-file") != NULL) eeprom->input_file_name = device_find_string_property(me, "input-file"); if (device_find_property(me, "output-file") != NULL) eeprom->input_file_name = device_find_string_property(me, "output-file"); /* figure out the sectors in the eeprom */ if (eeprom->sectors == NULL) { eeprom->nr_sectors = device_find_integer_property(me, "nr-sectors"); eeprom->sizeof_sector = device_find_integer_property(me, "sector-size"); eeprom->sectors = zalloc(eeprom->nr_sectors); } else memset(eeprom->sectors, 0, eeprom->nr_sectors); /* initialize the eeprom */ if (eeprom->memory == NULL) { eeprom->sizeof_memory = eeprom->sizeof_sector * eeprom->nr_sectors; eeprom->memory = zalloc(eeprom->sizeof_memory); } else memset(eeprom->memory, 0, eeprom->sizeof_memory); if (eeprom->input_file_name != NULL) { int i; FILE *input_file = fopen(eeprom->input_file_name, "r"); if (input_file == NULL) { perror("eeprom"); device_error(me, "Failed to open input file %s\n", eeprom->input_file_name); } for (i = 0; i < eeprom->sizeof_memory; i++) { if (fread(&eeprom->memory[i], 1, 1, input_file) != 1) break; } fclose(input_file); } /* timing */ eeprom->byte_write_delay = device_find_integer_property(me, "byte-write-delay"); eeprom->sector_start_delay = device_find_integer_property(me, "sector-start-delay"); eeprom->erase_delay = device_find_integer_property(me, "erase-delay"); /* misc */ eeprom->manufacture_code = device_find_integer_property(me, "manufacture-code"); eeprom->device_code = device_find_integer_property(me, "device-code"); }
static void hw_sem_init_data(device *me) { hw_sem_device *sem = (hw_sem_device*)device_data(me); const device_unit *d; int status; union semun help; /* initialize the properties of the sem */ if (device_find_property(me, "key") == NULL) error("sem_init_data() required key property is missing\n"); if (device_find_property(me, "value") == NULL) error("sem_init_data() required value property is missing\n"); sem->key = (key_t) device_find_integer_property(me, "key"); DTRACE(sem, ("semaphore key (%d)\n", sem->key) ); sem->initial = (int) device_find_integer_property(me, "value"); DTRACE(sem, ("semaphore initial value (%d)\n", sem->initial) ); d = device_unit_address(me); sem->physical_address = d->cells[ d->nr_cells-1 ]; DTRACE(sem, ("semaphore physical_address=0x%x\n", sem->physical_address)); /* Now to initialize the semaphore */ if ( sem->initial != -1 ) { sem->id = semget(sem->key, 1, IPC_CREAT | 0660); if (sem->id == -1) error("hw_sem_init_data() semget failed\n"); help.val = sem->initial; status = semctl( sem->id, 0, SETVAL, help ); if (status == -1) error("hw_sem_init_data() semctl -- set value failed\n"); } else { sem->id = semget(sem->key, 1, 0660); if (sem->id == -1) error("hw_sem_init_data() semget failed\n"); } sem->count = semctl( sem->id, 0, GETVAL, help ); if (sem->count == -1) error("hw_sem_init_data() semctl -- get value failed\n"); DTRACE(sem, ("semaphore OS value (%d)\n", sem->count) ); }
static int hw_disk_nr_blocks(device_instance *instance, int n_stack_args, unsigned32 stack_args[/*n_stack_args*/], int n_stack_returns, unsigned32 stack_returns[/*n_stack_returns*/]) { device *me = device_instance_device(instance); if ((n_stack_args != 0) || (n_stack_returns != 1)) { device_error(me, "Incorrect number of arguments for block-size method\n"); return -1; } else { unsigned_word nr_blocks; if (device_find_property(me, "#blocks")) nr_blocks = device_find_integer_property(me, "#blocks"); else nr_blocks = -1; DITRACE(disk, ("#blocks - instance=%ld #blocks=%ld\n", (unsigned long)device_instance_to_external(instance), (long int)nr_blocks)); stack_returns[0] = nr_blocks; return 0; } }
static int hw_disk_block_size(device_instance *instance, int n_stack_args, unsigned32 stack_args[/*n_stack_args*/], int n_stack_returns, unsigned32 stack_returns[/*n_stack_returns*/]) { device *me = device_instance_device(instance); if ((n_stack_args != 0) || (n_stack_returns != 1)) { device_error(me, "Incorrect number of arguments for block-size method\n"); return -1; } else { unsigned_cell block_size; if (device_find_property(me, "block-size")) block_size = device_find_integer_property(me, "block-size"); else block_size = 512; DITRACE(disk, ("block-size - instance=%ld block-size=%ld\n", (unsigned long)device_instance_to_external(instance), (long int)block_size)); stack_returns[0] = block_size; return 0; } }
static void hw_disk_init_address(device *me) { hw_disk_device *disk = device_data(me); unsigned_word address; int space; const char *name; /* attach to the parent. Since the bus is logical, attach using just the unit-address (size must be zero) */ device_address_to_attach_address(device_parent(me), device_unit_address(me), &space, &address, me); device_attach_address(device_parent(me), attach_callback, space, address, 0/*size*/, access_read_write_exec, me); /* Tell the world we are a disk. */ device_add_string_property(me, "device_type", "block"); /* get the name of the file specifying the disk image */ disk->name_index = 0; disk->nr_names = device_find_string_array_property(me, "file", disk->name_index, &name); if (!disk->nr_names) device_error(me, "invalid file property"); /* is it a RO device? */ disk->read_only = (strcmp(device_name(me), "disk") != 0 && strcmp(device_name(me), "floppy") != 0 && device_find_property(me, "read-only") == NULL); /* now open it */ open_disk_image(me, disk, name); }
static void hw_ide_init_address(device *me) { hw_ide_device *ide = device_data(me); int controller; int drive; /* zero some things */ for (controller = 0; controller < nr_ide_controllers; controller++) { memset(&ide->controller[controller], 0, sizeof(ide_controller)); for (drive = 0; drive < nr_ide_drives_per_controller; drive++) { ide->controller[controller].drive[drive].nr = drive; } ide->controller[controller].me = me; if (device_find_property(me, "ready-delay") != NULL) ide->controller[controller].ready_delay = device_find_integer_property(me, "ready-delay"); } /* attach this device to its parent */ generic_device_init_address(me); /* determine our own address map */ build_address_decoder(me, &ide->decoder); }
static int hw_disk_max_transfer(device_instance *instance, int n_stack_args, unsigned32 stack_args[/*n_stack_args*/], int n_stack_returns, unsigned32 stack_returns[/*n_stack_returns*/]) { device *me = device_instance_device(instance); if ((n_stack_args != 0) || (n_stack_returns != 1)) { device_error(me, "Incorrect number of arguments for max-transfer method\n"); return -1; } else { unsigned_cell max_transfer; if (device_find_property(me, "max-transfer")) max_transfer = device_find_integer_property(me, "max-transfer"); else max_transfer = 512; DITRACE(disk, ("max-transfer - instance=%ld max-transfer=%ld\n", (unsigned long)device_instance_to_external(instance), (long int)max_transfer)); stack_returns[0] = max_transfer; return 0; } }
tree_find_property(device *root, const char *path_to_property) { name_specifier spec; if (!split_property_specifier(root, path_to_property, &spec)) device_error(root, "Invalid property path %s", path_to_property); root = split_find_device(root, &spec); return device_find_property(root, spec.property); }
static void hw_data_init_data_callback(device *me) { unsigned_word addr = device_find_integer_property(me, "real-address"); const device_property *data = device_find_property(me, "data"); const char *instance_spec = (device_find_property(me, "instance") != NULL ? device_find_string_property(me, "instance") : NULL); device_instance *instance = NULL; if (data == NULL) device_error(me, "missing property <data>\n"); if (instance_spec != NULL) instance = tree_instance(me, instance_spec); switch (data->type) { case integer_property: { unsigned_cell buf = device_find_integer_property(me, "data"); H2T(buf); if (instance == NULL) { if (device_dma_write_buffer(device_parent(me), &buf, 0 /*address-space*/, addr, sizeof(buf), /*nr-bytes*/ 1 /*violate ro*/) != sizeof(buf)) device_error(me, "Problem storing integer 0x%x at 0x%lx\n", (unsigned)buf, (unsigned long)addr); } else { if (device_instance_seek(instance, 0, addr) < 0 || device_instance_write(instance, &buf, sizeof(buf)) != sizeof(buf)) device_error(me, "Problem storing integer 0x%x at 0x%lx of instance %s\n", (unsigned)buf, (unsigned long)addr, instance_spec); } } break; default: device_error(me, "Write of this data is not yet implemented\n"); break; } if (instance != NULL) device_instance_delete(instance); }
static void hw_shm_init_data(device *me) { hw_shm_device *shm = (hw_shm_device*)device_data(me); const device_unit *d; reg_property_spec reg; int i; /* Obtain the Key Value */ if (device_find_property(me, "key") == NULL) error("shm_init_data() required key property is missing\n"); shm->key = (key_t) device_find_integer_property(me, "key"); DTRACE(shm, ("shm key (0x%08x)\n", shm->key) ); /* Figure out where this memory is in address space and how long it is */ if ( !device_find_reg_array_property(me, "reg", 0, ®) ) error("hw_shm_init_data() no address registered\n"); /* Determine the address and length being as paranoid as possible */ shm->physical_address = 0xffffffff; shm->sizeof_memory = 0xffffffff; for ( i=0 ; i<reg.address.nr_cells; i++ ) { if (reg.address.cells[0] == 0 && reg.size.cells[0] == 0) continue; if ( shm->physical_address != 0xffffffff ) device_error(me, "Only single celled address ranges supported\n"); shm->physical_address = reg.address.cells[i]; DTRACE(shm, ("shm physical_address=0x%x\n", shm->physical_address)); shm->sizeof_memory = reg.size.cells[i]; DTRACE(shm, ("shm length=0x%x\n", shm->sizeof_memory)); } if ( shm->physical_address == 0xffffffff ) device_error(me, "Address not specified\n" ); if ( shm->sizeof_memory == 0xffffffff ) device_error(me, "Length not specified\n" ); /* Now actually attach to or create the shared memory area */ shm->id = shmget(shm->key, shm->sizeof_memory, IPC_CREAT | 0660); if (shm->id == -1) error("hw_shm_init_data() shmget failed\n"); shm->shm_address = shmat(shm->id, (char *)0, SHM_RND); if (shm->shm_address == (void *)-1) error("hw_shm_init_data() shmat failed\n"); }
static void hw_nvram_init_address(device *me) { hw_nvram_device *nvram = (hw_nvram_device*)device_data(me); /* use the generic init code to attach this device to its parent bus */ generic_device_init_address(me); /* find the first non zero reg property and use that as the device size */ if (nvram->sizeof_memory == 0) { reg_property_spec reg; int reg_nr; for (reg_nr = 0; device_find_reg_array_property(me, "reg", reg_nr, ®); reg_nr++) { unsigned attach_size; if (device_size_to_attach_size(device_parent(me), ®.size, &attach_size, me)) { nvram->sizeof_memory = attach_size; break; } } if (nvram->sizeof_memory == 0) device_error(me, "reg property must contain a non-zero phys-addr:size tupple"); if (nvram->sizeof_memory < 8) device_error(me, "NVRAM must be at least 8 bytes in size"); } /* initialize the hw_nvram */ if (nvram->memory == NULL) { nvram->memory = zalloc(nvram->sizeof_memory); } else memset(nvram->memory, 0, nvram->sizeof_memory); if (device_find_property(me, "timezone") == NULL) nvram->timezone = 0; else nvram->timezone = device_find_integer_property(me, "timezone"); nvram->addr_year = nvram->sizeof_memory - 1; nvram->addr_month = nvram->sizeof_memory - 2; nvram->addr_date = nvram->sizeof_memory - 3; nvram->addr_day = nvram->sizeof_memory - 4; nvram->addr_hour = nvram->sizeof_memory - 5; nvram->addr_minutes = nvram->sizeof_memory - 6; nvram->addr_seconds = nvram->sizeof_memory - 7; nvram->addr_control = nvram->sizeof_memory - 8; }
static void hw_ide_attach_address(device *me, attach_type type, int space, unsigned_word addr, unsigned nr_bytes, access_type access, device *client) /*callback/default*/ { hw_ide_device *ide = (hw_ide_device*)device_data(me); int controller_nr = addr / nr_ide_drives_per_controller; int drive_nr = addr % nr_ide_drives_per_controller; ide_controller *controller; ide_drive *drive; if (controller_nr >= nr_ide_controllers) device_error(me, "no controller for disk %s", device_path(client)); controller = &ide->controller[controller_nr]; drive = &controller->drive[drive_nr]; drive->device = client; if (device_find_property(client, "ide-byte-count") != NULL) drive->geometry.byte = device_find_integer_property(client, "ide-byte-count"); else drive->geometry.byte = 512; if (device_find_property(client, "ide-sector-count") != NULL) drive->geometry.sector = device_find_integer_property(client, "ide-sector-count"); if (device_find_property(client, "ide-head-count") != NULL) drive->geometry.head = device_find_integer_property(client, "ide-head-count"); drive->default_geometry = drive->geometry; DTRACE(ide, ("controller %d:%d %s byte-count %d, sector-count %d, head-count %d\n", controller_nr, drive->nr, device_path(client), drive->geometry.byte, drive->geometry.sector, drive->geometry.head)); }
INLINE_EMUL_GENERIC void emul_add_tree_options(device *tree, bfd *image, const char *emul, const char *env, int oea_interrupt_prefix) { int little_endian = 0; /* sort out little endian */ if (device_find_property(tree, "/options/little-endian?")) little_endian = device_find_boolean_property(tree, "/options/little-endian?"); else { #ifdef bfd_little_endian /* new bfd */ little_endian = (image != NULL && bfd_little_endian(image)); #else little_endian = (image != NULL && !image->xvec->byteorder_big_p); #endif device_tree_add_parsed(tree, "/options/little-endian? %s", little_endian ? "true" : "false"); } /* misc other stuff */ device_tree_add_parsed(tree, "/openprom/options/oea-memory-size 0x%x", OEA_MEMORY_SIZE); device_tree_add_parsed(tree, "/openprom/options/oea-interrupt-prefix %d", oea_interrupt_prefix); device_tree_add_parsed(tree, "/openprom/options/smp 1"); device_tree_add_parsed(tree, "/openprom/options/env %s", env); device_tree_add_parsed(tree, "/openprom/options/os-emul %s", emul); device_tree_add_parsed(tree, "/openprom/options/strict-alignment? %s", ((WITH_ALIGNMENT == 0 && little_endian) || (WITH_ALIGNMENT == STRICT_ALIGNMENT)) ? "true" : "false"); device_tree_add_parsed(tree, "/openprom/options/floating-point? %s", WITH_FLOATING_POINT ? "true" : "false"); device_tree_add_parsed(tree, "/openprom/options/use-stdio? %s", WITH_STDIO == DO_USE_STDIO ? "true" : "false"); device_tree_add_parsed(tree, "/openprom/options/model \"%s", model_name[WITH_DEFAULT_MODEL]); device_tree_add_parsed(tree, "/openprom/options/model-issue %d", MODEL_ISSUE_IGNORE); /* useful options */ /* FIXME - need to check the OpenBoot powerpc bindings to see if this is still used and if so what it should be */ device_tree_add_parsed(tree, "/options/load-base 0x80000"); }
static void hw_com_device_init_data(device *me) { hw_com_device *com = (hw_com_device*)device_data(me); /* clean up */ if (com->output.file != NULL) fclose(com->output.file); if (com->input.file != NULL) fclose(com->input.file); memset(com, 0, sizeof(hw_com_device)); /* the fifo speed */ com->output.delay = (device_find_property(me, "output-delay") != NULL ? device_find_integer_property(me, "output-delay") : 0); com->input.delay = (device_find_property(me, "input-delay") != NULL ? device_find_integer_property(me, "input-delay") : 0); /* the data source/sink */ if (device_find_property(me, "input-file") != NULL) { const char *input_file = device_find_string_property(me, "input-file"); com->input.file = fopen(input_file, "r"); if (com->input.file == NULL) device_error(me, "Problem opening input file %s\n", input_file); if (device_find_property(me, "input-buffering") != NULL) { const char *buffering = device_find_string_property(me, "input-buffering"); if (strcmp(buffering, "unbuffered") == 0) setbuf(com->input.file, NULL); } } if (device_find_property(me, "output-file") != NULL) { const char *output_file = device_find_string_property(me, "output-file"); com->output.file = fopen(output_file, "w"); if (com->output.file == NULL) device_error(me, "Problem opening output file %s\n", output_file); if (device_find_property(me, "output-buffering") != NULL) { const char *buffering = device_find_string_property(me, "output-buffering"); if (strcmp(buffering, "unbuffered") == 0) setbuf(com->output.file, NULL); } } /* ready from the start */ com->input.ready = 1; com->modem.carrier = 1; com->output.ready = 1; }
static void update_for_binary_section(bfd *abfd, asection *the_section, PTR obj) { unsigned_word section_vma; unsigned_word section_size; access_type access; device *me = (device*)obj; /* skip the section if no memory to allocate */ if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC)) return; /* check/ignore any sections of size zero */ section_size = bfd_get_section_size_before_reloc(the_section); if (section_size == 0) return; /* find where it is to go */ section_vma = bfd_get_section_vma(abfd, the_section); DTRACE(binary, ("name=%-7s, vma=0x%.8lx, size=%6ld, flags=%3lx(%s%s%s%s%s )\n", bfd_get_section_name(abfd, the_section), (long)section_vma, (long)section_size, (long)bfd_get_section_flags(abfd, the_section), bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "", bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "", bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "", bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "", bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : "" )); /* If there is an .interp section, it means it needs a shared library interpreter. */ if (strcmp(".interp", bfd_get_section_name(abfd, the_section)) == 0) error("Shared libraries are not yet supported.\n"); /* determine the devices access */ access = access_read; if (bfd_get_section_flags(abfd, the_section) & SEC_CODE) access |= access_exec; if (!(bfd_get_section_flags(abfd, the_section) & SEC_READONLY)) access |= access_write; /* if claim specified, allocate region from the memory device */ if (device_find_property(me, "claim") != NULL) { device_instance *memory = tree_find_ihandle_property(me, "/chosen/memory"); unsigned_cell mem_in[3]; unsigned_cell mem_out[1]; mem_in[0] = 0; /*alignment - top-of-stack*/ mem_in[1] = section_size; mem_in[2] = section_vma; if (device_instance_call_method(memory, "claim", 3, mem_in, 1, mem_out) < 0) device_error(me, "failed to claim memory for section at 0x%lx (0x%lx", section_vma, section_size); if (mem_out[0] != section_vma) device_error(me, "section address not as requested"); } /* if a map, pass up a request to create the memory in core */ if (strncmp(device_name(me), "map-binary", strlen("map-binary")) == 0) device_attach_address(device_parent(me), attach_raw_memory, 0 /*address space*/, section_vma, section_size, access, me); /* if a load dma in the required data */ if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) { void *section_init = zalloc(section_size); if (!bfd_get_section_contents(abfd, the_section, section_init, 0, section_size)) { bfd_perror("binary"); device_error(me, "load of data failed"); return; } if (device_dma_write_buffer(device_parent(me), section_init, 0 /*space*/, section_vma, section_size, 1 /*violate_read_only*/) != section_size) device_error(me, "broken transfer\n"); zfree(section_init); /* only free if load */ } }
split_device_specifier(device *current, const char *device_specifier, name_specifier *spec) { char *chp = NULL; /* expand any leading alias if present */ if (current != NULL && *device_specifier != '\0' && *device_specifier != '.' && *device_specifier != '/') { device *aliases = tree_find_device(current, "/aliases"); char alias[32]; int len = 0; while (device_specifier[len] != '\0' && device_specifier[len] != '/' && device_specifier[len] != ':' && !isspace(device_specifier[len])) { alias[len] = device_specifier[len]; len++; if (len >= sizeof(alias)) error("split_device_specifier: buffer overflow"); } alias[len] = '\0'; if (aliases != NULL && device_find_property(aliases, alias)) { strcpy(spec->buf, device_find_string_property(aliases, alias)); strcat(spec->buf, device_specifier + len); } else { strcpy(spec->buf, device_specifier); } } else { strcpy(spec->buf, device_specifier); } /* check no overflow */ if (strlen(spec->buf) >= sizeof(spec->buf)) error("split_device_specifier: buffer overflow\n"); /* strip leading spaces */ chp = spec->buf; while (*chp != '\0' && isspace(*chp)) chp++; if (*chp == '\0') return 0; /* find the path and terminate it with null */ spec->path = chp; while (*chp != '\0' && !isspace(*chp)) chp++; if (*chp != '\0') { *chp = '\0'; chp++; } /* and any value */ while (*chp != '\0' && isspace(*chp)) chp++; spec->value = chp; /* now go back and chop the property off of the path */ if (spec->value[0] == '\0') { spec->property = NULL; /*not a property*/ spec->value = NULL; } else if (spec->value[0] == '>' || spec->value[0] == '<') { /* an interrupt spec */ spec->property = NULL; } else { chp = strrchr(spec->path, '/'); if (chp == NULL) { spec->property = spec->path; spec->path = strchr(spec->property, '\0'); } else { *chp = '\0'; spec->property = chp+1; } } /* and mark the rest as invalid */ spec->name = NULL; spec->base = NULL; spec->unit = NULL; spec->args = NULL; spec->last_name = NULL; spec->last_base = NULL; spec->last_unit = NULL; spec->last_args = NULL; return 1; }
print_properties(device *me) { const device_property *property; for (property = device_find_property(me, NULL); property != NULL; property = device_next_property(property)) { printf_filtered("%s/%s", device_path(me), property->name); if (property->original != NULL) { printf_filtered(" !"); printf_filtered("%s/%s", device_path(property->original->owner), property->original->name); } else { switch (property->type) { case array_property: if ((property->sizeof_array % sizeof(signed_cell)) == 0) { unsigned_cell *w = (unsigned_cell*)property->array; int cell_nr; for (cell_nr = 0; cell_nr < (property->sizeof_array / sizeof(unsigned_cell)); cell_nr++) { printf_filtered(" 0x%lx", (unsigned long)BE2H_cell(w[cell_nr])); } } else { unsigned8 *w = (unsigned8*)property->array; printf_filtered(" ["); while ((char*)w - (char*)property->array < property->sizeof_array) { printf_filtered(" 0x%2x", BE2H_1(*w)); w++; } } break; case boolean_property: { int b = device_find_boolean_property(me, property->name); printf_filtered(" %s", b ? "true" : "false"); } break; case ihandle_property: { if (property->array != NULL) { device_instance *instance = device_find_ihandle_property(me, property->name); printf_filtered(" *%s", device_instance_path(instance)); } else { /* not yet initialized, ask the device for the path */ ihandle_runtime_property_spec spec; device_find_ihandle_runtime_property(me, property->name, &spec); printf_filtered(" *%s", spec.full_path); } } break; case integer_property: { unsigned_word w = device_find_integer_property(me, property->name); printf_filtered(" 0x%lx", (unsigned long)w); } break; case range_array_property: print_ranges_property(me, property); break; case reg_array_property: print_reg_property(me, property); break; case string_property: { const char *s = device_find_string_property(me, property->name); print_string(s); } break; case string_array_property: print_string_array_property(me, property); break; } } printf_filtered("\n"); } }