First big barely-functional code drop

This commit is contained in:
Peter Rutenbar 2014-02-24 17:14:52 -05:00
parent 6b3a5839d2
commit 93cefd9451
58 changed files with 24982 additions and 13 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/intermediates
/shoebill
.DS_Store
*.xcworkspace
xcuserdata

26
LICENSE
View File

@ -1,23 +1,23 @@
Copyright (c) 2014, pruten
Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

16
Makefile Normal file
View File

@ -0,0 +1,16 @@
CC = clang
CFLAGS = -O4 -arch x86_64 -Wno-deprecated-declarations
LFLAGS = -framework OpenGL -framework GLUT
all: shoebill
shoebill: make_core test.c
$(CC) $(LFLAGS) $(CFLAGS) -L intermediates -l shoebill_core test.c -o shoebill
make_core:
$(MAKE) -C core -j 4
clean:
rm -rf intermediates
rm -f shoebill

42
README Normal file
View File

@ -0,0 +1,42 @@
Shoebill - a Macintosh II emulator that can only run A/UX
See the wiki on https://code.google.com/p/shoebill for better
documentation on building and running Shoebill.
*** RUNNING ***
You will need
* OS X and a 64-bit Intel Macintosh
(32-bit builds may be possible in the future)
* A Macintosh II or IIx ROM
* A disk image with A/UX 1.x.x or 2.x.x installed
* The kernel on that image (/unix). Shoebill cant read
SVFS or UFS file sytems yet to load the kernel directly
from the disk image.
To boot A/UX
* Backup your disk images!!
When Shoebill inevitably crashes, your A/UX boot image
will very likely be corrupted - sometimes so severely
that A/UX cant even boot enough to run fsck.
* Open Shoebill.app and select Preferences menu item
* Set the paths for your ROM, kernel, and disk image(s).
* Do use SCSI ID #0 for your A/UX boot image.
* Give A/UX a reasonable amount of RAM - say, 32MB
* Press “Apply and Run”
*** BUILDING ***
1) cd to shoebill/
2) make # to build shoebill_core
3) xcodebuild -project gui/Shoebill.xcodeproj # to build the Cocoa GUI

58
core/Makefile Normal file
View File

@ -0,0 +1,58 @@
CC = clang
CFLAGS = -O4 -ggdb -arch x86_64 -Wno-deprecated-declarations
DEPS = core_api.h coff.h mc68851.h redblack.h shoebill.h Makefile macro.pl
NEED_DECODER = cpu dis
NEED_PREPROCESSING = adb fpu mc68851 mem via
NEED_NOTHING = atrap_tab coff exception floppy macii_symbols redblack scsi toby_frame_buffer video core_api
OBJ_NEED_NOTHING = $(patsubst %,$(TEMP)/%.o,$(NEED_NOTHING))
OBJ_NEED_PREPROCESSING = $(patsubst %,$(TEMP)/%.o,$(NEED_PREPROCESSING))
OBJ_NEED_DECODER = $(patsubst %,$(TEMP)/%.o,$(NEED_DECODER))
# Files that NEED_DECODER also NEED_PREPROCESSING
POST_PREPROCESSING = $(patsubst %,$(TEMP)/%.post.c,$(NEED_PREPROCESSING)) $(patsubst %,$(TEMP)/%.post.c,$(NEED_DECODER))
MACRO = perl macro.pl
TEMP = ../intermediates
all: $(TEMP)/libshoebill_core.a
$(TEMP)/libshoebill_core.a: $(TEMP) $(DEPS) $(OBJ_NEED_NOTHING) $(OBJ_NEED_PREPROCESSING) $(OBJ_NEED_DECODER)
libtool -static -o $(TEMP)/libshoebill_core.a $(OBJ_NEED_NOTHING) $(OBJ_NEED_PREPROCESSING) $(OBJ_NEED_DECODER)
# Build object files
$(OBJ_NEED_NOTHING): $(TEMP)/%.o: %.c $(DEPS)
$(CC) -c $(CFLAGS) $< -o $@
$(OBJ_NEED_PREPROCESSING): $(TEMP)/%.o: $(TEMP)/%.post.c $(DEPS)
$(CC) -c $(CFLAGS) $< -o $@
$(OBJ_NEED_DECODER): $(TEMP)/%.o: $(TEMP)/%.post.c $(DEPS) $(TEMP)/dis_decoder_guts.c $(TEMP)/inst_decoder_guts.c
$(CC) -c $(CFLAGS) $< -o $@
# Preprocess C files
$(POST_PREPROCESSING): $(TEMP)/%.post.c: %.c $(DEPS)
$(MACRO) $< $@
# Generate instruction decoders
$(TEMP)/inst_decoder_guts.c: $(TEMP)/decoder_gen $(DEPS)
$(TEMP)/decoder_gen inst $(TEMP)/
$(TEMP)/dis_decoder_guts.c: $(TEMP)/decoder_gen $(DEPS)
$(TEMP)/decoder_gen dis $(TEMP)/
# Compile the decoder generator
$(TEMP)/decoder_gen: decoder_gen.c $(DEPS)
$(CC) $(CFLAGS) decoder_gen.c -o $(TEMP)/decoder_gen
$(TEMP):
mkdir -p $(TEMP)
clean:
rm -rf $(TEMP)

393
core/adb.c Normal file
View File

