#ifndef _HW_INIT_C_
#define _HW_INIT_C_
#include "device_table.h"
#include "bfd.h"
#include "psim.h"
static int
dma_file(device *me,
const char *file_name,
unsigned_word addr)
{
int count;
int inc;
FILE *image;
char buf[1024];
image = fopen(file_name, "r");
if (image == NULL)
return -1;
count = 0;
while (1) {
inc = fread(buf, 1, sizeof(buf), image);
if (inc <= 0)
break;
if (device_dma_write_buffer(device_parent(me),
buf,
0 ,
addr+count,
inc ,
1 ) != inc) {
fclose(image);
return -1;
}
count += inc;
}
fclose(image);
return count;
}
static void
hw_file_init_data_callback(device *me)
{
int count;
const char *file_name = device_find_string_property(me, "file-name");
unsigned_word addr = device_find_integer_property(me, "real-address");
count = dma_file(me, file_name, addr);
if (count < 0)
device_error(me, "Problem loading file %s\n", file_name);
}
static device_callbacks const hw_file_callbacks = {
{ NULL, hw_file_init_data_callback, },
{ NULL, },
{ NULL, },
{ NULL, },
{ NULL, },
{ NULL, },
};
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 ,
addr,
sizeof(buf),
1 ) != 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 device_callbacks const hw_data_callbacks = {
{ NULL, hw_data_init_data_callback, },
{ NULL, },
{ NULL, },
{ NULL, },
{ NULL, },
{ NULL, },
};
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;
if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
return;
section_size = bfd_get_section_size_before_reloc(the_section);
if (section_size == 0)
return;
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 (strcmp(".interp", bfd_get_section_name(abfd, the_section)) == 0)
error("Shared libraries are not yet supported.\n");
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 (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;
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 (strncmp(device_name(me), "map-binary", strlen("map-binary")) == 0)
device_attach_address(device_parent(me),
attach_raw_memory,
0 ,
section_vma,
section_size,
access,
me);
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 ,
section_vma,
section_size,
1 )
!= section_size)
device_error(me, "broken transfer\n");
zfree(section_init);
}
}
static void
hw_binary_init_data_callback(device *me)
{
const char *file_name = device_find_string_property(me, "file-name");
bfd *image;
image = bfd_openr(file_name, NULL);
if (image == NULL) {
bfd_perror("binary");
device_error(me, "Failed to open file %s\n", file_name);
}
if (!bfd_check_format(image, bfd_object)) {
bfd_close(image);
device_error(me, "The file %s has an invalid binary format\n", file_name);
}
bfd_map_over_sections(image,
update_for_binary_section,
(PTR)me);
bfd_close(image);
}
static device_callbacks const hw_binary_callbacks = {
{ NULL, hw_binary_init_data_callback, },
{ NULL, },
{ NULL, },
{ NULL, },
{ NULL, },
{ NULL, },
};
static int
sizeof_argument_strings(char **arg)
{
int sizeof_strings = 0;
if (arg == NULL)
return 0;
for (; *arg != NULL; arg++) {
int len = strlen(*arg) + 1;
sizeof_strings += ALIGN_8(len);
}
return sizeof_strings;
}
static int
number_of_arguments(char **arg)
{
int nr;
if (arg == NULL)
return 0;
for (nr = 0; *arg != NULL; arg++, nr++);
return nr;
}
static int
sizeof_arguments(char **arg)
{
return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
}
static void
write_stack_arguments(device *me,
char **arg,
unsigned_word start_block,
unsigned_word end_block,
unsigned_word start_arg,
unsigned_word end_arg)
{
DTRACE(stack,
("write_stack_arguments(device=%s, arg=0x%lx, start_block=0x%lx, end_block=0x%lx, start_arg=0x%lx, end_arg=0x%lx)\n",
device_name(me), (long)arg, (long)start_block, (long)end_block, (long)start_arg, (long)end_arg));
if (arg == NULL)
device_error(me, "Attempt to write a null array onto the stack\n");
for (; *arg != NULL; arg++) {
int len = strlen(*arg)+1;
unsigned_word target_start_block;
DTRACE(stack,
("write_stack_arguments() write %s=%s at %s=0x%lx %s=0x%lx %s=0x%lx\n",
"**arg", *arg, "start_block", (long)start_block,
"len", (long)len, "start_arg", (long)start_arg));
if (psim_write_memory(device_system(me), 0, *arg,
start_block, len,
0) != len)
device_error(me, "Write of **arg (%s) at 0x%lx of stack failed\n",
*arg, (unsigned long)start_block);
target_start_block = H2T_word(start_block);
if (psim_write_memory(device_system(me), 0, &target_start_block,
start_arg, sizeof(target_start_block),
0) != sizeof(target_start_block))
device_error(me, "Write of *arg onto stack failed\n");
start_block += ALIGN_8(len);
start_arg += sizeof(start_block);
}
start_arg += sizeof(start_block);
if (start_block != end_block
|| ALIGN_8(start_arg) != end_arg)
device_error(me, "Probable corrpution of stack arguments\n");
DTRACE(stack, ("write_stack_arguments() = void\n"));
}
static void
create_ppc_elf_stack_frame(device *me,
unsigned_word bottom_of_stack,
char **argv,
char **envp)
{
const unsigned sizeof_envp_block = sizeof_argument_strings(envp);
const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block;
const unsigned sizeof_argv_block = sizeof_argument_strings(argv);
const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block;
const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word);
const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry);
const unsigned sizeof_envp = sizeof_arguments(envp);
const unsigned_word start_envp = start_aux - sizeof_envp;
const int argc = number_of_arguments(argv);
const unsigned sizeof_argv = sizeof_arguments(argv);
const unsigned_word start_argv = start_envp - sizeof_argv;
const unsigned_word top_of_stack = ((start_argv
- 2 * sizeof(unsigned_word))
& ~0xf);
write_stack_arguments(me, envp,
start_envp_block, bottom_of_stack,
start_envp, start_aux);
write_stack_arguments(me, argv,
start_argv_block, start_envp_block,
start_argv, start_envp);
psim_write_register(device_system(me), -1,
&top_of_stack, "sp", cooked_transfer);
psim_write_register(device_system(me), -1,
&argc, "r3", cooked_transfer);
psim_write_register(device_system(me), -1,
&start_argv, "r4", cooked_transfer);
psim_write_register(device_system(me), -1,
&start_envp, "r5", cooked_transfer);
psim_write_register(device_system(me), -1,
&start_aux, "r6", cooked_transfer);
}
static void
create_ppc_aix_stack_frame(device *me,
unsigned_word bottom_of_stack,
char **argv,
char **envp)
{
unsigned_word core_envp;
unsigned_word core_argv;
unsigned_word core_argc;
unsigned_word core_aux;
unsigned_word top_of_stack;
create_ppc_elf_stack_frame(me, bottom_of_stack, argv, envp);
psim_read_register(device_system(me), 0,
&top_of_stack, "r1", cooked_transfer);
psim_read_register(device_system(me), 0,
&core_argc, "r3", cooked_transfer);
psim_read_register(device_system(me), 0,
&core_argv, "r4", cooked_transfer);
psim_read_register(device_system(me), 0,
&core_envp, "r5", cooked_transfer);
psim_read_register(device_system(me), 0,
&core_aux, "r6", cooked_transfer);
device_error(me, "Unfinished procedure create_ppc_aix_stack_frame\n");
}
static void
create_ppc_chirp_bootargs(device *me,
char **argv)
{
char args[1024];
char **chp = argv + 1;
args[0] = '\0';
while (*chp != NULL) {
if (strlen(args) > 0)
strcat(args, " ");
if (strlen(args) + strlen(*chp) >= sizeof(args))
device_error(me, "buffer overflow");
strcat(args, *chp);
chp++;
}
tree_parse(me, "/chosen/bootargs \"%s", args);
}
static int
hw_stack_ioctl(device *me,
cpu *processor,
unsigned_word cia,
device_ioctl_request request,
va_list ap)
{
switch (request) {
case device_ioctl_create_stack:
{
unsigned_word stack_pointer = va_arg(ap, unsigned_word);
char **argv = va_arg(ap, char **);
char **envp = va_arg(ap, char **);
const char *stack_type;
DTRACE(stack,
("stack_ioctl_callback(me=0x%lx:%s processor=0x%lx cia=0x%lx argv=0x%lx envp=0x%lx)\n",
(long)me, device_name(me),
(long)processor,
(long)cia,
(long)argv,
(long)envp));
stack_type = device_find_string_property(me, "stack-type");
if (strcmp(stack_type, "ppc-elf") == 0)
create_ppc_elf_stack_frame(me, stack_pointer, argv, envp);
else if (strcmp(stack_type, "ppc-xcoff") == 0)
create_ppc_aix_stack_frame(me, stack_pointer, argv, envp);
else if (strcmp(stack_type, "chirp") == 0)
create_ppc_chirp_bootargs(me, argv);
else if (strcmp(stack_type, "none") != 0)
device_error(me, "Unknown initial stack frame type %s", stack_type);
DTRACE(stack,
("stack_ioctl_callback() = void\n"));
break;
}
default:
device_error(me, "Unsupported ioctl requested");
break;
}
return 0;
}
static device_callbacks const hw_stack_callbacks = {
{ NULL, },
{ NULL, },
{ NULL, },
{ NULL, },
{ NULL, },
{ NULL, },
NULL,
hw_stack_ioctl,
};
const device_descriptor hw_init_device_descriptor[] = {
{ "file", NULL, &hw_file_callbacks },
{ "data", NULL, &hw_data_callbacks },
{ "load-binary", NULL, &hw_binary_callbacks },
{ "map-binary", NULL, &hw_binary_callbacks },
{ "stack", NULL, &hw_stack_callbacks },
{ NULL },
};
#endif _HW_INIT_C_