sillicon graphics octane2の仕様(PROM編)

octane2のファームウェア(PROM)は、ARC firmware environmentを独自拡張したもの。
詳細はARC - LinuxMIPSに書いてある通りだが、オリジナルの規格に対し

などの違いがある模様。

sgi PROMとARC APIでお話出来るarcloadを使って少々解析を試みた。

SystemParameterBlock 0xFFFFFFFFA0001000

typedef struct {
        ULONG SPBSignature;
        ULONG SPBLength;
        USHORT Version;
        USHORT Revision;
        RESTARTBLOCK *RestartBlock;
        VOID *DebugBlock;
        VOID *GEVector;
        VOID *UTLBMissVector;
        ULONG FirmwareVectorLength;
        FIRMWAREVECTOR *FirmwareVector;
        ULONG PrivateVectorLength;
        VOID *PrivateVector;
        ULONG AdapterCount;
        ADAPTER Adapters[1];
} SPB;

このうち、FirmwareVectorを使ってARC APIと会話しているらしい。
SystemParameterBlock->FirmwareVector 0xa800000000001800

typedef struct {
        LONG(*Load) (CHAR *, ULONG, ULONG *, ULONG *);
        LONG(*Invoke) (ULONG, ULONG, ULONG, CHAR *[], CHAR *[]);
        LONG(*Execute) (CHAR *, ULONG, CHAR *[], CHAR *[]);
        VOID(*Halt) (VOID);
        VOID(*PowerDown) (VOID);
        VOID(*Restart) (VOID);
        VOID(*Reboot) (VOID);
        VOID(*EnterInteractiveMode) (VOID);
        VOID *reserved1;
        COMPONENT *(*GetPeer) (COMPONENT *);
        COMPONENT *(*GetChild) (COMPONENT *);
        COMPONENT *(*GetParent) (COMPONENT *);
        LONG(*GetConfigurationData) (VOID *, COMPONENT *);
        COMPONENT *(*AddChild) (COMPONENT *, COMPONENT *, VOID *);
        LONG(*DeleteComponent) (COMPONENT *);
        COMPONENT *(*GetComponent) (CHAR *);
        LONG(*SaveConfiguration) (VOID);
        SYSTEMID *(*GetSystemId) (VOID);
        MEMORYDESCRIPTOR *(*GetMemoryDescriptor) (MEMORYDESCRIPTOR *);
        VOID *reserved2;
        TIMEINFO *(*GetTime) (VOID);
        ULONG(*GetRelativeTime) (VOID);
        LONG(*GetDirectoryEntry) (ULONG, DIRECTORYENTRY *, ULONG, ULONG *);
        LONG(*Open) (CHAR *, OPENMODE, ULONG *);
        LONG(*Close) (ULONG);
        LONG(*Read) (ULONG, VOID *, ULONG, ULONG *);
        LONG(*GetReadStatus) (ULONG);
        LONG(*Write) (ULONG, VOID *, ULONG, ULONG *);
        LONG(*Seek) (ULONG, LARGEINTEGER *, SEEKMODE);
        LONG(*Mount) (CHAR *, MOUNTOPERATION);
        CHAR *(*GetEnvironmentVariable) (CHAR *);
        LONG(*SetEnvironmentVariable) (CHAR *, CHAR *);
        LONG(*GetFileInformation) (ULONG, FILEINFORMATION *);
        LONG(*SetFileInformation) (ULONG, ULONG, ULONG);
        VOID(*FlushAllCaches) (VOID);
        LONG(*TestUnicodeCharacter) (ULONG, USHORT);
        DISPLAY_STATUS *(*GetDisplayStatus) (ULONG);
} FIRMWAREVECTOR;
printf()とかputc()とかはどこ?

ファイルディスクリプタ0, 1でread(), write()するとコンソールと会話出来るらしい。
その名前はSTDIN, STDOUTとなっていて、この考え方はUNIXと同じ。

#define ARC_STDIN       0
#define ARC_STDOUT      1

static FILE arc_stdin = ARC_STDIN;
FILE *stdin = &arc_stdin;

static FILE arc_stdout = ARC_STDOUT;
FILE *stdout = &arc_stdout;

LONG ArcWrite(ULONG FileID, VOID * Buffer, ULONG N, ULONG * Count)
{
        return FVector->Write(FileID, Buffer, N, Count);
}

int fputs(const char *s, FILE * stream)
{
        LONG status;
        ULONG count;

        if (strlen(s) > 0) {
                status = ArcWrite(*stream, (char *) s, strlen(s), &count);
                if ((status != ESUCCESS) || (count != strlen(s)))
                        return EOF;
        }
        return 0;
}

int puts(const char *s)
{
        int status = fputs(s, stdout);

        if (status != EOF)
                status = fputs("\n\r", stdout);
        return status;
}
64bitについて

そもそもファームウェアから64bit空間にあり、それがロードするELFも恐らく64bitのみなのだろう。
arcloadもN64 ABIでコンパイルされている。
ARC APIも当然N64 Calling conventionなんだろう。
ここに32bitなカーネルを持ち込むには、恐らくarcloadをELF32対応させ、32bitカーネルの中でARC APIを話す時だけ64bitモードに入ってFirmware Vectorへアクセスして、、ってやらにゃいかんかな。
という事情があって、NetBSD/sgimipsは現状動かない訳だが。