@ -0,0 +1,393 @@
/*
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include "../core/shoebill.h"
#include <assert.h>
// via1 ORB bits abcd efgh
// cd -> adb FSM state
// e -> adb timeout occurred / service request (?)
// f/g/h nvram stuff
#define VIA_REGB_ADB_STATUS 8
/*
Reset:
-> OS writes reset command to sr, sets state 0
<- chip sets ADB status line, raises interrupt
-> OS dummy-reads sr, sets state 2
<- chip sets ADB status line, raises interrupt
-> OS dummy-reads sr, sets state 3
Talk:
-> OS writes talk command to sr, sets state 0
<- chip responds with an interrupt. Status=0 -> poll(unsolicited?), status=1 -> response?
-> OS sets state=1
<- chip responds with an interrupt. Status=0 -> timeout, status=1 -> not-timedout?
-> OS reads first byte from sr, sets state=2
<- chip responds with interrupt. Status=0 -> service request, service=1 no-service-reques
-> OS reads second byte from sr, sets state=3
Listen:
-> OS writes listen command to sr, sets state 0
<- chip
???
Keyboard:
-> OS sends EXISTS (TALK) for id 2, reg 3
<- (if no keyboard: timeout. If keyboard: respond with some data)
-> OS sends FLUSH
<- Keyboard responds
-> OS sends LISTEN for id 2, reg 3 (data: 0x2201 - sets the service request enable bit)
<- Keyboard respnods
-> OS sends TALK for id 2 reg 2
<- Keyboard responds with some keyboard setup data
-> OS sends TALK for id 2 reg 0
<- if there's a key, keyboard returns key data. Otherwise, response times out.
*/
void adb_start_service_request()
{
printf("adb_start_service_request: pending_requests = 0x%02x\n", shoe.adb.pending_service_requests);
if (shoe.adb.pending_service_requests) {
shoe.adb.service_request = 1;
shoe.adb.poll = shoe.adb.pending_poll;
shoe.adb.pending_poll = 0;
via_raise_interrupt(1, IFR_SHIFT_REG);
}
}
void adb_request_service_request(uint8_t id)
{
shoe.adb.pending_service_requests |= (1 << id);
shoe.adb.pending_poll = 1;
if (shoe.adb.state == 3) {
adb_start_service_request();
}
}
static void keyboard_talk(uint8_t reg)
{
shoe.adb.timeout = 0;
switch (reg) {
case 0:
if (shoe.key.key_i > 0) {
shoe.adb.data[0] = shoe.key.keys[0].code_b;
shoe.adb.data[1] = shoe.key.keys[0].code_a;
shoe.adb.data_len = 2;
shoe.key.key_i--;
memmove(&shoe.key.keys[0], &shoe.key.keys[1], shoe.key.key_i * sizeof(shoe.key.keys[0]));
}
else
shoe.adb.timeout = 1;
return ;
case 2:
// All the modifier keys are up
shoe.adb.data[0] = 0b01111111;
shoe.adb.data[1] = 0b11100111;
shoe.adb.data_len = 2;
return ;
case 1:
shoe.adb.timeout = 1;
return ;
case 3:
shoe.adb.data[0] = 0;
shoe.adb.data[1] = 0;
shoe.adb.data_len = 2;
return ;
}
}
static void mouse_talk(uint8_t reg)
{
shoe.adb.timeout = 0;
printf("mouse_talk: reg=%u\n", reg);
switch (reg) {
case 0:
if (shoe.mouse.changed) {
printf("mouse_talk: x=%d, y=%d button=%u\n", shoe.mouse.delta_x, shoe.mouse.delta_y, shoe.mouse.button_down);
shoe.adb.data[1] = shoe.mouse.delta_x & 0x7f;
shoe.adb.data[0] = shoe.mouse.delta_y & 0x7f;
if (!shoe.mouse.button_down) {
//shoe.adb.data[1] |= 0x80;
shoe.adb.data[0] |= 0x80;
}
// printf("mouse_talk: ")
shoe.adb.data_len = 2;
shoe.mouse.delta_x = 0;
shoe.mouse.delta_y = 0;
// shoe.mouse.button_down = 0;
shoe.mouse.changed = 0;
}
else
shoe.adb.timeout = 1;
return ;
case 1:
assert(!"Can't handle reg 1");
case 2:
assert(!"Can't handle reg 2");
case 3:
shoe.adb.data[0] = 3; // device address: 3
shoe.adb.data[1] = 1; // handler ID: 1
shoe.adb.data_len = 2;
return ;
}
}
static void adb_handle_state_zero(uint8_t command_byte, uint8_t is_poll) // "Command" state
{
via_state_t *via = &shoe.via[0];
const uint8_t id = command_byte >> 4; // the target device ID
const uint8_t reg = command_byte & 3;
// Figure out the command type (reset/flush/talk/listen)
if ((command_byte & 0xf) == 0) // reset
shoe.adb.command_type = adb_reset;
else if ((command_byte & 0xf) == 1) // flush
shoe.adb.command_type = adb_flush;
else if (~bmatch(command_byte, xxxx 11 xx)) // talk
shoe.adb.command_type = adb_talk;
else if (~bmatch(command_byte, xxxx 10 xx)) // listen
shoe.adb.command_type = adb_listen;
else
assert(!"What is this adb state-0 command? xxxx 01xx");
printf("adb_handle_state_zero: command_byte=0x%02x, id=%u, reg=%u\n", command_byte, id, reg);
shoe.adb.command_device_id = id;
shoe.adb.command_reg = reg;
// Flush/reset/listen and talk-with-timeout need data_i initialized to 0
shoe.adb.data_i = 0;
shoe.adb.data_len = 0;
// If talk, go ask they keyboard/mouse if they have anything to say
if (shoe.adb.command_type == adb_talk) {
if (id == 2) {
keyboard_talk(reg);
}
else if (id == 3) {
mouse_talk(reg);
}
else { // timeout
shoe.adb.timeout = 1;
}
// If there was a service request pending for this device, it is now handled.
shoe.adb.pending_service_requests &= ~~(1 << id);
}
shoe.adb.poll = 0;
via->regb |= VIA_REGB_ADB_STATUS;
via_raise_interrupt(1, IFR_SHIFT_REG);
}
static void adb_handle_state_one (void) // "Even" state
{
via_state_t *via = &shoe.via[0];
printf("adb_handle_state_one: ");
if (shoe.adb.poll) {
// Upon receiving a service request, the adb controller sends a TALK/reg=0 to the last accessed device
adb_handle_state_zero((shoe.adb.command_device_id << 4) | 0x0c, 1);
}
switch (shoe.adb.command_type) {
case adb_flush:
case adb_reset:
assert(!"adb_handle_state_one: unexpected command type");
break;
case adb_talk:
printf("adb_talk: ");
if (shoe.adb.timeout) {
shoe.adb.timeout = 0;
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
via_raise_interrupt(1, IFR_SHIFT_REG);
printf("timeout\n");
return ;
}
if (shoe.adb.data_i < shoe.adb.data_len)
via->sr = shoe.adb.data[shoe.adb.data_i++];
else
via->sr = 0;
printf("set sr = 0x%02x\n", via->sr);
break;
case adb_listen:
printf("adb_listen: ");
if (shoe.adb.timeout) {
shoe.adb.timeout = 0;
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
via_raise_interrupt(1, IFR_SHIFT_REG);
printf("timeout\n");
return ;
}
if (shoe.adb.data_i < 8)
shoe.adb.data[shoe.adb.data_i++] = via->sr;
else
assert(!"OS made us listen to > 8 bytes");
printf("loaded sr = 0x%02x\n", via->sr);
break;
}
via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == didn't-timeout
via_raise_interrupt(1, IFR_SHIFT_REG);
}
static void adb_handle_state_two (void) // "Odd" state
{
via_state_t *via = &shoe.via[0];
printf("adb_handle_state_two: ");
// If this transaction was part of a service request, clear the service_request flag now
if (shoe.adb.service_request) {
shoe.adb.service_request = 0;
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == service request
printf("(service request) ");
}
else
via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == no-service request
switch (shoe.adb.command_type) {
case adb_flush:
case adb_reset:
printf("adb_flush/reset\n");
break;
case adb_talk:
printf("adb_talk: ");
if (shoe.adb.data_i < shoe.adb.data_len)
via->sr = shoe.adb.data[shoe.adb.data_i++];
else
via->sr = 0;
printf("set sr = 0x%02x\n", via->sr);
break;
case adb_listen:
printf("adb_listen: ");
if (shoe.adb.data_i < 8)
shoe.adb.data[shoe.adb.data_i++] = via->sr;
else
assert(!"OS made us listen to > 8 bytes");
printf("read sr = 0x%02x\n", via->sr);
break;
}
via_raise_interrupt(1, IFR_SHIFT_REG);
}
static void adb_handle_state_three (void) // "idle" state
{
printf("adb_handle_state_three: completed for id %u\n", shoe.adb.command_device_id);
switch (shoe.adb.command_type) {
case adb_reset:
case adb_flush:
case adb_talk:
break;
case adb_listen:
printf("adb_handle_state_three: listen completed for id %u, reg %u, data_len = %u {%02x %02x}\n",
shoe.adb.command_device_id, shoe.adb.command_reg, shoe.adb.data_i, shoe.adb.data[0], shoe.adb.data[1]);
break;
}
adb_start_service_request();
}
void adb_handle_state_change(uint8_t old_state, uint8_t new_state)
{
via_state_t *via = &shoe.via[0];
printf("%s: lock\n", __func__); fflush(stdout);
assert(pthread_mutex_lock(&shoe.adb.lock) == 0);
shoe.adb.state = new_state;
switch (new_state) {
case 0:
shoe.adb.command_byte = via->sr;
adb_handle_state_zero(shoe.adb.command_byte, 0);
break ;
case 1:
adb_handle_state_one();
break ;
case 2:
adb_handle_state_two();
break ;
case 3:
adb_handle_state_three();
break ;
}
printf("%s: unlock\n", __func__); fflush(stdout);
pthread_mutex_unlock(&shoe.adb.lock);
}

4102
core/atrap_tab.c Normal file

File diff suppressed because it is too large Load Diff

329
core/coff.c Normal file
View File

@ -0,0 +1,329 @@
/*
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdint.h>
#include "shoebill.h"
#include "coff.h"
void symb_inorder(rb_node *cur) {
const coff_symbol *sym = (coff_symbol*)cur->value;
if (!sym)
return ;
symb_inorder(cur->left);
printf("0x%x %s\n", cur->key, sym->name);
symb_inorder(cur->right);
}
// Given a path to a COFF binary, create a coff_file structure and return a pointer.
// God help you if you want to free it.
coff_file* coff_parser(const char *path)
{
FILE *f;
uint8_t rawhead[20], *ptr;
uint32_t i;
coff_file *cf = NULL;
// Open the file
f = fopen(path, "r");
if (!f) {
printf("coff_parser: I couldn't open that binary for reading (%s)\n", path);
goto fail;
}
// Pull out 20 bytes (the file header)
if (fread(rawhead, 20, 1, f) != 1) {
printf("coff_parser: error: this binary is missing its file header\n");
goto fail;
}
// Allocate a coff_file and copy in the header
cf = (coff_file*)calloc(1, sizeof(coff_file));
ptr = rawhead;
cf->magic = be2native(&ptr, 2);
cf->num_sections = be2native(&ptr, 2);
cf->timestamp = be2native(&ptr, 4);
cf->symtab_offset = be2native(&ptr, 4);
cf->num_symbols = be2native(&ptr, 4);
cf->opt_header_len = be2native(&ptr, 2);
cf->flags = be2native(&ptr, 2);
// A little sanity checking...
if (cf->magic != 0x150) {
printf("coff_parse: I don't recognize this magic number: 0x%04x\n", cf->magic);
goto fail;
}
else if (cf->num_sections != 3) {
//printf("coff_parse: warning: there are %u sections in this file (not 3, like I expect)\n", cf->num_sections);
// FIXME: investigate all the other possible section types
}
// pull out cf->opt_header bytes (a.out-format header, I guess?)
if (cf->opt_header_len > 0) {
uint8_t *opt = malloc(cf->opt_header_len);
if (fread(opt, cf->opt_header_len, 1, f) != 1) {
printf("coff_parse: I ran out of data pulling the optional header (%u bytes)\n", cf->opt_header_len);
free(opt);
goto fail;
}
cf->opt_header = opt;
}
// start pulling out sections
cf->sections = calloc(cf->num_sections, sizeof(coff_section));
for (i=0; i<cf->num_sections; i++) {
// read the header
uint8_t rawsec[40];
if (fread(rawsec, 40, 1, f) != 1) {
printf("coff_parse: I ran out of data pulling section #%u\n", i+1);
goto fail;
}
// and copy it into cf->sections[i]
memcpy(cf->sections[i].name, rawsec, 8);
ptr = &rawsec[8];
cf->sections[i].p_addr = be2native(&ptr, 4);
cf->sections[i].v_addr = be2native(&ptr, 4);
cf->sections[i].sz = be2native(&ptr, 4);
cf->sections[i].data_ptr = be2native(&ptr, 4);
cf->sections[i].reloc_ptr = be2native(&ptr, 4);
cf->sections[i].line_ptr = be2native(&ptr, 4);
cf->sections[i].num_relocs = be2native(&ptr, 2);
cf->sections[i].num_lines = be2native(&ptr, 2);
cf->sections[i].flags = be2native(&ptr, 4);
// a little bit of sanity checking:
if (cf->sections[i].v_addr != cf->sections[i].p_addr) {
//printf("coff_parse: warning: section %u's virtual_addr and physical_addr don't match: p=%x v=%x\n",
// i+1, cf->sections[i].p_addr, cf->sections[i].v_addr);
// This is okay for the unix kernel
}
}
// pull out the corresponding raw data for each section
for (i=0; i<cf->num_sections; i++) {
uint8_t *data;
// don't bother if there's no data
if (cf->sections[i].sz == 0) {
continue ;
}
// don't bother if it's .bss
if (memcmp(cf->sections[i].name, ".bss\0\0\0\0", 8)==0) {
continue ;
}
// seek to the position in the binary that holds this section's raw data
if (fseek(f, cf->sections[i].data_ptr, SEEK_SET) != 0) {
printf("coff_parse: I couldn't seek to 0x%x in section %u\n", cf->sections[i].data_ptr, i+1);
goto fail;
}
// load the data and attach it to the section struct
data = malloc(cf->sections[i].sz); // FIXME: sz might not be a sane value
if (fread(data, cf->sections[i].sz, 1, f) != 1) {
printf("coff_parse: I couldn't fread section %u (%s)'s data (%u bytes)\n", i+1, cf->sections[i].name, cf->sections[i].sz);
free(data);
goto fail;
}
cf->sections[i].data = data;
}
// pull out the symbol table
if (cf->num_symbols == 0) // if num_symbols==0, symtab_offset may be bogus
return cf; // just return
cf->func_tree = rb_new();
//printf("func_tree = %llx, *func_tree = %llx\n", cf->func_tree, *cf->func_tree);
cf->symbols = (coff_symbol*)calloc(sizeof(coff_symbol), cf->num_symbols);
// Seek to the symbol table
if (fseek(f, cf->symtab_offset, SEEK_SET) != 0) {
printf("coff_parse: I couldn't seek to symtab_offset, 0x%x\n", cf->symtab_offset);
goto fail;
}
for (i=0; i < cf->num_symbols; i++) {
uint8_t raw_symb[18];
if (fread(raw_symb, 18, 1, f) != 1) {
printf("coff_parse: I ran out of data pulling symbol #%u\n", i+1);
goto fail;
}
// load the name
if (*((uint32_t*)raw_symb) == 0) {
uint8_t tmp_name[256];
uint32_t j, offset, idx = cf->symtab_offset + 18*cf->num_symbols;
for (j=4, offset=0; j<8; j++) offset = (offset<<8) | raw_symb[j];
idx += offset;
// printf("Loading from external: base idx=0x%x, offset=%u, addr=0x%x\n", idx-offset, offset, idx);
if (fseek(f, idx, SEEK_SET) != 0) {
printf("coff_parse: I ran out of data pulling symbol %u's name (idx=0x%x)\n", i+1, idx);
goto fail;
}
for (j=0; (fread(&tmp_name[j], 1, 1, f)==1) && tmp_name[j]; j++) {
if (j >= 255) {
// printf("coff_parse: this symbol's name is too long: %u\n", i+1);
goto fail;
}
}
cf->symbols[i].name = malloc(j+1);
memcpy(cf->symbols[i].name, tmp_name, j);
cf->symbols[i].name[j] = 0;
fseek(f, cf->symtab_offset + (i+1)*18, SEEK_SET);
//printf("cf->symtab_offset = 0x%x, i=%u, (i+1)*18 = %u\n",
//cf->symtab_offset, i, (i+1)*18);
//printf("seeking back to 0x%x\n", cf->symtab_offset + (i+1)*18);
}
else {
uint8_t tmp_name[9];
memcpy(tmp_name, raw_symb, 8);
tmp_name[8] = 0;
cf->symbols[i].name = strdup((char*)tmp_name);
}
ptr = &raw_symb[8];
cf->symbols[i].value = be2native(&ptr, 4);
cf->symbols[i].scnum = be2native(&ptr, 2);
cf->symbols[i].type = be2native(&ptr, 2);
cf->symbols[i].sclass = raw_symb[16];
cf->symbols[i].numaux = raw_symb[17];
// FIXME: I need to handle numaux > 0.
//if (cf->symbols[i].numaux > 0) {
printf("%s\n", cf->symbols[i].name);
printf("value=0x%08x scnum=0x%04x type=0x%04x sclass=0x%02x numaux=%u\n\n",
cf->symbols[i].value, cf->symbols[i].scnum, cf->symbols[i].type, cf->symbols[i].sclass, cf->symbols[i].numaux);
//}
if (cf->symbols[i].sclass == 2 || cf->symbols[i].sclass == 3) {
rb_insert(cf->func_tree, cf->symbols[i].value, &cf->symbols[i], NULL);
//printf("%s addr=0x%x\n", cf->symbols[i].name, cf->symbols[i].value);
}
// printf("%u: %s (class=%u)\n", i+1, cf->symbols[i].name, cf->symbols[i].sclass);
}
// symb_inorder(*cf->func_tree);
// and we're done
return cf;
fail:
if (cf) {
if (cf->opt_header) {
free(cf->opt_header);
}
if (cf->sections) {
for (i=0; i<cf->num_sections; i++) {
if (cf->sections[i].data) {
free(cf->sections[i].data);
}
}
free(cf->sections);
}
free(cf);
}
return NULL;
}
// dump some data about a coff_file structure
void print_coff_info(coff_file *coff)
{
char timebuf[32];
time_t timestamp = coff->timestamp;
uint32_t i;
printf("Magic = 0x%04x\n", coff->magic);
printf("Linked on %s", ctime_r(&timestamp, timebuf));
printf("Num sections = %u\n", coff->num_sections);
printf("debug: num_symbols=%u, symtab_offset=0x%x\n", coff->num_symbols, coff->symtab_offset);
for (i=0; i<coff->num_sections; i++) {
coff_section *s = &coff->sections[i];
char name[9];
memcpy(name, s->name, 8);
name[8] = 0;
printf("Section #%u: %s\n", i+1, name);
printf("\taddr=0x%08x, len=0x%x, (debug: paddr=0x%08x, flags=0x%08x)\n", s->v_addr, s->sz, s->p_addr, s->flags);
}
}
coff_symbol* coff_find_symbol(coff_file *coff, const char *name)
{
uint32_t i;
for (i=0; i < coff->num_symbols; i++) {
if (strcmp(coff->symbols[i].name, name) == 0)
return &coff->symbols[i];
}
return NULL;
}
coff_symbol* coff_find_func(coff_file *coff, uint32_t addr)
{
rb_node *cur;
coff_symbol *last = NULL;
// printf("coff->num_symbols = %u\n", coff->num_symbols);
if (coff->num_symbols == 0)
return NULL;
cur = *coff->func_tree;
while (cur) {
// printf("... iterating\n");
if (addr < cur->key)
cur = cur->left;
else if (addr > cur->key) {
last = cur->value;
cur = cur->right;
}
else
return cur->value;
}
return last;
}
// big endian -> native int
uint32_t be2native (uint8_t **dat, uint32_t bytes)
{
uint32_t i, v = 0;
for (i=0; i < bytes; i++)
v = (v<<8) | (*dat)[i];
(*dat) += bytes;
return v;
}

84
core/coff.h Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _COFF_H
#define _COFF_H
#include <stdint.h>
#include "redblack.h"
typedef struct {
char *name;
uint32_t value;
uint16_t scnum, type;
uint8_t sclass, numaux;
} coff_symbol;
// informed by http://www.delorie.com/djgpp/doc/coff/scnhdr.html
typedef struct {
char name[8];
uint32_t p_addr;
uint32_t v_addr;
uint32_t sz;
uint32_t data_ptr;
uint32_t reloc_ptr;
uint32_t line_ptr;
uint16_t num_relocs;
uint16_t num_lines;
uint32_t flags;
uint8_t *data;
} coff_section;
// data for this segment appears in the file, but shouldn't be copied into memory
#define coff_copy 0x0010
#define coff_text 0x0020
#define coff_data 0x0040
#define coff_bss 0x0080
typedef struct {
uint16_t magic;
uint16_t num_sections;
uint32_t timestamp;
uint32_t symtab_offset;
uint32_t num_symbols;
uint16_t opt_header_len;
uint16_t flags;
uint8_t *opt_header;
coff_section *sections;
rb_tree *func_tree;
coff_symbol *symbols;
} coff_file;
coff_symbol* coff_find_func(coff_file *coff, uint32_t addr);
coff_symbol* coff_find_symbol(coff_file *coff, const char *name);
coff_file* coff_parser(const char *path);
uint32_t be2native (uint8_t **dat, uint32_t bytes);
void print_coff_info(coff_file *coff);
#endif // _COFF_H

908
core/core_api.c Normal file
View File

@ -0,0 +1,908 @@
/*
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <assert.h>
#include <pthread.h>
#include <unistd.h>
#include "shoebill.h"
#include "coff.h"
#include "core_api.h"
static uint64_t sub_tv (const struct timeval a, const struct timeval b)
{
return 0;
}
void print_mmu_rp(uint64_t rp)
{
printf("lu=%u limit=0x%x sg=%u dt=%u addr=0x%08x\n", rp_lu(rp), rp_limit(rp), rp_sg(rp), rp_dt(rp), rp_addr(rp));
}
void printregs()
{
printf("[d0]%08x [d1]%08x [d2]%08x [d3]%08x\n", shoe.d[0], shoe.d[1], shoe.d[2], shoe.d[3]);
printf("[d4]%08x [d5]%08x [d6]%08x [d7]%08x\n", shoe.d[4], shoe.d[5], shoe.d[6], shoe.d[7]);
printf("[a0]%08x [a1]%08x [a2]%08x [a3]%08x\n", shoe.a[0], shoe.a[1], shoe.a[2], shoe.a[3]);
printf("[a4]%08x [a5]%08x [a6]%08x [a7]%08x\n", shoe.a[4], shoe.a[5], shoe.a[6], shoe.a[7]);
printf("[pc]%08x [sr]%c%c%c%c%c%c%c [tc]%08x\n", shoe.pc,
sr_s()?'S':'s',
sr_m()?'M':'m',
sr_x()?'X':'x',
sr_n()?'N':'n',
sr_z()?'Z':'z',
sr_v()?'V':'v',
sr_c()?'C':'c',
shoe.tc
);
printf("[vbr]%08x\n", shoe.vbr);
printf("srp: ");
print_mmu_rp(shoe.srp);
printf("crp: ");
print_mmu_rp(shoe.crp);
printf("tc: e=%u sre=%u fcl=%u ps=%u is=%u (tia=%u tib=%u tic=%u tid=%u)\n",
tc_enable(), tc_sre(), tc_fcl(), tc_ps(), tc_is(), tc_tia(), tc_tib(), tc_tic(), tc_tid());
printf("\n");
}
void print_pc()
{
char str[1024];
uint8_t binary[32];
uint32_t i;
uint32_t len;
const char *name = NULL;
if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) {
uint32_t i, addr = shoe.pc % (shoe.physical_rom_size);
for (i=0; macii_rom_symbols[i].name; i++) {
if (macii_rom_symbols[i].addr > addr) {
break;
}
name = macii_rom_symbols[i].name;
}
}
else if (sr_s()) { // these symbols are only meaningful in supervisor mode
coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc);
if (symb && strlen(symb->name))
name = symb->name;
}
else {
if ((shoe.pc >= 0x10000000) && (shoe.pc < 0x20000000)) {
uint32_t i, addr = shoe.pc % (shoe.physical_rom_size);
for (i=0; macii_rom_symbols[i].name; i++) {
if (macii_rom_symbols[i].addr > addr) {
break;
}
name = macii_rom_symbols[i].name;
}
}
/*else {
coff_symbol *symb = coff_find_func(shoe.launch, shoe.pc);
if (symb)
name = symb->name;
}*/
}
const uint16_t old_abort = shoe.abort;
shoe.suppress_exceptions = 1;
for (i=0; i<32; i++) {
binary[i] = (uint8_t) lget(shoe.pc+i, 1);
}
disassemble_inst(binary, shoe.pc, str, &len);
printf("*0x%08x %s [ ", shoe.pc, name ? name : "");
for (i=0; i<len; i+=2) {
printf("%02x%02x ", binary[i], binary[i+1]);
}
printf("] %s\n", str);
shoe.abort = old_abort;
shoe.suppress_exceptions = 0;
if (name && strcmp(name, "ui_ioctl")==0)
printregs();
}
void shoebill_start()
{
pthread_mutex_unlock(&shoe.cpu_thread_lock);
pthread_mutex_unlock(&shoe.via_clock_thread_lock);
}
static void _cpu_loop_fast()
{
while (1) {
if (shoe.cpu_thread_notifications) {
// If there's an interrupt pending
if (shoe.cpu_thread_notifications & 0xff) {
// process_pending_interrupt() may clear SHOEBILL_STATE_STOPPED
process_pending_interrupt();
}
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
continue; // FIXME: yield or block on a condition variable here
}
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_SWITCH_MODE)
return ;
}
cpu_step();
}
}
static void _cpu_loop_debug()
{
while (1) {
if (shoe.cpu_thread_notifications) {
// I think we can safely ignore "stop" instructions for A/UX in debug mode
shoe.cpu_thread_notifications &= ~SHOEBILL_STATE_STOPPED;
if (shoe.cpu_thread_notifications & 0xff) {
process_pending_interrupt();
}
}
}
}
void *_cpu_thread (void *arg) {
pthread_mutex_lock(&shoe.cpu_thread_lock);
while (1) {
shoe.cpu_thread_notifications &= ~SHOEBILL_STATE_SWITCH_MODE;
if (shoe.cpu_mode == CPU_MODE_FAST)
_cpu_loop_fast();
else if (shoe.cpu_mode == CPU_MODE_DEBUG)
_cpu_loop_debug();
else if (shoe.cpu_mode == CPU_MODE_STEPI) {
cpu_step();
shoe.cpu_mode = CPU_MODE_STEPI_COMPLETE;
while (shoe.cpu_mode == CPU_MODE_STEPI_COMPLETE)
pthread_yield_np();
}
else if (shoe.cpu_mode == CPU_MODE_FREEZE) {
pthread_mutex_lock(&shoe.cpu_freeze_lock);
pthread_mutex_unlock(&shoe.cpu_freeze_lock);
}
}
}
void shoebill_cpu_stepi (void)
{
if (shoe.cpu_mode != CPU_MODE_FREEZE)
return ;
shoe.cpu_mode = CPU_MODE_STEPI;
pthread_mutex_unlock(&shoe.cpu_freeze_lock);
// Just spin until the instruction completes - it should be quick
while (shoe.cpu_mode != CPU_MODE_STEPI_COMPLETE)
pthread_yield_np();
pthread_mutex_lock(&shoe.cpu_freeze_lock);
shoe.cpu_mode = CPU_MODE_FREEZE;
}
void shoebill_cpu_freeze (void)
{
pthread_mutex_lock(&shoe.cpu_freeze_lock);
shoe.cpu_mode = CPU_MODE_FREEZE;
shoe.cpu_thread_notifications &= SHOEBILL_STATE_SWITCH_MODE;
while (shoe.cpu_thread_notifications & SHOEBILL_STATE_SWITCH_MODE);
pthread_yield_np();
}
/*
* The A/UX bootloader blasts this structure into memory
* somewhere before jumping into the kernel to commmunicate
* stuff like: which scsi device/partition is root?
*/
struct __attribute__ ((__packed__)) kernel_info {
// Auto data
uint32_t auto_magic;
uint32_t auto_id[16];
uint32_t auto_version[16];
uint32_t auto_command;
uint16_t root_ctrl;
uint8_t root_drive;
uint8_t root_cluster;
struct __attribute__ ((__packed__)) sect_info {
uint32_t vstart;
uint32_t pstart;
uint32_t size;
} si[3];
uint16_t machine_type; // Not the same as gestalt IDs!
uint32_t drive_queue_offset;
uint16_t ki_flags;
uint8_t ki_version; // always 1
uint8_t root_partition;
uint16_t swap_ctrl;
uint8_t swap_drive;
uint8_t swap_partition;
// A series of DrvQEl (drive queue elements) follow this structure
};
/* Inside Macintosh: Files 2-85 throughtfully provides this information
* on the secret internal flags:
*
* The File Manager also maintains four flag bytes preceding each drive queue element.
* These bytes contain the following information:
* Byte (from low address to high address)
* 0 Bit 7=1 if the volume on the drive is locked
* 1 0 if no disk in drive; 1 or 2 if disk in drive; 8 if nonejectable disk in drive; $FC$FF if
* disk was ejected within last 1.5 seconds; $48 if disk in drive is nonejectable but driver
* wants a call
* 2 Used internally during system startup
* 3 Bit 7=0 if disk is single-sided
* You can read these flags by subtracting 4 bytes from the beginning of a drive queue element,
* as illustrated in Listing 2-11.
*/
struct __attribute__ ((__packed__)) drive_queue_element {
/* Secret internal flags */
uint8_t unknown_1 : 7;
uint8_t is_locked : 1; // 1 if locked, 0 -> unlocked
uint8_t is_in_drive;
uint8_t unknown_2;
uint8_t unknown_3 : 7;
uint8_t double_sided : 1; // 0 if single-sided, presumably 1 if HDD or double-sided
/* --- */
uint32_t next_offset;
int16_t qType; // 1 -> both dQDrvSz and dQDrvSz2 are used
int16_t dQDrive; // drive number (scsi target ID)
int16_t dQRefNum; // Driver reference number (I'm thinking -33 is the right value here)
int16_t dQFSID; // Filesystem identifier (0 is best, I think)
uint16_t dQDrvSz; // low 16 bits of numblocks
uint16_t dQDrvSz2; // high 16 bits of numblocks
};
/*
* Initialize the Macintosh lomem variables, or some of them anyways.
* Debugging weird errors revealed that A/UX actually cares about
* some of them.
*/
static void _init_macintosh_lomem_globals (const uint32_t offset)
{
/*
* FIXME: explain what I'm doing here
*/
uint32_t i;
// Fill the entire lomem space with 0xBB to make debugging easier
// if somebody tries to read an uninitialized lomem value
// for (i=0; i<0x4000; i++)
// pset(offset + i, 1, 0xBB);
// There are the lomem globals that matter, apparently
pset(offset+0x12f, 1, 0x02); // CPUFlag = 0x02 (MC68020)
pset(offset+0x31a, 4, 0x00ffffff); // Lo3Bytes (always 0x00ffffff)
pset(offset+0x28e, 2, 0x3fff); // ROM85 (always 0x3fff, I think?)
// universal info ptr. is allowed to be null on Mac II, (I THINK)
pset(offset+0xdd8, 4, 0);
pset(offset+0x1d4, 4, 0x50000000); // VIA (via1 ptr)
pset(offset+0x1d8, 4, 0x50004000); // SCC
#define hwCbSCSI (1<<15)
#define hwCbClock (1<<14)
#define hwCbExPRAM (1<<13)
#define hwCbFPU (1<<12)
#define hwCbMMU (1<<11)
#define hwCbADB (1<<10)
#define hwCbAUX (1<<9) /* not sure if I need to set this one */
const uint16_t HWCfgFlags = hwCbSCSI | hwCbClock | hwCbFPU | hwCbMMU | hwCbADB;
pset(0xb22, 2, HWCfgFlags); // HWCfgFlags
}
/*
* Setup and blast the kernel_info structure into memory
* before booting A/UX.
* Side-effects: sets CPU registers d0 and a0
*/
static void _init_kernel_info(shoebill_control_t *control, scsi_device_t *disks, uint32_t offset)
{
struct kernel_info ki, *p;
uint32_t i, p_addr;
p_addr = offset + 0x3c00;
p = (struct kernel_info*) (uint64_t)p_addr;
/*
* On boot, the kernel looks for this magic constant in d0 to see whether
* the bootloader setup a kernel_info structure.
*/
shoe.d[0] = 0x536d7201; // "Smr\1"? Something version 1?
shoe.a[0] = (uint32_t)p; // Address of the kernel_info structure
/* ----- Setup kernel info structure ------ */
ki.auto_magic = 0x50696773; // 'Pigs' (Pigs in space?)
for (i=0; i<16; i++) {
ki.auto_id[i] = 0x0000ffff;
ki.auto_version[i] = 0;
}
// FIXME: I need to stick the auto_id for each nubus card in here
// ki.auto_id[0xb] = 0x5; // Macintosh II video card has an auto_id of 5 (I guess?)
ki.auto_command = control->aux_autoconfig; // AUTO_NONE/AUTO_CONFIG
/*
* Note: ctrl -> SCSI controller chip
* drive -> SCSI Target ID
* partition -> partition
* cluster -> A set of partitions on a given drive
* (Used by escher/eschatology somehow)
*/
ki.root_ctrl = control->root_ctrl;
ki.swap_ctrl = control->swap_ctrl;
ki.root_drive = control->root_drive;
ki.swap_drive = control->swap_drive;
ki.root_partition = control->root_partition;
ki.swap_partition = control->swap_partition;
ki.root_cluster = control->root_cluster;
// Find the text, data, and bss segments in the kernel
for (i = 0; i < shoe.coff->num_sections; i++) {
coff_section *s = &shoe.coff->sections[i];
uint8_t sect;
if (strcmp(s->name, ".text") == 0)
sect = 0;
else if (strcmp(s->name, ".data") == 0)
sect = 1;
else if (strcmp(s->name, ".bss") == 0)
sect = 2;
else
continue;
ki.si[sect].vstart = s->v_addr;
ki.si[sect].pstart = s->p_addr;
ki.si[sect].size = s->sz;
}
ki.machine_type = 4; // Macintosh II?
// +4 because the DrvQEl structure has a hidden "flags" field 4 bytes below the pointer
ki.drive_queue_offset = sizeof(struct kernel_info) + 4;
ki.ki_flags = control->aux_verbose;
ki.ki_version = 1;
/* ----- Copy ki into memory ----- */
#define ki_pset(_f) pset((uint32_t)&p->_f, sizeof(p->_f), ki._f)
ki_pset(auto_magic);
for (i=0; i<16; i++) {
ki_pset(auto_id[i]);
ki_pset(auto_version[i]);
}
ki_pset(auto_command);
ki_pset(root_ctrl);
ki_pset(root_drive);
ki_pset(root_cluster);
for (i=0; i<3; i++) {
ki_pset(si[i].vstart);
ki_pset(si[i].pstart);
ki_pset(si[i].size);
}
ki_pset(machine_type);
ki_pset(drive_queue_offset);
ki_pset(ki_flags);
ki_pset(ki_version);
ki_pset(root_partition);
ki_pset(swap_ctrl);
ki_pset(swap_drive);
ki_pset(swap_partition);
/* ---- Copy DrvQEl elements into memory ---- */
// FIXME: btw, this is probably wrong. DrvQEl elements are supposed to be partitions, I think
uint32_t addr = p_addr + sizeof(struct kernel_info);
uint32_t num_disks = 0;
for (i=0; i<7; i++)
if (disks[i].f) num_disks++;
for (i=0; i<7; i++) {
if (disks[i].f == NULL)
continue;
num_disks--;
pset(addr, 4, 0x00080000); addr += 4; // magic internal flags (non-ejectable)
pset(addr, 4, num_disks ? 0x14 : 0); addr += 4; // offset to next drvqel
pset(addr, 2, 1); addr += 2; // Use both dQDrvSzs
pset(addr, 2, i | 8); addr += 2; // SCSI ID (with bit 3 always set?)
// pset(addr, 2, 0xffdf); addr += 2; // dQRefNum: not sure if this is right
pset(addr, 2, (i | 0x20) ^ 0xffff); addr += 2; // dQRefNum: not sure if this is right
pset(addr, 2, 0); addr += 2; // FSID
pset(addr, 2, disks[i].num_blocks & 0xffff); addr += 2; // low 16 bits of num_blocks
pset(addr, 2, disks[i].num_blocks >> 16); addr += 2; // high bits