📄 emul_chirp.c
字号:
/* check the size */ if (head.descsz == sizeof(note->desc) - sizeof(signed32)) { sim_io_printf_filtered("chirp: note descriptor missing load-base\n"); } else if (head.descsz != sizeof(note->desc)) { sim_io_printf_filtered("chirp: note descriptor of wrong size\n"); note->found = note_found; return; } note->found = note_correct; /* get the contents */ if (!bfd_get_section_contents(image, sect, ¬e->desc, /* page align start */ ((sizeof(head) + head.namesz) + 3) & ~3, head.descsz)) { error("chirp: note descriptor unreadable\n"); } note->desc.real_mode = bfd_get_32(image, (void*)¬e->desc.real_mode); note->desc.real_base = bfd_get_32(image, (void*)¬e->desc.real_base); note->desc.real_size = bfd_get_32(image, (void*)¬e->desc.real_size); note->desc.virt_base = bfd_get_32(image, (void*)¬e->desc.virt_base); note->desc.virt_size = bfd_get_32(image, (void*)¬e->desc.virt_size); if (head.descsz == sizeof(note->desc)) note->desc.load_base = bfd_get_32(image, (void*)¬e->desc.load_base); else note->desc.load_base = (signed32)-1; }}static os_emul_data *emul_chirp_create(device *root, bfd *image, const char *name){ os_emul_data *chirp; device *node; chirp_note note; int i; /* Sanity check that this really is the chosen emulation */ if (name == NULL && image == NULL) return NULL; if (name != NULL && strcmp(name, "ob") != 0 && strcmp(name, "ieee1274") != 0 && strcmp(name, "chrp") != 0 && strcmp(name, "chirp") != 0 && strcmp(name, "openboot") != 0) return NULL; /* look for an elf note section, enter its values into the device tree */ memset(¬e, 0, sizeof(note)); if (image != NULL) bfd_map_over_sections(image, map_over_chirp_note, ¬e); if (name == NULL && image != NULL && note.found == note_missing) return NULL; /* Assume that it is a chirp emulation */ chirp = ZALLOC(os_emul_data); chirp->root = root; chirp->services = services; /* the root node */ tree_parse(root, "/name \"gpl,clayton"); /* default options */ emul_add_tree_options(root, image, "chirp", "oea", 0 /*oea-interrupt-prefix*/); /* hardware */ emul_add_tree_hardware(root); /* basic information */ chirp->memory_size = tree_find_integer_property(root, "/openprom/options/oea-memory-size"); chirp->little_endian = tree_find_boolean_property(root, "/options/little-endian?"); chirp->floating_point_available = tree_find_boolean_property(root, "/openprom/options/floating-point?"); chirp->interrupt_prefix = tree_find_integer_property(root, "/openprom/options/oea-interrupt-prefix"); /* Perform an interum layout of the openboot firmware in memory */ /* a page for firmware calls */ chirp->sizeof_code = 4096; chirp->code_offset = 0x4000; /* possible space for interrupt table */ /* the stack */ chirp->sizeof_stack = 32 * 1024; chirp->stack_offset = chirp->code_offset + chirp->sizeof_code; /* the hash table */ if (!note.desc.real_mode) { chirp->nr_page_table_entry_groups = (chirp->memory_size < 0x800000 ? 1024 /* min allowed */ : (chirp->memory_size / 4096 / 2)); chirp->sizeof_htab = chirp->nr_page_table_entry_groups * 64; } chirp->htab_offset = chirp->stack_offset + chirp->sizeof_stack; /* the actual amount of space needed */ chirp->real_size = chirp->htab_offset + chirp->sizeof_htab; /* now go through and see if it fits in what is available */ /* resolve real-mode? */ if (note.found == note_correct) chirp->real_mode = note.desc.real_mode; else if (tree_find_property(root, "/options/real-mode?") != NULL) chirp->real_mode = tree_find_boolean_property(root, "/options/real-mode?"); else chirp->real_mode = 0; if (tree_find_property(root, "/options/real-mode?") != NULL) { if (!chirp->real_mode != !tree_find_boolean_property(root, "/options/real-mode?")) error("chirp: /options/real-mode? conflicts with note section\n"); } else tree_parse(root, "/options/real-mode? %s", chirp->real_mode ? "true" : "false"); /* resolve real-base */ if (note.found == note_correct && note.desc.real_base != (signed32)-1) chirp->real_base = note.desc.real_base; else if (tree_find_property(root, "/options/real-base") != NULL) chirp->real_base = tree_find_integer_property(root, "/options/real-base"); else chirp->real_base = chirp->memory_size - chirp->real_size; if (tree_find_property(root, "/options/real-base") != NULL) { if (chirp->real_base != tree_find_integer_property(root, "/options/real-base")) error("chirp: /options/real-base conflicts with note section\n"); } else tree_parse(root, "/options/real-base 0x%lx", (unsigned long)chirp->real_base); /* resolve real-size */ if (note.found == note_correct && note.desc.real_size != (signed32)-1 && note.desc.real_size != 0 && chirp->real_size > note.desc.real_size) error("chirp: insufficient physical memory for firmware\n"); if (tree_find_property(root, "/options/real-size") != NULL) { if (chirp->real_size > tree_find_integer_property(root, "/options/real-size")) error("chirp: /options/real-size conflicts with note section\n"); } else tree_parse(root, "/options/real-size 0x%lx", (unsigned long)chirp->real_size); /* resolve virt-base */ if (chirp->real_mode) chirp->virt_base = chirp->real_base; else if (note.found == note_correct && note.desc.virt_base != -1) chirp->virt_base = note.desc.virt_base; else if (tree_find_property(root, "/options/virt-base") != NULL) chirp->virt_base = tree_find_integer_property(root, "/options/virt-base"); else chirp->virt_base = CHIRP_START_ADDRESS; if (tree_find_property(root, "/options/virt-base") != NULL) { unsigned_word virt_base = tree_find_integer_property(root, "/options/virt-base"); if (virt_base != -1 && chirp->virt_base != virt_base) error("chirp: /options/virt-base conflicts with note section\n"); } else tree_parse(root, "/options/virt-base 0x%lx", chirp->real_mode ? -1 : (unsigned long)chirp->virt_base); /* resolve virt-size */ chirp->virt_size = chirp->real_size; if (note.found == note_correct && note.desc.virt_size != (signed32)-1 && note.desc.virt_size != 0 && !chirp->real_mode && chirp->virt_size > note.desc.virt_size) error("chirp: insufficent virtual memory for firmware\n"); if (tree_find_property(root, "/options/virt-size") != NULL) { if (chirp->virt_size > tree_find_integer_property(root, "/options/virt-size")) error("chirp: /options/virt-size conflicts with note section\n"); } else tree_parse(root, "/options/virt-size 0x%lx", chirp->real_mode ? -1 : (unsigned long)chirp->virt_size); /* resolve load-base */ if (note.found == note_correct && note.desc.load_base != (signed32)-1) chirp->load_base = note.desc.load_base; else if (tree_find_property(root, "/options/load-base") != NULL) chirp->load_base = tree_find_integer_property(root, "/options/load-base"); else chirp->load_base = CHIRP_LOAD_BASE; if (tree_find_property(root, "/options/load-base") != NULL) { if (chirp->load_base != tree_find_integer_property(root, "/options/load-base")) error("chirp: /options/load-base conflicts with note section\n"); } else tree_parse(root, "/options/load-base 0x%lx", (unsigned long)chirp->load_base); /* now adjust the preliminary firmware addresses to final values */ chirp->code_ra = chirp->code_offset + chirp->real_base; chirp->stack_ra = chirp->stack_offset + chirp->real_base; chirp->htab_ra = chirp->htab_offset + chirp->real_base; /* the virtual addresses. In real mode these are real addresses. */ chirp->code_va = chirp->code_offset + chirp->virt_base; chirp->stack_va = chirp->stack_offset + chirp->virt_base; chirp->htab_va = chirp->htab_offset + chirp->virt_base; chirp->code_client_va = chirp->code_va; chirp->code_client_ra = chirp->code_ra; chirp->code_callback_va = chirp->code_client_va + 16; chirp->code_callback_ra = chirp->code_client_ra + 16; chirp->code_loop_va = chirp->code_callback_va + 16; chirp->code_loop_ra = chirp->code_callback_ra + 16; /* initialization */ tree_parse(root, "/openprom/init"); tree_parse(root, "/openprom/init/register"); tree_parse(root, "/openprom/init/register/0.pc 0x%lx", (unsigned long)bfd_get_start_address(image)); tree_parse(root, "/openprom/init/register/pc 0x%lx", (unsigned long)chirp->code_loop_va); tree_parse(root, "/openprom/init/register/msr 0x%x", (msr_machine_check_enable | (chirp->real_mode ? 0 : (msr_instruction_relocate | msr_data_relocate)) | (chirp->little_endian ? (msr_little_endian_mode | msr_interrupt_little_endian_mode) : 0) | (chirp->floating_point_available ? msr_floating_point_available : 0) | (chirp->interrupt_prefix ? msr_interrupt_prefix : 0) )); tree_parse(root, "/openprom/init/register/sdr1 0x%lx", (unsigned long)(chirp->htab_ra | MASK32(16, 22) | ((chirp->sizeof_htab - 1) >> 16))); /* make certain that the segment registers map straight through */ for (i = 0; i < 16; i++) { tree_parse(root, "/openprom/init/register/sr%d 0x%lx", i, (unsigned long)i); } /* establish an initial state for all processors */ /* the client interface address */ tree_parse(root, "/openprom/init/register/r5 0x%lx", (unsigned long)chirp->code_client_va); /* a stack */ tree_parse(root, "/openprom/init/register/sp 0x%lx", (unsigned long)(chirp->stack_va + chirp->sizeof_stack - 16)); /* in chrp mode any arguments end up being concatinated */ tree_parse(root, "/openprom/init/stack/stack-type chirp"); /* client interface - emul-call followed by return instruction */ node = tree_parse(root, "/openprom/init/data@0x%lx", (unsigned long)chirp->code_client_ra); tree_parse(node, "./psim,description \"client-interface instruction"); tree_parse(node, "./real-address 0x%lx", (unsigned long)chirp->code_client_ra); tree_parse(node, "./data 0x%lx", (unsigned long)emul_call_instruction); node = tree_parse(root, "/openprom/init/data@0x%lx", (unsigned long)(chirp->code_client_ra + 4)); tree_parse(node, "./psim,description \"client-interface return instruction"); tree_parse(node, "./real-address 0x%lx", (unsigned long)(chirp->code_client_ra + 4)); tree_parse(node, "./data 0x%lx", (unsigned long)emul_blr_instruction); /* return address for client callbacks - an emul-call instruction that is again followed by a return instruction */ node = tree_parse(root, "/openprom/init/data@0x%lx", (unsigned long)chirp->code_callback_ra); tree_parse(node, "./psim,description \"client-callback instruction"); tree_parse(node, "./real-address 0x%lx", (unsigned long)chirp->code_callback_ra); tree_parse(node, "./data 0x%lx", (unsigned long)emul_call_instruction); node = tree_parse(root, "/openprom/init/data@0x%lx", (unsigned long)(chirp->code_callback_ra + 4)); tree_parse(node, "./psim,description \"client-callback return instruction"); tree_parse(node, "./real-address 0x%lx", (unsigned long)(chirp->code_callback_ra + 4)); tree_parse(node, "./data 0x%lx", (unsigned long)emul_blr_instruction); /* loop to keep other processors busy */ node = tree_parse(root, "/openprom/init/data@0x%lx", (unsigned long)chirp->code_loop_ra); tree_parse(node, "./psim,description \"processor busy loop"); tree_parse(node, "./real-address 0x%lx", (unsigned long)chirp->code_loop_ra); tree_parse(node, "./data 0x%lx", (unsigned long)emul_loop_instruction); /* hash table */ /* create a hash table */ if (!chirp->real_mode) { node = tree_parse(root, "/openprom/init/htab@0x%lx", (unsigned long)chirp->htab_ra); tree_parse(node, "./claim 0"); tree_parse(node, "./real-address 0x%lx", (unsigned long)chirp->htab_ra); tree_parse(node, "./nr-bytes 0x%lx", (unsigned long)chirp->sizeof_htab); } /* map in the stack */ if (!chirp->real_mode) { node = tree_parse(root, "/openprom/init/htab/pte@0x%lx", (unsigned long)chirp->stack_ra); tree_parse(node, "./psim,description \"map in the stack"); tree_parse(node, "./claim 1"); tree_parse(node, "./virtual-address 0x%lx", (unsigned long)chirp->stack_va); tree_parse(node, "./real-address 0x%lx", (unsigned long)chirp->stack_ra); tree_parse(node, "./nr-bytes 0x%lx", (unsigned long)chirp->sizeof_stack); tree_parse(node, "./wimg %d", 0x7); tree_parse(node, "./pp %d", 0x2); } /* map in the chrp openboot callback code */ if (!chirp->real_mode) { node = tree_parse(root, "/openprom/init/htab/pte@0x%lx", (unsigned long)chirp->code_ra); tree_parse(node, "./psim,description \"map in chrp openboot callback code"); tree_parse(node, "./claim 1"); tree_parse(node, "./virtual-address 0x%lx", (unsigned long)chirp->code_va); tree_parse(node, "./real-address 0x%lx", (unsigned long)chirp->code_ra); tree_parse(node, "./nr-bytes 0x%lx", (unsigned long)chirp->sizeof_code); tree_parse(node, "./wimg %d", 0x7); tree_parse(node, "./pp %d", 0x2); } /* map in the program to run */ if (chirp->real_mode) { node = tree_parse(node, "/openprom/init/load-binary"); tree_parse(node, "./psim,description \"load the binary"); tree_parse(node, "./file-name %s", bfd_get_filename(image)); tree_parse(node, "./claim 1"); } else { node = tree_parse(root, "/openprom/init/htab/pte@0x%lx", (unsigned long)chirp->load_base); tree_parse(node, "./psim,description \"load & map the binary"); tree_parse(node, "./claim 1"); tree_parse(node, "./file-name \"%s", bfd_get_filename(image)); tree_parse(node, "./wimg %d", 0x7); tree_parse(node, "./pp %d", 0x2); } /* map in the interrupt vectors */ if (!chirp->real_mode) { node = tree_parse(root, "/openprom/init/htab/pte@0x0"); tree_parse(node, "./psim,description \"map in interrupt vectors"); tree_parse(node, "./virtual-address 0x0"); tree_parse(node, "./real-address 0x0"); tree_parse(node, "./nr-bytes 0x3000"); tree_parse(node, "./wimg %d", 0x7); tree_parse(node, "./pp %d", 0x2); } return chirp;}static voidemul_chirp_init(os_emul_data *emul_data, int nr_cpus){ emul_data->state = serving;}static intemul_chirp_instruction_call(cpu *processor, unsigned_word cia, unsigned_word ra, os_emul_data *emul_data){ unsigned_word service_name_addr; unsigned_word result; char service_buf[32]; char *service_name; chirp_services *service; switch (emul_data->state) { case serving: /* we are waiting on an OpenBoot request from the client program via the client interface */ if (cia != emul_data->code_client_va) return 0; emul_data->return_address = LR; emul_data->arguments = cpu_registers(processor)->gpr[3]; /* try to determine what to do */ service_name_addr = emul_read_word(cpu_registers(processor)->gpr[3], processor, cia); service_name = emul_read_string(service_buf, service_name_addr, sizeof(service_buf), processor, cia); emul_data->n_args = emul_read_word(emul_data->arguments + sizeof(unsigned_cell), processor, cia); emul_data->n_returns = emul_read_word(emul_data->arguments + 2 * sizeof(unsigned_cell), processor, cia); /* verify what was passed */ if (service_name_addr == 0 || service_name == NULL) { error("OpenFirmware called with invalid (NULL) service name from 0x%lx with args 0x%lx\n", (unsigned long)emul_data->return_address, (unsigned long)emul_data->arguments); } if (emul_data->n_args > 6) { /* See iee1275 requirements on nr returns */ error("OpenFirmware service %s called from 0x%lx with args 0x%lx, too many args (%d)\n", (unsigned long)emul_data->return_address, (unsigned long)emul_data->arguments, emul_data->n_returns); } if (emul_data->n_returns > 6) { error("OpenFirmware service %s called from 0x%lx with args 0x%lx, with too many returns (%d)\n", (unsigned long)emul_data->return_address, (unsigned long)emul_data->arguments, emul_data->n_args); } /* look it up */ TRACE(trace_os_emul, ("%s called from 0x%lx with args 0x%lx\n", service_name, (unsigned long)emul_data->return_address, (unsigned long)emul_data->arguments)); service = services; while (service->name != NULL && strcmp(service->name, service_name) != 0) service++; /* found or not? */ if (service->name == NULL) { error("OpenBoot service `%s' not found\n", service_name); TRACE(trace_os_emul, ("%s not found\n", service_name)); cpu_registers(processor)->gpr[3] = -1; } else { emul_data->service = service; /* call upon it */ result = service->handler(emul_data, processor, cia); if (result != 0) TRACE(trace_os_emul, ("%s aborted with %ld\n", service_name, (long)result)); cpu_registers(processor)->gpr[3] = result; } break; default: error("emul_chirp_instruction_call() unknown internal state\n"); result = -1; break; } /* return to caller - instruction following this is a function return */ return 1;}const os_emul emul_chirp = { "chirp", emul_chirp_create, emul_chirp_init, NULL, /*system_call*/ emul_chirp_instruction_call, 0 /*data*/};#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -