diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/boot/veneer | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/boot/veneer')
31 files changed, 11796 insertions, 0 deletions
diff --git a/private/ntos/boot/veneer/makefile b/private/ntos/boot/veneer/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/boot/veneer/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/boot/veneer/makefile.inc b/private/ntos/boot/veneer/makefile.inc new file mode 100644 index 000000000..b90118411 --- /dev/null +++ b/private/ntos/boot/veneer/makefile.inc @@ -0,0 +1,64 @@ +# +# Copyright (c) 1995,1996 FirePower Systems, Inc. +# +# $RCSfile: makefile.inc $ +# $Revision: 1.9 $ +# $Date: 1996/07/02 20:32:24 $ +# $Locker: $ +# + +!IFNDEF LANGUAGE +LANGUAGE=usa +!ENDIF + +!IFDEF NotNow +msg.rc msg.h msg00001.bin: msg.$(LANGUAGE) + mc -v msg.$(LANGUAGE) +!ENDIF + +!IF $(PPC) + +!IFDEF NotNow +obj\$(TARGET_DIRECTORY)\veneer.res: msg.$(LANGUAGE) +!ENDIF + +!IFNDEF DDKBUILDENV + +VENEER=obj\$(TARGET_DIRECTORY)\veneer.lib + +obj\$(TARGET_DIRECTORY)\veneer.exe: $(VENEER) makefile.inc + -link -out:obj\$(TARGET_DIRECTORY)\veneer.exe -nodefaultlib @<< +-machine:$(TARGET_DIRECTORY) +-rom +-BASE:0x50000 +-debug:notmapped +-debugtype:coff +-map:obj\$(TARGET_DIRECTORY)\veneer.map +-align:0x200 +-entry:start +obj\$(TARGET_DIRECTORY)\veneer.lib +$(BASEDIR)\public\sdk\lib\$(TARGET_DIRECTORY)\int64.lib +<<NOKEEP + + + -@binplace obj\$(TARGET_DIRECTORY)\veneer.exe + +!ELSE +# +# This is for building within a DDK environment... +# +VENEER=$(BASEDIR)\lib\$(CPU)\$(DDKBUILDENV)\veneer.lib + +$(TARGETPATH)\$(TARGET_DIRECTORY)\veneer.exe: $(VENEER) makefile.inc + -link -out:$(TARGETPATH)\$(TARGET_DIRECTORY)\veneer.exe -nodefaultlib -machine:ppc -rom -BASE:0x50000 -debug:notmapped -debugtype:coff -map:obj\ppc\veneer.map -align:0x200 -entry:start $(VENEER) $(BASEDIR)\lib\$(TARGET_DIRECTORY)\$(DDKBUILDENV)\int64.lib +# -@binplace -d .. $(TARGETPATH)\$(TARGET_DIRECTORY)\veneer.exe + +$(VENEER): obj\$(CPU)\$(DDKBUILDENV)\veneer.lib + -copy obj\$(CPU)\$(DDKBUILDENV)\veneer.lib $(VENEER) + +!ENDIF # End of else clause covering ddk build environment case + +verno.c: $(MAIN_PPC_SOURCES) + +!ENDIF # End of IF $(PPC) clause + diff --git a/private/ntos/boot/veneer/ppc/pxcache.s b/private/ntos/boot/veneer/ppc/pxcache.s new file mode 100644 index 000000000..74fea4e71 --- /dev/null +++ b/private/ntos/boot/veneer/ppc/pxcache.s @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * + * $RCSfile: pxcache.s $ + * $Revision: 1.7 $ + * $Date: 1996/01/11 07:54:50 $ + * $Locker: $ + * + * Derived from: + * Source: halfire/ppc/pxcache.s + * Revision: 1.6 + * Date: 1995/04/17 21:17:37 + */ + +//++ +// +// Copyright (c) 1993, 1994, 1995 IBM Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxcache.s +// +// Abstract: +// +// This module implements the routines to flush cache on the PowerPC. +// +// Author: +// +// Peter L. Johnston (plj@vnet.ibm.com) September 1993 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 27-Dec-93 plj Added 603 support. +// 13-Mar-94 plj Fixed problem introduced during switch to pas, +// added 604 support. +// 18-Jan-95 plj Add 603+, 604+ and 620 support. +// +//-- + +#include "kxppc.h" + +//++ +// +// HalpSweepPhysicalRangeInBothCaches +// +// Force data in a given PHYSICAL address range to memory and +// invalidate from the block in the instruction cache. +// +// This implementation assumes a block size of 32 bytes. It +// will still work on the 620. +// +// Arguments: +// +// r.3 Start physical PAGE number. +// r.4 Starting offset within page. Cache block ALIGNED. +// r.5 Length (in bytes) +// +// Return Value: +// +// None. +// +//-- + + .set PAGE_SHIFT, 12 + + + LEAF_ENTRY(HalpSweepPhysicalRangeInBothCaches) + +// +// Starting physical address = (PageNumber << PAGE_SHIFT) | Offset +// + + rlwimi r.4, r.3, PAGE_SHIFT, 0xfffff000 + + addi r.5, r.5, 31 // bump length by block size - 1 + srwi r.5, r.5, 5 // get number of blocks + mflr r.0 // save return address + mtctr r.5 // set loop count + +// +// Interrupts MUST be disabled for the duration of this function as +// we use srr0 and srr1 which will be destroyed by any exception or +// interrupt. +// + + DISABLE_INTERRUPTS(r.12,r.11) // r.11 <- disabled MSR + // r.12 <- previous MSR +// +// Find ourselves in memory. This is needed as we must disable +// both instruction and data translation. We do this while +// interrupts are disabled only to try to avoid changing the +// Link Register when an unwind might/could occur. +// +// The HAL is known to be in KSEG0 so its physical address is +// its effective address with the top bit stripped off. +// + + bl hspribc +hspribc: + + mflr r.6 // r.6 <- &hspribc + rlwinm r.6, r.6, 0, 0x7fffffff // r.6 &= 0x7fffffff + addi r.6, r.6, hspribc.real - hspribc + // r.6 = real &hspribc.real + + sync // ensure all previous loads and + // stores are complete. + + mtsrr0 r.6 // address in real space + + rlwinm r.11, r.11, 0, ~0x30 // turn off Data and Instr relocation + mtsrr1 r.11 + rfi // leap to next instruction + +hspribc.real: + mtsrr0 r.0 // set return address + mtsrr1 r.12 // set old MSR value + +hspribc.loop: +// XXX dcbst 0, r.4 // flush data block to memory + dcbf 0, r.4 // flush data block to memory + icbi 0, r.4 // invalidate i-cache + addi r.4, r.4, 32 // point to next block + bdnz hspribc.loop // jif more to do + + sync // ensure all translations complete + isync // don't even *think* about getting + // ahead. + rfi // return to caller and translated + // mode + + DUMMY_EXIT(HalpSweepPhysicalRangeInBothCaches) diff --git a/private/ntos/boot/veneer/ppc/pxutil.s b/private/ntos/boot/veneer/ppc/pxutil.s new file mode 100644 index 000000000..e4f5b5f2f --- /dev/null +++ b/private/ntos/boot/veneer/ppc/pxutil.s @@ -0,0 +1,62 @@ +//++ +// +// Copyright (c) 1995 FirePower Systems, Inc. +// +// $RCSfile: pxutil.s $ +// $Revision: 1.6 $ +// $Date: 1996/01/11 07:54:54 $ +// $Locker: $ +// +// Copyright (c) 1994 FirePower Systems, Inc. +// +// +// Module Name: +// +// pxutil.s +// +// +// Author: +// +// Shin Iwamoto at FirePower Systems, Inc. +// +// +// Revision History: +// 15-Sep-94 Shin Iwamoto at FirePower Systems, Inc. +// Changed passing argument. +// 06-Jul-94 Shin Iwamoto at FirePower Systems, Inc. +// Created. +// +//-- + +//++ +// +// Routine Description: +// +// PxInvoke +// +// This function is called by FwInvoke and runs in FwInvoke's context. +// That is, sp register isn't changed and link register is lost. +// +// +//-- + .text + + .globl ..PxInvoke +..PxInvoke: + + mtspr ctr,r3 // load ctr reg. with routine to call + + mr r3,r5 // move argc to 1st argument + mr r4,r6 // move argv to 2nd argument + mr r5,r7 // move envp to 3rd argument + bctr // jump to execute routine (no return) + + +// +// TOC entries +// + .reldata + .align 2 + .globl PxInvoke +PxInvoke: + .long ..PxInvoke,.toc diff --git a/private/ntos/boot/veneer/ppc/sources b/private/ntos/boot/veneer/ppc/sources new file mode 100644 index 000000000..8bfd468c9 --- /dev/null +++ b/private/ntos/boot/veneer/ppc/sources @@ -0,0 +1,36 @@ +# +# Copyright (c) 1995 FirePower Systems, Inc. +# +# $RCSfile: sources $ +# $Revision: 1.4 $ +# $Date: 1996/01/11 07:54:58 $ +# $Locker: $ +# + +MAIN_PPC_SOURCES=\ + vrmain.c \ + vrconfig.c \ + vrcons.c \ + vrcpiwrp.c \ + vrdumptr.c \ + vrenv.c \ + vrio.c \ + vrdisp.c \ + vrlib.c \ + vrmalloc.c \ + vrmemory.c \ + vrload.c \ + vrrstart.c \ + vrmisc.c \ + vrpehdr.c \ + vrsup.c \ + vrtree.c \ + ppc\vrstart.s \ + ppc\vrmp.s \ + ppc\pxcache.s \ + ppc\pxutil.s + +PPC_SOURCES=$(MAIN_PPC_SOURCES) \ + verno.c + +NTTARGETFILES=obj\*\veneer.exe diff --git a/private/ntos/boot/veneer/ppc/vrmp.s b/private/ntos/boot/veneer/ppc/vrmp.s new file mode 100644 index 000000000..f47b798c2 --- /dev/null +++ b/private/ntos/boot/veneer/ppc/vrmp.s @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1995 FirmWorks, Mountain View CA USA. All rights reserved. + * + * $RCSfile: vrmp.s $ + * $Revision: 1.5 $ + * $Date: 1996/06/20 16:30:16 $ + * $Locker: $ + */ + +#include "VrBAT.h" + +/* + * The PPC Open Firmware implementation uses a different protocol + * for MP startup than the ARC specification. In this module, + * we implement the ARC startup protocol. + * + * The PPC OF binding specifies that the /cpus node has + * a method cpu-machine-execute ( addr cpu# -- true | false ) + * where cpu# is the cpu number and addr is the address + * (in the parent's address space?) at which the cpu is to + * begin execution. + * + * The ARC specifies that a cpu is to spin on the state of the + * ProcessorStart bit in the BootStatus word of the cpu's Restart Block. + * When ProcessorStart = 1, the cpu switches context to that saved in + * the SaveArea array in the Restart Block. + * + * Define here the context switch routine and the polling loop. + */ + .data + .align 4 + .globl naperr +naperr: + .ascii "processor not sleeping" + + .text + .align 4 + .globl ..fatal + +/* + * VOID ArcPoll(VOID) + */ + .globl ArcPoll +ArcPoll: + /* + * We have to figure out where our BootStatus and SaveArea are. + * There's no way to explicitly pass variables to this routine, + * so our caller has helpfully stuffed them into locations + * ArcPoll-8 and ArcPoll-4. Retrieve them into r3 and r4. + * The pvr is initialized in ArcPoll-12. This is used by + * the IdleCPU() to check whether the machine is Multi processor + * worthy or not. The pvr should match for all proceesors and + * rev > 3.4 to be MP worthy + * Incidentally, we can trash all our registers as we won't + * ever return from this loop and this routine is not TOC-based. + */ + + bl here +here: + mfpvr r5 + mflr r1 // r1 = here + mr r4, r1 + stw r5, -16(r1) // store it before moving 0x1234 + li r2, 0x1234 + lwz r3, -12(r1) + stw r2, -12(r1) + mr r29, r1 // save off r1 for future use + lwz r1, -8(r1) + +cputest: + lwz r5, -12(r29) + cmplw r5, r2 // is still 1234 + beq cputest + li r2, 0xBAD + cmplw r5, r2 // is it bad to start this cpu + bne gonow +napnow: // put it to sleep + mfmsr r5 + li r2, 4 + rlwinm r2,r2,16,0,31 + or r5,r5,r2 + mtmsr r5 +// lis r3, (naperr>>16) +// ori r3, r3, napper + b ..fatal + +gonow: + // + // Turn off data/address translation ( I.E. go to real mode ) + // + bl RealMode + + /* + * Spin on the ProcessorStart bit (bit 23 in PPC nomenclature). + */ +ArcSpin: + lwz r2, 0(r3) + extrwi. r2, r2, 1, 23 + beq ArcSpin + + /* + * ProcessorStart is 1: reload processor state. + */ + li r2, 0x789a + stw r2, -12(r4) + + lwz r2, 0x104(r1) // CR0-7 + mtcrf 255, r2 + lwz r2, 0x108(r1) // XER + mtxer r2 + lwz r2, 0x110(r1) // IAR + lis r3, 0x8000 + andc r2, r2, r3 + mtlr r2 + + lwz r0, 0x84(r1) + // Get r1 later. + lwz r2, 0x8c(r1) + lwz r3, 0x90(r1) + lwz r4, 0x94(r1) + lwz r5, 0x98(r1) + lwz r6, 0x9c(r1) + lwz r7, 0xa0(r1) + lwz r8, 0xa4(r1) + lwz r9, 0xa8(r1) + lwz r10, 0xac(r1) + lwz r11, 0xb0(r1) + lwz r12, 0xb4(r1) + lwz r13, 0xb8(r1) + lwz r14, 0xbc(r1) + lwz r15, 0xc0(r1) + lwz r16, 0xc4(r1) + lwz r17, 0xc8(r1) + lwz r18, 0xcc(r1) + lwz r19, 0xd0(r1) + lwz r20, 0xd4(r1) + lwz r21, 0xd8(r1) + lwz r22, 0xdc(r1) + lwz r23, 0xe0(r1) + lwz r24, 0xe4(r1) + lwz r25, 0xe8(r1) + lwz r26, 0xec(r1) + lwz r27, 0xf0(r1) + lwz r28, 0xf4(r1) + lwz r29, 0xf8(r1) + lwz r30, 0xfc(r1) + lwz r31,0x100(r1) + + lwz r1, 0x88(r1) + blr + + +/* + * Goto real mode via a branch and link to this routine. We'll turn off + * data and instruction address translation and reset the program counter + * so the return from this routine leaves the cpu in real mode. + */ + .globl RealMode +RealMode: + mflr r20 + mfmsr r21 // get current state + rlwinm r21, r21, 0, ~EXTRNL_INT_ENABL // clear interrupt enable + mtmsr r21 // disable interrupts + rlwinm r21, r21, 0, ~(DATA_ADDR_XLATE | INSTR_ADDR_XLATE ) + mtsrr1 r21 // desired initial state + rlwinm r20, r20, 0, 0x7fffffff // physical return addrress + mtsrr0 r20 + rfi // return + + .globl EndArcPoll +EndArcPoll: diff --git a/private/ntos/boot/veneer/ppc/vrstart.s b/private/ntos/boot/veneer/ppc/vrstart.s new file mode 100644 index 000000000..5a934a1af --- /dev/null +++ b/private/ntos/boot/veneer/ppc/vrstart.s @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * Copyright (c) 1994 FirePower Systems Inc. + * + * $RCSfile: vrstart.s $ + * $Revision: 1.7 $ + * $Date: 1996/06/20 16:30:20 $ + * $Locker: $ + */ + + .text + .align 4 + + .globl start +start: + + /* + * We get control from the firmware here. + * As of 4/19/94, we're getting the following arguments: + * r1 initial stack pointer + * r2 zero (we must set up TOC) + * r3 reserved (residual data) + * r4 client program entry point + * r5 client interface handler + * r6 client program argument address + * r7 client program argument length + * + * Note that we're receiving all our arguments in registers; + * if we call C subroutines before calling main we'll + * have to save state...so it might not be best to use bzero() + * (unless we recode it in assembler). + */ + + /* + * XXX - We may need to remap ourselves. If so, that code goes here. + * XXX - Is bss zeroed? If not, do that here. + */ + + /* + * Set up the veneer's TOC pointer. + */ + + bl skip_toc + .word .toc +skip_toc: + mflr r2 + lwz r2, 0(r2) + + /* + * Now we know where we are. Store the cif_handler, find main, + * and jump to it. + */ + lwz r8, [toc]CifHandler(rtoc) + stw r5, 0(r8) + + .extern main + lwz r8, [toc]main(rtoc) + lwz r8, 0(r8) + mtspr ctr, r8 + bctrl // call main() + + /* + * We should never get back here. + */ + li r3, 0 + .extern OFExit + lwz r8, [toc]OFExit(rtoc) + lwz r8, 0(r8) + mtspr ctr, r8 + bctrl // call OFExit() + + /* + * We should NEVER get here. + */ + li r0, 0 + mtlr r0 + blr + + + + .globl ..VrGetProcRev +..VrGetProcRev: + mfpvr r.3 // get processor version + blr +..VrGetProcRev.end: + + + + .globl ..call_firmware +..call_firmware: + lwz r4, [toc]CifHandler(rtoc) + lwz r4, 0(r4) + mtspr ctr, r4 + bctr + + .globl ..get_toc +..get_toc: + mr r3, r2 + blr + + .reldata + .align 2 + .globl call_firmware +call_firmware: + .long ..call_firmware,.toc + .globl get_toc +get_toc: + .long ..get_toc,.toc + + .data + .align 4 +CifHandler: + .long 0 + + diff --git a/private/ntos/boot/veneer/proto.h b/private/ntos/boot/veneer/proto.h new file mode 100644 index 000000000..4685742bf --- /dev/null +++ b/private/ntos/boot/veneer/proto.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * + * $RCSfile: proto.h $ + * $Revision: 1.13 $ + * $Date: 1996/06/17 02:55:59 $ + * $Locker: $ + * + */ + +#define prl_t CM_PARTIAL_RESOURCE_LIST +#define prd_t CM_PARTIAL_RESOURCE_DESCRIPTOR + + // vrmain.c + +VOID VrMoveNode(PCONFIGURATION_NODE, PCONFIGURATION_NODE, + PCONFIGURATION_NODE, CONFIGURATION_CLASS, CONFIGURATION_TYPE); +LONG claimreal(PVOID, ULONG); + + // vrmemory.c + +PMEMORY_DESCRIPTOR +VrGetMemoryDescriptor( PMEMORY_DESCRIPTOR MemoryDescriptor ); +VOID VrCreateMemoryDescriptors( VOID ); +VOID VrMemoryInitialize( VOID ); +VOID DisplayMemory(VOID); + + // vrdisp.c + +PARC_DISPLAY_STATUS VrGetDisplayStatus( ULONG FileId ); +ARC_STATUS VrTestUnicodeCharacter( ULONG FileId, WCHAR UnicodeCharacter ); +VOID VrDisplayInitialize( VOID ); + + // vrconsole.c + +PCHAR VrFindConsolePath(char *console); + + // vrlib.c + +#if defined(_M_PPC) && defined(_MSC_VER) && (_MSC_VER>=1000) +#pragma function(strcmp) +#pragma function(strlen) +#pragma function(strcpy) +#pragma function(strcat) +#endif + +int get_bool_prop(phandle, char *); +int decode_int(UCHAR *); +int get_int_prop(phandle node, char *key); +reg * decode_reg(UCHAR *buf, int buflen, int addr_cells, int size_cells); +reg * get_reg_prop(phandle node, char *key, int index); +char * get_str_prop(phandle node, char *key, allocflag alloc); +int strcmp(const char *s, const char *t); +int strncmp(const char *s, const char *t, size_t len); +int strncasecmp(const char *s, const char *t, size_t len); +size_t strlen(const char *s); +char * strcpy(char *to, const char *from); +char * strcat(char *to, const char *from); +VOID bcopy(char *from, char *to, int len); +VOID bzero(char *cp, int len); +VOID * zalloc(int size); +VOID sleep(ULONG delay); +int claim(void *adr, int bytes); +VOID * alloc(int size, int align); +int atoi(char *s); +char * index(char *s, int c); +char * strcsep(char *s, const char sep); +char * strctok(char *s, const char sep); +char * capitalize(char *s); +VOID warn(char *fmt, ...); +VOID fatal(char *fmt, ... ); +VOID debug(int debug_level, char *fmt, ...); +VOID sprintf(char *, char *, ...); +VOID putchar(char c); +VOID puts(char *s); +VOID gets(char *inbuf); + + // vrconfig.c + +PCONFIGURATION_COMPONENT VrAddChild( PCONFIGURATION_COMPONENT Component, + PCONFIGURATION_COMPONENT NewComponent, PVOID ConfigurationData ); +ARC_STATUS VrDeleteComponent( PCONFIGURATION_COMPONENT Component ); +PCONFIGURATION_COMPONENT VrGetChild ( + PCONFIGURATION_COMPONENT Component ); +PCONFIGURATION_COMPONENT VrGetParent(PCONFIGURATION_COMPONENT Component); +PCONFIGURATION_COMPONENT VrGetPeer(PCONFIGURATION_COMPONENT Component); +PCONFIGURATION_COMPONENT VrGetComponent( PCHAR Path ); +ARC_STATUS VrGetConfigurationData ( PVOID ConfigurationData, + PCONFIGURATION_COMPONENT Component ); +ARC_STATUS VrSaveConfiguration( VOID ); +VOID VrConfigInitialize( VOID ); + + // vrio.c + +ARC_STATUS VrOpen( PCHAR OpenPath, OPEN_MODE OpenMode, PULONG FileId ); +ARC_STATUS VrClose( ULONG FileId ); +ARC_STATUS VrRead( ULONG FileId, PVOID Buffer, ULONG Length, PULONG Count ); +ARC_STATUS VrWrite( ULONG FileId, PVOID Buffer, ULONG Length, PULONG Count ); +ARC_STATUS VrMount( PCHAR MountPath, MOUNT_OPERATION Operation ); +ARC_STATUS VrSeek( ULONG FileId, PLARGE_INTEGER Offset, SEEK_MODE SeekMode ); +ARC_STATUS VrGetDirectoryEntry( ULONG FileId, PDIRECTORY_ENTRY Buffer, + ULONG Length, PULONG Count ); +ARC_STATUS VrGetFileInformation( ULONG FileId, PFILE_INFORMATION pFI ); +ARC_STATUS VrGetReadStatus( ULONG FileId ); +ARC_STATUS VrSetFileInformation( ULONG FileId, ULONG AttributeFlags, + ULONG AttributeMask ); +VOID VrIoInitialize( VOID ); + + + // vrcpiwrp.c + +phandle OFPeer(phandle device_id); +phandle OFChild(phandle device_id); +phandle OFParent(phandle device_id); +long OFGetproplen( phandle device_id, char *name ); +long OFGetprop( phandle device_id, char *name, char *buf, ULONG buflen ); +long OFNextprop( phandle device_id, char *name, char *buf ); +long OFSetprop( phandle device_id, char *name, char *buf, ULONG buflen ); +phandle OFFinddevice( char *devicename); +ihandle OFOpen( char *devicename); +void OFClose(ihandle id); +long OFRead( ihandle instance_id, PCHAR addr, ULONG len ); +long OFWrite( ihandle instance_id, PCHAR addr, ULONG len ); +long OFSeek( ihandle instance_id, ULONG poshi, ULONG poslo ); +ULONG OFClaim( PCHAR addr, ULONG size, ULONG align ); +VOID OFRelease( PCHAR addr, ULONG size ); +long OFPackageToPath( phandle device_id, char *addr, ULONG buflen ); +long OFInstanceToPath( ihandle ih, char *addr, ULONG buflen ); +phandle OFInstanceToPackage(ihandle ih); +long OFCallMethod( ULONG n_outs, ULONG n_ins, ULONG *outp, char *method, + ihandle id, ... ); +long OFInterpret( ULONG n_outs, ULONG n_ins, ULONG *outp, char *cmd, ... ); +ULONG OFMilliseconds( VOID ); +VOID OFBoot( char *bootspec ); +VOID OFEnter( VOID ); +VOID OFExit( VOID ); + + // vrtree.c + +void walk_obp( phandle node, CONFIGURATION_NODE *here, + CONFIGURATION_NODE *parent, CONFIGURATION_NODE *peer); + + // vrtrunk.c +VOID vr_dump_config_node(PCONFIGURATION_NODE); +prl_t * grow_prl(PCONFIGURATION_NODE node, int dev_specific); +CONFIGURATION_NODE *add_new_child( + CONFIGURATION_NODE *, char *, CONFIGURATION_CLASS, CONFIGURATION_TYPE); + + // vrload.c + +VOID VrCopyArguments( ULONG Argc, PCHAR Argv[] ); +ARC_STATUS VrGenerateDescriptor( PMEMORY_DESCRIPTOR MemoryDescriptor, + MEMORY_TYPE MemoryType, ULONG BasePage, ULONG PageCount ); +ARC_STATUS VrLoad( PCHAR ImagePath, ULONG TopAddress, PULONG EntryAddress, + PULONG LowAddress ); +ARC_STATUS VrInvoke( ULONG EntryAddress, ULONG StackAddress, ULONG Argc, + PCHAR Argv[], PCHAR Envp[] ); +ARC_STATUS VrExecute( PCHAR ImagePath, ULONG Argc, PCHAR Argv[], PCHAR Envp[] ); +VOID VrLoadInitialize( VOID ); + + // vrmalloc.c + +char * malloc(unsigned); +void free(char *); +int log2(int); + + + // vrdumptr.c + +VOID quick_dump_tree(PCONFIGURATION_NODE node); +VOID dump_tree(PCONFIGURATION_NODE node); +VOID DisplayConfig(PCONFIGURATION_COMPONENT); + + + // vrmisc.c + +PTIME_FIELDS VrGetTime( VOID ); +ULONG VrGetRelativeTime( VOID ); +VOID VrFlushAllCaches( VOID ); +VOID VrTimeInitialize( VOID ); + + // vrrstart.c + +VOID VrEnterInteractiveMode( VOID ); +PSYSTEM_ID VrGetSystemId( VOID ); +VOID VrPowerDown( VOID ); +VOID VrReboot( VOID ); +VOID VrRestart( VOID ); +VOID VrHalt( VOID ); +VOID VrRestartInitialize( VOID ); + + // vrsup.c + +PCONFIGURATION_NODE ArcPathToNode(PCHAR Path); +PCHAR NodeToArcPath(PCONFIGURATION_NODE node); +PCONFIGURATION_NODE PackageToNode(phandle ph); +PCONFIGURATION_NODE PathToNode(PCHAR path); +PCONFIGURATION_NODE InstanceToNode(ihandle ih); +phandle NodeToPackage(PCONFIGURATION_NODE node); +PCHAR NodeToPath(PCONFIGURATION_NODE node); +ihandle NodeToInstance(PCONFIGURATION_NODE node); +phandle FindNodeByType(char *); +ihandle OpenPackage( phandle ); + + // vrenv.c + +PCHAR VrGetEnvironmentVariable( PCHAR Variable ); +ARC_STATUS VrSetEnvironmentVariable( PCHAR Variable, PCHAR Value ); +VOID VrEnvInitialize( VOID ); + + // vrpehdr.c + +void *load_file(ihandle bootih); + + // vrstart.s + +int call_firmware(ULONG *); + + // pxcache.s + +VOID PSIFlushCache(VOID); +VOID PPCFlushAllCaches(VOID); diff --git a/private/ntos/boot/veneer/sources b/private/ntos/boot/veneer/sources new file mode 100644 index 000000000..9280ea3cb --- /dev/null +++ b/private/ntos/boot/veneer/sources @@ -0,0 +1,49 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation +Copyright (c) 1995 Motorola Corporation +Copyright (c) 1995 FirePower Systems, Inc. + +Module Name: + + Veneer sources. + +Abstract: + + +Author: + + $RCSfile: sources $ + $Revision: 1.5 $ + $Date: 1996/03/01 20:17:49 $ + $Locker: $ + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=bldr + +TARGETNAME=veneer +TARGETPATH=obj +TARGETTYPE=LIBRARY + +VENEER_VERSION=0x0 +VENEER_REVISION=0x9909 + +C_DEFINES=$(C_DEFINES) -D_NTSYSTEM_ -Dppc=1 -D$(CPU)=1 -D_$(CPU)_=1 -DVENEER_VERSION=$(VENEER_VERSION) -DVENEER_REVISION=$(VENEER_REVISION) + +# INCLUDES=..\..\inc +INCLUDES=$(BASEDIR)\private\ntos\inc + +!IFDEF DDKBUILDENV +INCLUDES=$(BASEDIR)\SRC\HAL\INC +!ENDIF + +CFLAGS= /W3 /Oxs /Zd -ZB64 + +!IF DEFINED (BUILTBY) +C_DEFINES=$(C_DEFINES) -DBUILTBY=$(BUILTBY) +!ENDIF + +SOURCES= + diff --git a/private/ntos/boot/veneer/veneer.h b/private/ntos/boot/veneer/veneer.h new file mode 100644 index 000000000..aae1b1d1c --- /dev/null +++ b/private/ntos/boot/veneer/veneer.h @@ -0,0 +1,287 @@ +/*++ + * + * Copyright (c) 1994,1996 FirePower Systems, Inc. + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * + * $RCSfile: veneer.h $ + * $Revision: 1.20 $ + * $Date: 1996/06/19 23:13:15 $ + * $Locker: $ + * + * + + +Module Name: + + veneer.h + +Abstract: + + This module contains the private data structures and procedure + prototypes for the veneer for the PowerPC NT. + + This module is specifically tailored for the PowerPro and PowerTop + systems. + +Author: + + A. Benjamin 9-May-1994 + +Revision History: + 20-Jul-94 Shin Iwamoto at FirePower Systems Inc. + Added VRDBG_LOAD. + 13-Jul-94 Shin Iwamoto at FirePower Systems Inc. + Added ReadAheadCount and ReadAheadBuffer[2] in FileTable. + 12-Jul-94 Shin Iwamoto at FirePower Systems Inc. + Added Delete and NetworkDevice flags in FILE_FLAGS. + + +--*/ + + +#ifndef _VENEER +#define _VENEER + +//---------------------------------------------------------------- +// +// Headers +// + +#include <windef.h> +#include "vrheader.h" +#include <arc.h> +#include <arccodes.h> +#include <stdarg.h> + +#ifdef putchar +# undef putchar +#endif +#ifdef puts +# undef puts +#endif + +//---------------------------------------------------------------- +// +// Define common macros.... +// + +//---------------------------------------------------------------- +// +// IEEE 1275-1994 definitions +// + +typedef long phandle; +typedef long ihandle; + +typedef struct { + long hi, lo; + long size; +} reg; + +//---------------------------------------------------------------- +// +// Global definitions and macros +// + +#define MAX_IDE_DEVICE 4 + +#ifdef BAT_MMU +#define CLAIM(BaseAddr, SizeOfImage) \ + claim(BaseAddr, SizeOfImage) +#else +#define CLAIM(BaseAddr, SizeOfImage) \ + claimreal(BaseAddr, SizeOfImage) +#endif + + +typedef enum { + NOALLOC, + ALLOC +} allocflag; + +#define new(t) (t *)zalloc(sizeof(t)); + +#ifdef islower +# undef islower +#endif +#define islower(c) (((c) >= 'a') && ((c) <= 'z')) + +#ifdef toupper +# undef toupper +#endif +#define toupper(c) (((c) - 'a') + 'A') + +// +// Current version and revision numbers. +// These values are in OSLoader specifications (3-49). +// +#define ARC_VERSION 2 +#define ARC_REVISION 0 + +// +// CPU type +// + +typedef enum { + PPC_UNKNOWN = 0, + PPC_601 = 1, + PPC_603 = 3, + PPC_604 = 4, + PPC_603E = 6, + PPC_604E = 9, + nPROCESSOR_TYPE +} PROCESSOR_TYPE; + + +// +// Definitions associated with ARC. +// +#define SYSTEM_BLOCK_SIGNATURE 0x53435241 +#define RSTB_SIGNATURE 0x42545352 + +// +// The current (1/95) PowerPC port requires a "MIPS kseg0"-like +// mapping which aliases 0x80000000 to 0x00000000. This macro, +// used by claim(), undoes the mapping. +// +#define MAP(x) ((ULONG)(x) & ~0x80000000) +#define UNMAP(x) ((ULONG)(x) | 0x80000000) + + +//---------------------------------------------------------------- +// +// Veneer data structures and declarations +// + +/* + * This data structure is intended to link the components of the ARC + * tree with the nodes of the OF tree. + */ +typedef struct _CONFIGURATION_NODE { + phandle OfPhandle; + CONFIGURATION_COMPONENT Component; + CM_PARTIAL_RESOURCE_LIST *ConfigurationData; + struct _CONFIGURATION_NODE *Peer, *Child, *Parent; + char *ComponentName; + int Wildcard; + char *WildcardAddrPath; +} CONFIGURATION_NODE, *PCONFIGURATION_NODE; + + +// +// Define the vendor specific entry point numbers. +// +typedef enum _VENDOR_ENTRY { + MaximumVendorRoutine + } VENDOR_ENTRY; + +// +// Define file table structure. +// +#define FILE_TABLE_SIZE 32 + +typedef struct _FILE_FLAGS { + ULONG Open : 1; + ULONG Read : 1; + ULONG Write : 1; + ULONG Delete : 1; + ULONG Device : 1; + ULONG Partition : 1; + ULONG DisplayDevice : 1; + ULONG RemovableDevice : 1; + ULONG NetworkDevice : 1; +} FILE_FLAGS, *PFILE_FLAGS; + +#define MAX_PATH_NAME_SIZE 128 + +typedef struct _FILE_TABLE_ENTRY { + ihandle IHandle; + FILE_FLAGS Flags; + LARGE_INTEGER Position; + PCHAR PathName; + LONG ReadAheadCount; + CHAR ReadAheadBuffer[2]; +} FILE_TABLE_ENTRY, *PFILE_TABLE_ENTRY; +extern FILE_TABLE_ENTRY FileTable[]; + +// +// Define the keyboard and mouse id strings. +// +#define KBD_IDENTIFIER "PCAT_ENHANCED" +#define MOUSE_IDENTIFIER "PS2 MOUSE" + + +//---------------------------------------------------------------- +// +// External/Global variable declarations +// + +extern int VrDebug; +extern CONFIGURATION_NODE *RootNode; +extern ihandle ConsoleIn, ConsoleOut; +extern BOOLEAN use_bat_mapping; + +//---------------------------------------------------------------- +// +// Function prototypes +// + +// +// Useful macros for pragma message, ie. #pragma message(REVIEW "some text") +// +#define QUOTE(x) #x +#define IQUOTE(x) QUOTE(x) +#define REVIEW __FILE__ "(" IQUOTE(__LINE__) ") : REVIEW -> " + +//---------------------------------------------------------------- +// +// Debugging definitions and macros +// + +#define STATIC static + +#define VRDBG_VR 0x00000001 // printout "ARC" interface activity. +#define VRDBG_OF 0x00000002 +#define VRDBG_TEST 0x00000004 +#define VRDBG_TREE 0x00000008 +#define VRDBG_MEM 0x00000010 +#define VRDBG_MAIN 0x00000020 +#define VRDBG_ENTRY 0x00000040 +#define VRDBG_PE 0x00000080 +#define VRDBG_CONF 0x00000100 +#define VRDBG_OPEN 0x00000200 +#define VRDBG_CONFIG 0x00000400 +#define VRDBG_LOAD 0x00000800 +#define VRDBG_RDWR 0x00001000 +#define VRDBG_ARGV 0x00002000 +#define VRDBG_ENV 0x00004000 // printout environment values and variables +#define VRDBG_DUMP 0x00008000 +#define VRDBG_HOLDIT 0x00010000 +#define SANDALFOOT 0x00020000 +//#define CDROMHACK 0x00040000 +#define VRDBG_TMP 0x00080000 +#define VRDBG_ARCDATA 0x00100000 +#define VRDBG_SCSI 0x00200000 // print out scsi node activity +#define VRDBG_IDE 0x00400000 // print out ide node activity +#define VRDBG_TIME 0x00800000 +#define VRDBG_ALL 0xffffffff + +#define VRASSERT(_exp) \ + if (!(_exp)) { \ + warn("Assertion Failure: line %d, File %s\n",\ + __LINE__, __FILE__); \ + warn("Veneer Assertion Failure:" #_exp "\n"); \ + ArcHalt();\ + } + +#define DBGSET(_value) ((_value)&(VrDebug)) +#define VRDBG(_value, _str) \ + { \ + if (DBGSET(_value)) { \ + _str; \ + } \ + } + +#include "proto.h" + +#endif // _VENEER diff --git a/private/ntos/boot/veneer/verno.c b/private/ntos/boot/veneer/verno.c new file mode 100644 index 000000000..0ed3e5fd8 --- /dev/null +++ b/private/ntos/boot/veneer/verno.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1995,1996 FirePower Systems, Inc. + * + * $RCSfile: verno.c $ + * $Revision: 1.15 $ + * $Date: 1996/06/08 00:59:34 $ + * $Locker: $ + */ + +#include "veneer.h" + +#define VENEER_MAJOR 3 +#define VENEER_MINOR 00 +#define __BLDSTAMP__ __DATE__ " - " __TIME__ + +#define SALUTATION "Open Firmware ARC Interface Version %d.%d (%s)\n" +#define VERSION "FirmWorks,ENG,%d.%d,%s,%s,GENERAL" + + +void +Salutation(void) +{ + warn(SALUTATION, VENEER_MAJOR, VENEER_MINOR, __BLDSTAMP__); +} + + +char * +VeneerVersion(void) +{ + static char buf[128]; + + sprintf(buf, VERSION, VENEER_MAJOR, VENEER_MINOR, __DATE__, __TIME__); + return (buf); +} diff --git a/private/ntos/boot/veneer/vrbat.h b/private/ntos/boot/veneer/vrbat.h new file mode 100644 index 000000000..696a7dede --- /dev/null +++ b/private/ntos/boot/veneer/vrbat.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1995 FirmWorks, Mountain View CA USA. All rights reserved. + * Copyright (c) 1996 FirePower, Inc. + * + * $RCSfile: vrbat.h $ + * $Revision: 1.2 $ + * $Date: 1996/01/16 18:05:24 $ + * $Locker: $ + */ + +#ifndef VRBAT_H +#define VRBAT_H + +/* + *********************************************************************** + * + * MSR bit definitions + * + *********************************************************************** + */ +#define INSTR_ADDR_XLATE 0x00000020 // Instruction Addr xlate +#define DATA_ADDR_XLATE 0x00000010 // Data Addr xlate +#define EXTRNL_INT_ENABL 0x00008000 // EE bit +#define PRIVILEDGES 0x00004000 // PR bit for supervisor/user + // mode. Setting this bit to 1 + // restricts access to user only +#define XCPT_LE_MODE 0x00010000 // take exceptions in little + // endian mode. +#define LITTLE_ENDIAN 0x00000001 // run little endian mode +#define MCHNE_CHK_EN 0x00001000 // Machine Check Enable +#define FLOAT_PNT_EN 0x00002000 + +/* +************************************************************************ +** +** Block Address Translation registers +** +************************************************************************ +*/ +// +// Here are defines for the UPPER 32 bit bat register: +// +#define PAGE_INDEX_BITS 0xfffe0000 +#define BEPI(x) ( x & PAGE_INDEX_BITS ) + +#define A_128K_BLOCK_SIZE 0x00000000 +#define A_256K_BLOCK_SIZE 0x00000004 +#define A_512K_BLOCK_SIZE 0x0000000c +#define A_1MEG_BLOCK_SIZE 0x0000001c +#define A_2MEG_BLOCK_SIZE 0x0000003c +#define A_4MEG_BLOCK_SIZE 0x0000007c +#define AN_8MEG_BLOCK_SIZE 0x000000fc +#define A_16MB_BLOCK_SIZE 0x000001fc +#define A_32MB_BLOCK_SIZE 0x000003fc +#define A_64MB_BLOCK_SIZE 0x000007fc +#define A_128M_BLOCK_SIZE 0x00000ffc +#define A_256M_BLOCK_SIZE 0x00001ffc + +#define SUPERVISOR_ONLY 0x00000002 +#define USER_ACCESS 0x00000001 + +// +// The Lower BAT Register +// +#define BRPN(x) ( (x >> 8) & PAGE_INDEX_BITS) + +// +// WIMG: VIMVENDERS BITS: +// +#define WRITE_THROUGH 0x00000040 +#define CACHE_INHIBIT 0x00000020 +#define MEMORY_COHRNCY 0x00000010 +#define GUARDED_BLOCK 0x00000008 // for IBAT use only.... + +#define PAGE_RW_ACCESS 0x00000002 +#define PAGE_RO_ACCESS 0x00000001 +#define PAGE_UNAVAILBL 0x00000000 + + +// +// define the special purpose register values for +// use with the "mfspr, mtspr" instructions +// +#define SDR1 25 +#define IBAT0_UPPER 528 +#define IBAT0_LOWER 529 +#define IBAT1_UPPER 530 +#define IBAT1_LOWER 531 +#define IBAT2_UPPER 532 +#define IBAT2_LOWER 533 +#define IBAT3_UPPER 534 +#define IBAT3_LOWER 535 + +#define DBAT0_UPPER 536 +#define DBAT0_LOWER 537 +#define DBAT1_UPPER 538 +#define DBAT1_LOWER 539 +#define DBAT2_UPPER 540 +#define DBAT2_LOWER 541 +#define DBAT3_UPPER 542 +#define DBAT3_LOWER 543 + +// +// data which written to the BAT's upper register +// will turn off it's translation abilities +// +#define INVALIDATE 0x00000000 +#define KSEG0 0x80000000 +#define LDW(x,y) addi x, 0, (y&0xffff) ;\ + addis x, 0, (y>>16) + +#endif //VRBAT_H diff --git a/private/ntos/boot/veneer/vrconfig.c b/private/ntos/boot/veneer/vrconfig.c new file mode 100644 index 000000000..e09fcd2c4 --- /dev/null +++ b/private/ntos/boot/veneer/vrconfig.c @@ -0,0 +1,567 @@ +/*++ + * + * Copyright (c) 1995 FirePower Systems, Inc. + * + * $RCSfile: vrconfig.c $ + * $Revision: 1.10 $ + * $Date: 1996/04/15 02:56:07 $ + * $Locker: $ + * + + +Module Name: + + vrconfig.c + +Abstract: + + This module contains the configuration functions. + +Author: + + A. Benjamin 2-May-1994 + +Revision History: +09-06-94 Shin Iwamoto at FirePower Systems Inc. + Added checking ConfigurationData in VrGetConfigurationData(). + Added checking Componet in VrGetParent() and VrGetPeer(). +09-01-94 Shin Iwamoto at FirePower Systems Inc. + Added to be an error if the ConfigurationDataLength field of + NewComponent is non-zero and the COnfigurationData parameter is null. +07-22-94 Shin Iwamoto at FirePower Systems Inc. + Added VrAddChild() and VrDeleteComponent(). +07-21-94 Shin Iwamoto at FirePower Systems Inc. + Moved the intialization of vector table for VrGetEnvironmentVariable + and VrGetMemoryDescriptor into vrenv.c. +07-20-94 Shin Iwamoto at FirePower Systems Inc. + Moved VrSystemInit() and VrNotYet() to vrmain.c and then + renamed VrSystemInit() with VrConfigInitialize() for only + initializing the vector table. + +--*/ + + +#include "veneer.h" + + +/* + * Name: VrAddChild + * + * Description: + * This function adds a new component entry as a child of Component, + * including an identifier string if the IdentifierLength field of + * NewComponent is non-zero, and configuration data if the + * ConfigurationDataLength field of NewComponent is non-zero and the + * ConfigurationData parameter is present. If Componet is NULL, + * the root component is being added. + * + * Arguments: + * Component - Supplies a pointer to a configuration component. + * NewComponent- Supplies a pointer to a new configuration component + * to be added as a child of Component. + * ConfigurationData - Supplies an optional pointer to a configuration + * data buffer. + * + * Return Value: + * Returns a pointer to the new configuration component entry. + * If the create operation was unsuccessful, NULL is returned. + * + */ +PCONFIGURATION_COMPONENT +VrAddChild( + IN PCONFIGURATION_COMPONENT Component, + IN PCONFIGURATION_COMPONENT NewComponent, + IN PVOID ConfigurationData OPTIONAL + ) +{ + PCONFIGURATION_NODE ConfNode; + PCONFIGURATION_NODE ChildNode; + PCONFIGURATION_NODE ParentNode; + + // + // If there is not enough space for the new component, retrun NULL. + // + ConfNode = new(CONFIGURATION_NODE); + if ((PCHAR) ConfNode == NULL) { + return (PCONFIGURATION_COMPONENT) NULL; + } + + // + // Fill in new configuration entry with Identifier and ConfigurationData. + // + bcopy((PCHAR)NewComponent, (PCHAR)&ConfNode->Component, + sizeof(CONFIGURATION_COMPONENT)); + if (NewComponent->IdentifierLength != 0) { + ConfNode->Component.Identifier = malloc(NewComponent->IdentifierLength); + if (ConfNode->Component.Identifier == NULL) { + ConfNode->Component.IdentifierLength = 0; + goto ErrorAddChild; + } + bcopy(NewComponent->Identifier, ConfNode->Component.Identifier, + NewComponent->IdentifierLength); + } else { + ConfNode->Component.Identifier = NULL; // For safety + } + + if (NewComponent->ConfigurationDataLength != 0) { + if (ConfigurationData == NULL) { + ConfNode->Component.ConfigurationDataLength = 0; + goto ErrorAddChild; + } + ConfNode->ConfigurationData = + (CM_PARTIAL_RESOURCE_LIST *) + malloc(NewComponent->ConfigurationDataLength); + + if (ConfNode->ConfigurationData == NULL) { + ConfNode->Component.ConfigurationDataLength = 0; + goto ErrorAddChild; + } + bcopy(ConfigurationData, (PCHAR)(ConfNode->ConfigurationData), + NewComponent->ConfigurationDataLength); + } + + // + // If Component is NULL and the new Class is system, the root component + // is being added, otherwise the new is added according to Component. + // + if ((Component == NULL) && (NewComponent->Class == SystemClass)) { + + // + // If the root component is being added, replace the root component. + // However, some information such as phandle are adhered. + // XXXX Is it Ok? + // + ConfNode->Peer = RootNode->Peer; + ConfNode->Child = RootNode->Child; + ConfNode->Parent = NULL; + ConfNode->OfPhandle = RootNode->OfPhandle; + RootNode = ConfNode; + + // + // The parent of the old parent's children is changed. + // + ChildNode = ConfNode->Child; + while(ChildNode != NULL) { + ChildNode->Parent = ConfNode; + ChildNode = ChildNode->Peer; + } + + } else { + if (Component == NULL) { + ParentNode = RootNode; + } else { + ParentNode = CONTAINING_RECORD(Component, + CONFIGURATION_NODE, + Component); + } + ConfNode->Peer = ParentNode->Child; + ParentNode->Child = ConfNode; + ConfNode->Child = NULL; + ConfNode->Parent = ParentNode; + ConfNode->OfPhandle = OFChild(ParentNode->OfPhandle); + if (!(ConfNode->OfPhandle)) { // This "can't happen." + goto ErrorAddChild; + } + } + + + return (&ConfNode->Component); + + + ErrorAddChild: + if (ConfNode->Component.IdentifierLength != 0) { + free(ConfNode->Component.Identifier); + } + if (ConfNode->Component.ConfigurationDataLength != 0) { + free((PVOID)ConfNode->ConfigurationData); + } + bzero((char *)ConfNode, sizeof(CONFIGURATION_NODE)); // For safety + free((char *) ConfNode); + return (PCONFIGURATION_COMPONENT) NULL; +} + + +/* + * Name: VrDeleteComponent + * + * Description: + * This function deletes a component entry. If the entry has one or more + * children, an error is returned, otherwise the entry is deleted. + * Deleting the entry will implicitly delete the identifier string and + * the configuration data. + * + * Arguments: + * Component - Supplies a pointer to a configuration component. + * + * Return Value: + * Returns ESUCCESS if the entry was successfully deleted, otherwise retunrs + * EINVAL or EACCES. + * + */ +ARC_STATUS +VrDeleteComponent( + IN PCONFIGURATION_COMPONENT Component + ) +{ + PCONFIGURATION_NODE ConfNode; + PCONFIGURATION_NODE SearchNode; + + if (Component == NULL) { + return EINVAL; + } + if (!(Component->Version == ARC_VERSION && + Component->Revision == ARC_REVISION)) { + return EINVAL; + } + + ConfNode = CONTAINING_RECORD(Component, + CONFIGURATION_NODE, + Component); + + // + // If Component's parent field is NULL, return EINVAL. + // + if (ConfNode->Parent == NULL) { + return EINVAL; + } + + // + // If Component has children, return EACCES. + // + if (ConfNode->Child != NULL) { + return EACCES; + } + + // + // Find the entry that points to Component, and point it to + // Components's peer. If this is Components's parent, update the child + // pointer, otherwise this is apeer and update the peer pointer. + // + SearchNode = ConfNode->Parent; + if (SearchNode->Child == ConfNode) { + SearchNode->Child = ConfNode->Peer; + } else { + SearchNode = SearchNode->Child; + while (SearchNode->Peer != ConfNode) { + SearchNode = SearchNode->Peer; + } + SearchNode->Peer = ConfNode->Peer; + } + + // + // Free Conponent with Identifier and ConfigurationData, if any. + // + if (ConfNode->Component.IdentifierLength != 0) { + free(ConfNode->Component.Identifier); + } + if (ConfNode->Component.ConfigurationDataLength != 0) { + free((PVOID)ConfNode->ConfigurationData); + } + bzero((char *)ConfNode, sizeof(CONFIGURATION_NODE)); // For safety + free((char *) ConfNode); + + return ESUCCESS; +} + + +/*++ + +Routine Description: + + The system configuration data structure is organized as a tree of + component structures. This function returns a pointer to the first + child of a configuration node. + + If Component is null, then a pointer to the root node is returned. + +Arguments: + + Component - pointer to a component structure. + +Return Value: + + Returns a pointer to the structure of the child of component + if one exists, otherwise it returns a null pointer. + +--*/ + +PCONFIGURATION_COMPONENT +VrGetChild ( + IN PCONFIGURATION_COMPONENT Component OPTIONAL + ) +{ + PCONFIGURATION_NODE OfLink; + + debug(VRDBG_VR, "VrGetChild: Entry - Component: %x\n", Component); + + if (Component == (PCONFIGURATION_COMPONENT)NULL) { + debug(VRDBG_VR, "VrGetChild: Root %x\n", &RootNode->Component); + return &RootNode->Component; + } + + OfLink = CONTAINING_RECORD(Component, + CONFIGURATION_NODE, + Component); + + if (OfLink->Child == NULL ) { + debug(VRDBG_VR, "VrGetChild: NULL\n"); + return NULL; + } else { + debug(VRDBG_VR, "VrGetChild: Child %x (%s)\n", + &OfLink->Child->Component, OfLink->Child->ComponentName); + return &OfLink->Child->Component; + } +} + +PCONFIGURATION_COMPONENT +VrGetParent(IN PCONFIGURATION_COMPONENT Component) +{ +PCONFIGURATION_NODE OfLink; + + debug(VRDBG_VR, "VrGetParent: Entry - Component: %x\n", Component); + + if (Component == NULL) { + return NULL; + } + if (!(Component->Version == ARC_VERSION && + Component->Revision == ARC_REVISION)) { + return NULL; + } + + OfLink = CONTAINING_RECORD(Component, + CONFIGURATION_NODE, + Component); + if (OfLink->Parent == NULL) { + debug(VRDBG_VR, "VrGetParent: Exit-1\n"); + return NULL; + } else { + debug(VRDBG_VR, "VrGetParent: Exit-2\n"); + return &OfLink->Parent->Component; + } +} + +PCONFIGURATION_COMPONENT +VrGetPeer(IN PCONFIGURATION_COMPONENT Component) +{ + PCONFIGURATION_NODE OfNode; + + debug(VRDBG_VR, "VrGetPeer: Entry - Component: %x\n", Component); + + if (Component == NULL) { + return NULL; + } + if (!(Component->Version == ARC_VERSION && + Component->Revision == ARC_REVISION)) { + return NULL; + } + + OfNode = CONTAINING_RECORD(Component, + CONFIGURATION_NODE, + Component); + if (OfNode->Peer == NULL ) { + debug(VRDBG_VR, "VrGetPeer: NULL\n"); + return NULL; + } else { + debug(VRDBG_VR, "VrGetPeer: Peer %x (%s)\n", + &OfNode->Peer->Component, OfNode->Peer->ComponentName); + return &OfNode->Peer->Component; + } +} + + +/*++ + GetComponent - This function returns a pointer to the component structure + that best matches the path string pointed to by Path. The search algorithm + searches for each component starting with the first and continues + until either the string has been exhausted or no component mathes the + string. + + BUBUG The spec. specifies the following two inconsistent return values + + 1. The function returns a pointer to the last successfully matched + component. + + 2. If the path is invalid or if a component structure does not + exist, this function returns a null pointer. +--*/ + +PCONFIGURATION_COMPONENT +VrGetComponent( + IN PCHAR Path + ) +{ + PCONFIGURATION_NODE Node; + + debug(VRDBG_VR, "VrGetComponent: Entry - Path: %s\n", Path); + + if (Node = ArcPathToNode(Path)) { + debug(VRDBG_VR, "VrGetComponent: Exit; found %x (%s)\n", + &Node->Component, Node->ComponentName); + return (&Node->Component); + } else { + debug(VRDBG_VR, "VrGetComponent: No match found!\n"); + return (NULL); + } +} + + +/*++ + +Routine Description: + + This functions returns the configuration data associated with Component + in the buffer supplied by ConfigurationData. The length of the data + is stored in the Component structure. + +Arguments: + + ConfigurationData - Supplies a pointer to a buffer to receive the + configuration data. + + Component - Supplies a pointer to a configuration component. + +Return Value: + + If the configuration data is successfully copied into the buffer + provided by ConfigurationData, ESUCCESS is returned. Otherwise one of + the following error codes is returned. + + EINVAL Component is not a valid configuration component, or the + configuration is invalid. + +--*/ + +ARC_STATUS +VrGetConfigurationData ( + OUT PVOID ConfigurationData, + IN PCONFIGURATION_COMPONENT Component + ) +{ + PCONFIGURATION_NODE Node; + ULONG DataSize; + + debug(VRDBG_VR, "VrGetConfigurationData: Entry - Config.Data: %x Comp.: %x\n", + ConfigurationData, Component); + + if (Component == NULL) { + return EINVAL; + } + DataSize = Component->ConfigurationDataLength; + + // + // check the passing parameters + // + if (DataSize == 0) { + return EINVAL; + } + + Node = CONTAINING_RECORD( Component, CONFIGURATION_NODE, Component ); + +#ifdef TOO_STRINGENT + // + // If Component's Parent field is NULL, return EINVAL. + // + if (Node->Parent == NULL) { + return EINVAL; + } + + // + // If the Component doesn't point to a valid configuration component, + // return EINVAL. + // + if (!(Node->ConfigurationData->Version == ARC_VERSION && + Node->ConfigurationData->Revision == ARC_REVISION)) { + return EINVAL; + } +#endif + + // + // Copy the data. + // + + bcopy((PCHAR)Node->ConfigurationData, ConfigurationData, DataSize); + + debug(VRDBG_VR, "VrGetConfigurationData: Exit; copied %d bytes from %x\n", + DataSize, Node->ConfigurationData); + + return ESUCCESS; +} + + +/* + * Name: VrSaveConfiguration + * + * Description: + * This function stores all of the configuration entries into NVRAM, + * including the associated identifier strings and configuration data. + * + * Arguments: + * None. + * + * Return Value: + * Returns ESUCCESS if thesave completed successfully, otherwise returns + * ENOSPC. + * + */ +ARC_STATUS +VrSaveConfiguration( + VOID + ) +{ + // + // Open Firmware doesn't batch the NVRAM writes; thus this always succeeds. + // + return ESUCCESS; +} + + +/*++ + +Routine Description: + + This routine initializes the firmware vector in the system parameter + block. + +Arguments: + + None. + + +Return Value: + + None. + +--*/ + +VOID +VrConfigInitialize( + VOID + ) +{ + debug(VRDBG_ENTRY, "VrConfigInitialize BEGIN....\n"); + (PARC_ADD_CHILD_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[AddChildRoutine] = VrAddChild; + + (PARC_DELETE_COMPONENT_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[DeleteComponentRoutine] = + VrDeleteComponent; + (PARC_GET_CHILD_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetChildRoutine] = VrGetChild; + + (PARC_GET_PARENT_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetParentRoutine] = VrGetParent; + + (PARC_GET_PEER_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetPeerRoutine] = VrGetPeer; + + (PARC_GET_DATA_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetDataRoutine] = + VrGetConfigurationData; + (PARC_GET_COMPONENT_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetComponentRoutine] = + VrGetComponent; + (PARC_SAVE_CONFIGURATION_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[SaveConfigurationRoutine] = + VrSaveConfiguration; + debug(VRDBG_ENTRY, "VrConfigInitialize ....END\n"); +} diff --git a/private/ntos/boot/veneer/vrcons.c b/private/ntos/boot/veneer/vrcons.c new file mode 100644 index 000000000..e28a188f6 --- /dev/null +++ b/private/ntos/boot/veneer/vrcons.c @@ -0,0 +1,55 @@ +/*++ + + Copyright (c) 1995 FirePower Systems, Inc. + + $RCSfile: vrcons.c $ + $Revision: 1.6 $ + $Date: 1996/02/17 00:34:54 $ + $Locker: $ + +Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + +Module Name: + + vrconsole.c + +--*/ + +#include "veneer.h" + +ihandle ConsoleIn = 0, ConsoleOut = 0; + +/* + * Look up either the stdin or stdout and return an NT path to + * the device. The console argument should be either "stdin" or + * "stdout". + */ + +PCHAR +VrFindConsolePath(char *console) +{ + phandle chosen; + ihandle console_ih; + PCONFIGURATION_NODE node; + + chosen = OFFinddevice("/chosen"); + console_ih = get_int_prop(chosen, console); + + if (console_ih == -1) { + return (NULL); + } + + if (strcmp(console, "stdin") == 0) { + ConsoleIn = console_ih; + } + if (strcmp(console, "stdout") == 0) { + ConsoleOut = console_ih; + } + + node = InstanceToNode(console_ih); + if (node == NULL) { + fatal("VrFindConsolePath: cannot locate %s node\n", console); + } + + return (NodeToArcPath(node)); +} diff --git a/private/ntos/boot/veneer/vrcpiwrp.c b/private/ntos/boot/veneer/vrcpiwrp.c new file mode 100644 index 000000000..dfd9d0461 --- /dev/null +++ b/private/ntos/boot/veneer/vrcpiwrp.c @@ -0,0 +1,525 @@ +/*++ + * + * Copyright (c) 1995 FirePower Systems, Inc. + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * + * $RCSfile: vrcpiwrp.c $ + * $Revision: 1.12 $ + * $Date: 1996/02/26 20:17:32 $ + * $Locker: $ + * + + + +Module Name: + + vrcpiwrp.c + +Abstract: + + This module implements the wrapper for the P1275 boot firmware client + program interface. There is a wrapper routine for each of the client + interface service. The wrapper routine constructs a client interface + argument array as illustraed in the figure below, places its address + in r3 and transfers control to the client interface handler. The + return address of the wrapper routine is placed in lr register. + + The Client interface handler performs the service specified in the + argument array and return to wrapper routine which in turn return + to the client program. The client interface handler places the return + value (success or failure) in %r3. + + + Layout of the argument array + + +--------------------------------------+ + | Name of the client interface service | + +--------------------------------------+ + | Number of input arguments | + +--------------------------------------+ + | Number of return values | + +--------------------------------------+ + | Input arguments (arg1, ..., argN) | + +--------------------------------------+ + | Returned values (ret1, ..., retN) | + +--------------------------------------+ + +Author: + + A. Benjamin 27-Apr-1994 + +Revision History: +07-20-94 Shin Iwamoto at FirePower Systems Inc. + Added OFBoot and OFEnter. + + +--*/ + + +#include "veneer.h" + +#define VR_CIF_HANDLER_IN 3 + +// +// Device tree routines +// + +// +// Peer() - This routines outputs the identifier(phandle) of the device node that is +// the next sibling of the specified device node. +// +// Inputs: +// phandle - identifier of a device node +// +// Outputs: +// sibling_phandle - identifier of the next sibling. +// Zero if there are no more siblings. +// + +// +// peer +// +phandle +OFPeer(phandle device_id) +{ + ULONG argarray[] = { (ULONG)"peer",1,1,0,0}; + argarray[VR_CIF_HANDLER_IN+0] = device_id; + if (call_firmware(argarray) != 0) { + return (phandle)0; + } + return ((phandle)argarray[VR_CIF_HANDLER_IN+1]); +} + +// +//child +// +phandle +OFChild(phandle device_id) +{ + ULONG argarray[] = { (ULONG)"child",1,1,0,0}; + argarray[VR_CIF_HANDLER_IN+0] = device_id; + if (call_firmware(argarray) != 0) { + return (phandle)0; + } + return ((phandle)argarray[VR_CIF_HANDLER_IN+1]); +} +// +// parent +// +phandle +OFParent(phandle device_id) +{ + ULONG argarray[] = { (ULONG)"parent",1,1,0,0}; + argarray[VR_CIF_HANDLER_IN+0] = device_id; + if (call_firmware(argarray) != 0) { + return (phandle)0; + } + return ((phandle)argarray[VR_CIF_HANDLER_IN+1]); +} +// +//getproplen +// +long +OFGetproplen( + phandle device_id, + char *name + ) +{ + ULONG argarray[] = { (ULONG)"getproplen",2,1,0,0,0}; + argarray[VR_CIF_HANDLER_IN+0] = (long)device_id; + argarray[VR_CIF_HANDLER_IN+1] = (long)name; + if (call_firmware(argarray) != 0) { + return (-1); + } + return (argarray[VR_CIF_HANDLER_IN+2]); +} +// +//getprop +// +long +OFGetprop( + phandle device_id, + char *name, + char *buf, + ULONG buflen + ) +{ + ULONG argarray[] = { (ULONG)"getprop",4,1,0,0,0,0,0}; + argarray[VR_CIF_HANDLER_IN+0] = (long)device_id; + argarray[VR_CIF_HANDLER_IN+1] = (long)name; + argarray[VR_CIF_HANDLER_IN+2] = (long)buf; + argarray[VR_CIF_HANDLER_IN+3] = buflen; + if (call_firmware(argarray) != 0) { + return (-1); + } + return (argarray[VR_CIF_HANDLER_IN+4]); +} +// +//nextprop +// +long +OFNextprop( + phandle device_id, + char *name, + char *buf + ) +{ + ULONG argarray[] = { (ULONG)"nextprop",3,1,0,0,0,0}; + argarray[VR_CIF_HANDLER_IN+0] = (long)device_id; + argarray[VR_CIF_HANDLER_IN+1] = (long)name; + argarray[VR_CIF_HANDLER_IN+2] = (long)buf; + if (call_firmware(argarray) != 0) { + return (-1); + } + return (argarray[VR_CIF_HANDLER_IN+3]); +} +// +//setprop +// +long +OFSetprop( + phandle device_id, + char *name, + char *buf, + ULONG buflen + ) +{ + ULONG argarray[] = { (ULONG)"setprop",4,1,0,0,0,0,0}; + argarray[VR_CIF_HANDLER_IN+0] = (long)device_id; + argarray[VR_CIF_HANDLER_IN+1] = (long)name; + argarray[VR_CIF_HANDLER_IN+2] = (long)buf; + argarray[VR_CIF_HANDLER_IN+3] = buflen; + if (call_firmware(argarray) != 0) { + return (-1); + } + return (argarray[VR_CIF_HANDLER_IN+4]); +} + +// +// finddevice +// +phandle +OFFinddevice( char *devicename) +{ + ULONG argarray[] = { (ULONG)"finddevice",1,1,0,0}; + + argarray[VR_CIF_HANDLER_IN+0] = (long)devicename; + if (call_firmware(argarray) != 0) { + return (phandle)0; + } + return ((phandle) argarray[VR_CIF_HANDLER_IN+1]); +} + +// +// open +// +ihandle +OFOpen( char *devicename) +{ + ULONG argarray[] = { (ULONG)"open",1,1,0,0}; + + debug(VRDBG_OF, "OFOpen('%s')\n", devicename); + argarray[VR_CIF_HANDLER_IN+0] = (long)devicename; + if (call_firmware(argarray) != 0) { + return (ihandle)0; + } + return ((ihandle) argarray[VR_CIF_HANDLER_IN+1]); +} + +// +// close +// +void +OFClose(ihandle id) +{ + ULONG argarray[] = { (ULONG)"close",1,1,0,0}; + argarray[VR_CIF_HANDLER_IN+0] = (long)id; + if (call_firmware(argarray) != 0) { + warn("OFClose(%x) failed\n", id); + } + +} +// +//read +// +long +OFRead( + ihandle instance_id, + PCHAR addr, + ULONG len + ) +{ + ULONG argarray[] = { (ULONG)"read",3,1,0,0,0,0}; + + argarray[VR_CIF_HANDLER_IN+0] = (long) instance_id; + argarray[VR_CIF_HANDLER_IN+1] = (ULONG)addr; + argarray[VR_CIF_HANDLER_IN+2] = len; + if (call_firmware(argarray) != 0) { + return (-1); + } + return (argarray[VR_CIF_HANDLER_IN+3]); +} +// +//write +// +long +OFWrite( + ihandle instance_id, + PCHAR addr, + ULONG len + ) +{ + ULONG argarray[] = { (ULONG)"write",3,1,0,0,0,0}; + + argarray[VR_CIF_HANDLER_IN+0] = (long) instance_id; + argarray[VR_CIF_HANDLER_IN+1] = (ULONG)addr; + argarray[VR_CIF_HANDLER_IN+2] = len; + if (call_firmware(argarray) != 0) { + return (-1); + } + return (argarray[VR_CIF_HANDLER_IN+3]); +} +// +// seek +// +long +OFSeek( + ihandle instance_id, + ULONG poshi, + ULONG poslo + ) +{ + ULONG argarray[] = { (ULONG)"seek",3,1,0,0,0,0}; + + argarray[VR_CIF_HANDLER_IN+0] = (long) instance_id; + argarray[VR_CIF_HANDLER_IN+1] = poshi; + argarray[VR_CIF_HANDLER_IN+2] = poslo; + if (call_firmware(argarray) != 0) { + return (-1); + } + return (argarray[VR_CIF_HANDLER_IN+3]); +} +// +// claim +// +ULONG +OFClaim( + PCHAR addr, + ULONG size, + ULONG align + ) +{ + ULONG argarray[] = { (ULONG)"claim",3,1,0,0,0,0}; + + argarray[VR_CIF_HANDLER_IN+0] = (ULONG)addr; + argarray[VR_CIF_HANDLER_IN+1] = size; + argarray[VR_CIF_HANDLER_IN+2] = align; + if (call_firmware(argarray) != 0) { + return (ULONG)0; + } + return (argarray[VR_CIF_HANDLER_IN+3]); +} +// +// release +// +VOID +OFRelease( + PCHAR addr, + ULONG size + ) +{ + ULONG argarray[] = { (ULONG)"release",2,0,0,0}; + argarray[VR_CIF_HANDLER_IN+0] = (ULONG)addr; + argarray[VR_CIF_HANDLER_IN+1] = size; + call_firmware(argarray); +} + +// +// package-to-path +// +long +OFPackageToPath( + phandle device_id, + char *addr, + ULONG buflen + ) +{ + ULONG argarray[] = { (ULONG)"package-to-path",3,1,0,0,0,0}; + + argarray[VR_CIF_HANDLER_IN+0] = (ULONG)device_id; + argarray[VR_CIF_HANDLER_IN+1] = (ULONG)addr; + argarray[VR_CIF_HANDLER_IN+2] = buflen; + if (call_firmware(argarray) != 0) { + return (-1); + } + return ((LONG)argarray[VR_CIF_HANDLER_IN+3]); +} + +// +// instance-to-path +// +long +OFInstanceToPath( + ihandle ih, + char *addr, + ULONG buflen + ) +{ + ULONG argarray[] = { (ULONG)"instance-to-path",3,1,0,0,0,0}; + + argarray[VR_CIF_HANDLER_IN+0] = (ULONG)ih; + argarray[VR_CIF_HANDLER_IN+1] = (ULONG)addr; + argarray[VR_CIF_HANDLER_IN+2] = buflen; + if (call_firmware(argarray) != 0) { + return (-1); + } + return ((LONG)argarray[VR_CIF_HANDLER_IN+3]); +} + +// +// instance-to-package +// +phandle +OFInstanceToPackage(ihandle ih) +{ + ULONG argarray[] = { (ULONG)"instance-to-package",1,1,0,0}; + + argarray[VR_CIF_HANDLER_IN+0] = (ULONG)ih; + if (call_firmware(argarray) != 0) { + return (-1); + } + return ((LONG)argarray[VR_CIF_HANDLER_IN+1]); +} + +// +// call-method +// +long +OFCallMethod( + ULONG n_outs, + ULONG n_ins, + ULONG *outp, + char *method, + ihandle id, + ... + ) +{ + ULONG *argarray, i; + va_list ins; + int res; + + argarray = (ULONG *) zalloc((n_ins + n_outs + 4) * sizeof(ULONG)); + argarray[0] = (ULONG) "call-method"; + argarray[1] = (ULONG) n_ins; + argarray[2] = (ULONG) n_outs + 1; + argarray[VR_CIF_HANDLER_IN+0] = (ULONG)method; + argarray[VR_CIF_HANDLER_IN+1] = (ULONG)id; + va_start(ins, id); + for (i = 2; i < n_ins; ++i) { + argarray[VR_CIF_HANDLER_IN+i] = va_arg(ins, ULONG); + } + va_end(ins); + + if ((res = call_firmware(argarray)) != 0) { + debug(VRDBG_OF, "OFCallMethod: call_firmware() != 0\n"); + return (-1); + } + debug(VRDBG_OF, "OFCallMethod: catch_res %x return %x\n", + argarray[VR_CIF_HANDLER_IN+n_ins], + argarray[VR_CIF_HANDLER_IN+n_ins+1]); + for (i = 0; i < n_outs; ++i) + outp[i] = argarray[VR_CIF_HANDLER_IN + n_ins + 1 + i]; + return ((LONG)argarray[VR_CIF_HANDLER_IN+n_ins]); +} + +// +// interpret +// +long +OFInterpret( + ULONG n_outs, + ULONG n_ins, + ULONG *outp, + char *cmd, + ... + ) +{ + ULONG *argarray, i; + va_list ins; + int res; + + argarray = (ULONG *) zalloc((n_ins + (n_outs + 1) + 3) * sizeof(ULONG)); + argarray[0] = (ULONG) "interpret"; + argarray[1] = (ULONG) n_ins; + argarray[2] = (ULONG) n_outs + 1; + argarray[VR_CIF_HANDLER_IN+0] = (ULONG)cmd; + va_start(ins, cmd); + for (i = 1; i < n_ins; ++i) { + argarray[VR_CIF_HANDLER_IN+i] = va_arg(ins, ULONG); + } + va_end(ins); + + if ((res = call_firmware(argarray)) != 0) { + debug(VRDBG_OF, "OFCallMethod: call_firmware() != 0\n"); + return (-1); + } + debug(VRDBG_OF, "OFCallMethod: catch_res %x return %x\n", + argarray[VR_CIF_HANDLER_IN+n_ins], + argarray[VR_CIF_HANDLER_IN+n_ins+1]); + for (i = 0; i < n_outs; ++i) + outp[i] = argarray[VR_CIF_HANDLER_IN + n_ins + 1 + i]; + return ((LONG)argarray[VR_CIF_HANDLER_IN+n_ins]); +} + +// +// milliseconds +// +ULONG +OFMilliseconds( VOID ) +{ + ULONG argarray[] = { (ULONG)"milliseconds",0,1,0}; + if (call_firmware(argarray) != 0) { + return (ULONG)0; + } + return (argarray[VR_CIF_HANDLER_IN+0]); +} + + +// +// boot +// +VOID +OFBoot( + char *bootspec + ) +{ + ULONG argarray[] = { (ULONG)"boot",1,0,0}; + + argarray[VR_CIF_HANDLER_IN+0] = (ULONG)bootspec; + call_firmware(argarray); +} + + +// +// enter +// +VOID +OFEnter( VOID ) +{ + ULONG argarray[] = { (ULONG)"enter",0,0}; + + call_firmware(argarray); +} + + +// +// exit +// +VOID +OFExit( VOID ) +{ + ULONG argarray[] = { (ULONG)"exit",0,0}; + + warn("Program complete - please reboot.\n"); + call_firmware(argarray); +} diff --git a/private/ntos/boot/veneer/vrdisp.c b/private/ntos/boot/veneer/vrdisp.c new file mode 100644 index 000000000..e158c677e --- /dev/null +++ b/private/ntos/boot/veneer/vrdisp.c @@ -0,0 +1,169 @@ +/* + * + * Copyright (c) 1995 FirePower Systems, Inc. + * + * $RCSfile: vrdisp.c $ + * $Revision: 1.7 $ + * $Date: 1996/04/15 02:56:02 $ + * $Locker: $ + * + * + * + * Module Name: + * vrdisp.c + * + * Author: + * Shin Iwamoto at FirePower Systems Inc. + * + * History: + * 16-Jun-94 Shin Iwamoto at FirePower Systems Inc. + * Returned always EINVAL in VrTestUnicodeCharacter(). + * 18-May-94 Shin Iwamoto at FirePower Systems Inc. + * Added for DispalDevice flag. + * Added some comments. + * 05-May-94 Shin Iwamoto at FirePower Systems Inc. + * Created roughly. + * + */ + + +#include "veneer.h" + + +// +// Static data. +// +STATIC ARC_DISPLAY_STATUS DisplayStatus = { + // + // Assume bold, (1), white, (7), foreground and blue, (4) + // background because the only known programs that use the + // "get current colors" feature is arcinst which uses white + // on blue. Anyway, every other Microsoft ARC client we have + // seen uses the same color scheme. + // + 0, 0, 80, 32, 7, 4, 1, 0, 0 +}; + + +/* + * Name: VrGetDisplayStatus + * + * Description: + * This function returns a pointer to a display status structure. + * + * Arguments: + * FileId - Supplies the file table index. + * + * Return Value: + * If the device associated with FileId is not a display device + * or is not a valid file descriptor, then return a null pointer. + * Otherwise, returns the display status structure. + * + */ +PARC_DISPLAY_STATUS +VrGetDisplayStatus( + IN ULONG FileId + ) +{ + PARC_DISPLAY_STATUS PDisplayStatus = &DisplayStatus; + phandle ph; + int lines; + + if (FileId == 1) { // stdout + ph = OFFinddevice("/chosen"); + lines = get_int_prop(ph, "stdout-#lines"); + if (lines != -1) { + PDisplayStatus->CursorMaxYPosition = lines; + } + return PDisplayStatus; + } + if (FileId >= FILE_TABLE_SIZE) { + return (PARC_DISPLAY_STATUS)NULL; + } + if (!(FileTable[FileId].Flags.Open == 1 + && FileTable[FileId].Flags.Write == 1)) { + + return (PARC_DISPLAY_STATUS)NULL; + } + if (FileTable[FileId].Flags.DisplayDevice != 1) { + return (PARC_DISPLAY_STATUS)NULL; + } + + ph = OFInstanceToPackage(FileTable[FileId].IHandle); + lines = get_int_prop(ph, "stdout-#lines"); + if (lines != -1) { + PDisplayStatus->CursorMaxYPosition = lines; + } + + return PDisplayStatus; +} + + +/* + * Name: VrTestUnicodeCharacter + * + * Description: + * This function tests whether or not the display driver associated + * with FileId is capable of rendering the Unicode character. + * + * Arguments: + * FileId - Supplies the file table index. + * UnicodeCharacter - Supplies the character to be tested. + * + * Return Value: + * + */ +ARC_STATUS +VrTestUnicodeCharacter( + IN ULONG FileId, + IN WCHAR UnicodeCharacter + ) +{ + if (FileId >= FILE_TABLE_SIZE) { + return EBADF; + } + if (!((FileTable[FileId].Flags.Open == 1) && + (FileTable[FileId].Flags.Write == 1))) { + + return EBADF; + } + if (FileTable[FileId].Flags.DisplayDevice != 1) { + return EBADF; + } + + // + // Open Firmware has not capability to render any Unicode character. + // But it supports 8-bit through. (Mr. Tooch said. '94.06.15) + // + return EINVAL; +} + + +/* + * Name: VrDisplayInitialize + * + * Description: + * This function initializes the Dispaly entry points in the firmware + * transfer vector. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrDisplayInitialize( + VOID + ) +{ + debug(VRDBG_ENTRY, "VrDisplayInitialize BEGIN.....\n"); + // + // Initialize the Display entry points in the firmware transfer vector. + // + (PARC_GET_DISPLAY_STATUS_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetDisplayStatusRoutine] = + VrGetDisplayStatus; + debug(VRDBG_ENTRY, "VrDisplayInitialize .....END\n"); +} diff --git a/private/ntos/boot/veneer/vrdumptr.c b/private/ntos/boot/veneer/vrdumptr.c new file mode 100644 index 000000000..fc789a72d --- /dev/null +++ b/private/ntos/boot/veneer/vrdumptr.c @@ -0,0 +1,212 @@ +/* + * + * Copyright (c) 1995 FirePower Systems, Inc. + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * + * $RCSfile: vrdumptr.c $ + * $Revision: 1.7 $ + * $Date: 1996/02/17 00:35:53 $ + * $Locker: $ + * + * + * + * Module Name: + * vrdumptr.c + * + * Author: + * Shin Iwamoto at FirePower Systems Inc. + * + * History: + * 11-May-94 Shin Iwamoto at FirePower Systems Inc. + * Created. + * + */ + + +#include "veneer.h" + +PCHAR +ClassTable[] = {"System", + "Processor", + "Cache", + "Adapter", + "Controller", + "Peripheral", + "Memory"}; +PCHAR +TypeTable[] = {"ArcSystem", + "CentralProcessor", + "FloatingPointProcessor", + "PrimaryIcache", + "PrimaryDcache", + "SecondaryIcache", + "SecondaryDcache", + "SecondaryCache", + "EisaAdapter", + "TcAdapter", + "ScsiAdapter", + "DtiAdapter", + "MultiFunctionAdapter", + "DiskController", + "TapeController", + "CdromController", + "WormController", + "SerialController", + "NetworkController", + "DisplayController", + "ParallelController", + "PointerController", + "KeyboardController", + "AudioController", + "OtherController", + "DiskPeripheral", + "FloppyDiskPeripheral", + "TapePeripheral", + "ModemPeripheral", + "MonitorPeripheral", + "PrinterPeripheral", + "PointerPeripheral", + "KeyboardPeripheral", + "TerminalPeripheral", + "OtherPeripheral", + "LinePeripheral", + "NetworkPeripheral", + "SystemMemory"}; +PCHAR +ResourceTypeTable[] + = {"CmResourceTypeNull", + "CmResourceTypePort", + "CmResourceTypeInterrupt", + "CmResourceTypeMemory", + "CmResourceTypeDma", + "CmResourceTypeDeviceSpecific"}; +PCHAR +ShareDispositionTable[] + = {"CmResourceShareUndetermined", + "CmResourceShareDeviceExclusive", + "CmResourceShareDriverExclusive", + "CmResourceShareShared"}; + +STATIC VOID DisplayConfData(PCM_PARTIAL_RESOURCE_DESCRIPTOR); + +VOID +quick_dump_tree(PCONFIGURATION_NODE node) +{ + PCONFIGURATION_COMPONENT P = &node->Component; + extern int level; + + if (P->IdentifierLength) { + debug(VRDBG_CONFIG, "%x %s %s(%d) [%s]\n", node, + TypeTable[P->Type], node->ComponentName, P->Key, + P->Identifier); + } else { + debug(VRDBG_CONFIG, "%x %s %s(%d)\n", node, + TypeTable[P->Type], node->ComponentName, P->Key); + } + + if (node->Child) { + ++level; + quick_dump_tree(node->Child); + --level; + } + if (node->Peer) { + quick_dump_tree(node->Peer); + } +} + +VOID +dump_tree(PCONFIGURATION_NODE node) +{ + debug(VRDBG_DUMP, "\n"); + debug(VRDBG_DUMP, "dump_tree %x '%s'\n", node, node->ComponentName); + debug(VRDBG_DUMP, "\tparent '%s' peer '%s' child '%s'\n", + node->Parent ? node->Parent->ComponentName : "", + node->Peer ? node->Peer->ComponentName : "", + node->Child ? node->Child->ComponentName : ""); + DisplayConfig(&node->Component); + + if (node->Child) { + dump_tree(node->Child); + } + if (node->Peer) { + dump_tree(node->Peer); + } +} + +VOID +DisplayConfig( + PCONFIGURATION_COMPONENT P + ) +{ + PCM_PARTIAL_RESOURCE_LIST ConfList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR ConfData; + int count; + + warn("\tClass=%s, Type=%s, Key=0x%x, Flags=0x%x\n", + ClassTable[P->Class], TypeTable[P->Type], P->Key, P->Flags); + warn( + "\tVersion=%d, Revision=%d, AffinityMask=0x%x\n", + P->Version, P->Revision, P->AffinityMask); + warn("\tIdentifierLength=%d, Identifier='%s'\n", + P->IdentifierLength, + P->IdentifierLength ? P->Identifier : ""); + + count = P->ConfigurationDataLength; + warn("\tConfLen=%d\n", count); + if (count == 0) { + return; + } + + ConfList = + (PCM_PARTIAL_RESOURCE_LIST)malloc(count); + if (VrGetConfigurationData(ConfList, P)) { + free((char *) ConfList); + return; + } + + warn("\tVersion=%d, Revision=%d, Count=%d\n", + ConfList->Version, ConfList->Revision, ConfList->Count); + if (ConfList->Version == 1 && ConfList->Revision == 0) { + // pre-803 releases + free((char *) ConfList); + return; + } + count = ConfList->Count; + ConfData = ConfList->PartialDescriptors; + while (count-- > 0) { + warn( + "\t\tType=%s\n\t\tShareDesposition=%s\n\t\tFlags=0x%x", + ResourceTypeTable[ConfData->Type], + ShareDispositionTable[ConfData->ShareDisposition], + ConfData->Flags); + if (ConfData->Type == CmResourceTypeDeviceSpecific) { + int len = ConfData->u.DeviceSpecificData.DataSize; + int *data = (int *) ((char *) ConfData + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + warn(" Data length=%d", len); + while (len > 0) { + warn( "\n\t\t%x %x %x", *data, *(data+1), *(data+2)); + len -= 3 * sizeof(int); + data += 3; + } + ConfData += 1; + (char *) ConfData = (char *) ConfData + len; + warn("\n"); + } else { + warn( "\n\t\t%x %x %x\n", ConfData->u.Dma.Channel, + ConfData->u.Dma.Port, ConfData->u.Dma.Reserved1); + ConfData += 1; + } + } + free((char *) ConfList); +} + +STATIC VOID +DisplayConfData( + PCM_PARTIAL_RESOURCE_DESCRIPTOR P + ) +{ + warn("\nType=%s, ShareDesposition=%s, Flags=0x%x\n", + ResourceTypeTable[P->Type], + ShareDispositionTable[P->ShareDisposition], P->Flags); +} diff --git a/private/ntos/boot/veneer/vrenv.c b/private/ntos/boot/veneer/vrenv.c new file mode 100644 index 000000000..5f8a4a9e3 --- /dev/null +++ b/private/ntos/boot/veneer/vrenv.c @@ -0,0 +1,254 @@ +/*++ + * + * Copyright (c) 1994 FirePower Systems, Inc. + * Copyright (c) 1995 FirePower Systems, Inc. + * + * $RCSfile: vrenv.c $ + * $Revision: 1.13 $ + * $Date: 1996/06/19 23:13:26 $ + * $Locker: $ + * + + +Module Name: + + vrenv.c + +Abstract: + + This module contains environment variable functions. + +Author: + + A. Benjamin 9-May-1994 + +Revision History: +08-08-94 Shin Iwamoto at FirePower Systems Inc. + Made OptionsPhandle global static, and set the vales + in VrEnvInitialize. +07-21-94 Shin Iwamoto at FirePower Systems Inc. + Added VrEnvInitialize(). + +--*/ + + +#include "veneer.h" +#define MAX_ARGC 16 +#define MAX_ENVC 16 + +extern char *VrArgv[MAX_ARGC], *VrEnvp[MAX_ENVC]; +STATIC phandle OptionsPhandle = 0; +STATIC VOID VrEnvOpen(VOID); +PCHAR FindInLocalEnv( PCHAR Variable ); +PCHAR ConvertToUpper( PCHAR Orig ); +PCHAR GetEnvVar( PCHAR Variable ); +PCHAR VrCanonicalName( IN PCHAR Variable); + +PCHAR +VrCanonicalName( + IN PCHAR Variable + ) +{ + static char CanonicalName[32]; + + if (strlen(Variable) > 31) { + fatal( + "Veneer: Environment variable name %s is longer than 31 characters\n", + Variable); + } + strcpy(CanonicalName, Variable); + return (capitalize(CanonicalName)); +} + +/* + * + * ROUTINE: VrGetEnvironmentVariable( PCHAR Variable ) + * + * DESCRIPTION: + * Exported Interface to an arc program. This routine will check + * the environment passed to the program for the variable before calling + * back into the firmware. Since ARC enforces no case sensitivity on + * variables, this routine will force all variables to upper case before + * checking the local environment. + * + */ + +PCHAR +VrGetEnvironmentVariable( + IN PCHAR Variable + ) +{ + PCHAR Value = NULL; + + + debug(VRDBG_ENV, "VrGetEnvironmentVariable: Entry - Variable: '%s'\n", + Variable ? Variable : "NULL"); + + if ((Value = FindInLocalEnv(Variable)) == NULL) { + Value = GetEnvVar(Variable); + } + + debug(VRDBG_ENV, "VrGetEnvironmentVariable: Exit '%s'\n", + Value ? Value : "NULL"); + return Value; +} + + +ARC_STATUS +VrSetEnvironmentVariable( + IN PCHAR Variable, + IN PCHAR Value + ) +{ + long retval; + + debug(VRDBG_ENV, + "VrSetEnvironmentVariable: Entry - Variable: '%s' Value '%s'\n", + Variable, Value); + + if (OptionsPhandle == 0) { + VrEnvOpen(); + } + retval = OFSetprop(OptionsPhandle, VrCanonicalName(Variable), + Value, strlen(Value)); + retval = (retval != (long) strlen(Value)); + + debug(VRDBG_ENV, "VrGetEnvironmentVariable: Exit '%s'\n", retval); + return retval; +} + + +/* + * Name: VrEnvInitialize + * + * Description: + * This function initializes the Environment entry points in the firmware + * transfer vector and the file table. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrEnvInitialize(VOID) +{ + // + // Initialize the I/O entry points in the firmware transfer vector. + // + debug(VRDBG_ENTRY, "VrEnvInitialize: BEGIN......\n"); + (PARC_GET_ENVIRONMENT_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetEnvironmentRoutine] + = VrGetEnvironmentVariable; + (PARC_SET_ENVIRONMENT_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[SetEnvironmentRoutine] + = VrSetEnvironmentVariable; + debug(VRDBG_ENTRY, "VrEnvInitialize: .....END\n"); +} + +/* + * Name: VrEnvOpen + * + * Description: + * This function gets the phandle for the Open Firmware options node + * so that Open Firmware configuration variables can be later accessed. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +STATIC VOID +VrEnvOpen(VOID) +{ + OptionsPhandle = OFFinddevice("/options"); + if (OptionsPhandle == 0) { + fatal("Veneer: Cannot access /options\n"); + } +} + +/* + * ROUTINE: FindInLocalEnv( PCHAR Variable ) + * + * DESCRIPTION: + * Force the passed in variable to upper case, check the local environ- + * ment array for this variable and return it's contents if found. Assume + * that the environment array is all upper case, at least for the key. + * + * RETURN: + * returns a pointer to data of type CHAR. Null if no var found. + */ + +PCHAR +FindInLocalEnv( + IN PCHAR Variable + ) +{ + PCHAR Value = NULL; + PCHAR alpha; + ULONG count=0,i=0; + + // + // set the incoming variable to all upper case... + // + alpha = VrCanonicalName(Variable); + debug(VRDBG_ENV, "FindInLocalEnv: Entry - Variable: '%s'\n",alpha); + + // + // Run through the VrEnvp array looking for a match. Since the VrEnvp + // array should all be upper case values, we shouldn't need to worry + // about case. + // + while( VrEnvp[count] && *(VrEnvp[count]) ){ + + // Compare the capitalized version of the Variable passed in with + // each entry in the VrEnvp array for a length equal to the Variable + // less the null terminator. + // + if (!strncmp(VrEnvp[count], alpha, (strlen(alpha)-1))) { + // we've found our match. Now return pointer to this value + return(VrEnvp[count]+strlen(alpha)); + } + + // + // reset and try again + // + count++; + } + + // + // if we fall out of the loop, it's because we didn't match anything. + // + return((PCHAR)NULL); +} + +/* + * ROUTINE: GetEnvVar( PCHAR Variable ) + * + * DESCRIPTION: + * This call is an internal only call that actually delves into the + * OpenFirmware to retrieve a value. + * + * RETURN: + * returns a pointer to data of type CHAR. Null if no var found. The + * returned value is the contents of the variable found. + */ +PCHAR +GetEnvVar( + IN PCHAR Variable + ) +{ + PCHAR Value = NULL; + + debug(VRDBG_ENV, "GetEnvVar: Entry - Variable: '%s'\n",Variable); + if (OptionsPhandle == 0) { + VrEnvOpen(); + } + Value= get_str_prop(OptionsPhandle, VrCanonicalName(Variable), NOALLOC); + return Value; +} + diff --git a/private/ntos/boot/veneer/vrheader.h b/private/ntos/boot/veneer/vrheader.h new file mode 100644 index 000000000..8f757bb1e --- /dev/null +++ b/private/ntos/boot/veneer/vrheader.h @@ -0,0 +1,325 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * + * $RCSfile: vrheader.h $ + * $Revision: 1.10 $ + * $Date: 1996/01/11 08:03:25 $ + * $Locker: $ + * + */ + +/* + * From nt/public/sdk/inc/ntdef.h + */ + +// +// Physical address. +// + +typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; + +// +// Cardinal Data Types [0 - 2**N-2) +// + +typedef char CCHAR; // winnt +typedef short CSHORT; +typedef ULONG CLONG; + +typedef CCHAR *PCCHAR; +typedef CSHORT *PCSHORT; +typedef CLONG *PCLONG; + + + +/* + * From nt/public/sdk/inc/ntconfig.h + */ + +// +// Defines the Type in the RESOURCE_DESCRIPTOR +// + +typedef enum _CM_RESOURCE_TYPE { + CmResourceTypeNull = 0, // Reserved + CmResourceTypePort, + CmResourceTypeInterrupt, + CmResourceTypeMemory, + CmResourceTypeDma, + CmResourceTypeDeviceSpecific, + CmResourceTypeMaximum +} CM_RESOURCE_TYPE; + +// +// Defines the ShareDisposition in the RESOURCE_DESCRIPTOR +// + +typedef enum _CM_SHARE_DISPOSITION { + CmResourceShareUndetermined = 0, // Reserved + CmResourceShareDeviceExclusive, + CmResourceShareDriverExclusive, + CmResourceShareShared +} CM_SHARE_DISPOSITION; + +// +// Define the bit masks for Flags when type is CmResourceTypeInterrupt +// + +#define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0 +#define CM_RESOURCE_INTERRUPT_LATCHED 1 + +// +// Define the bit masks for Flags when type is CmResourceTypeInterrupt +// + +#define CM_RESOURCE_MEMORY_READ_WRITE 0 +#define CM_RESOURCE_MEMORY_READ_ONLY 1 +#define CM_RESOURCE_MEMORY_WRITE_ONLY 2 + +// +// Define the bit masks for Flags when type is CmResourceTypePort +// + +#define CM_RESOURCE_PORT_MEMORY 0 +#define CM_RESOURCE_PORT_IO 1 + + +// +// This structure defines one type of resource used by a driver. +// +// There can only be *1* DeviceSpecificData block. It must be located at +// the end of all resource descriptors in a full descriptor block. +// + +// +// BUGBUG Make sure alignment is made properly by compiler; otherwise move +// flags back to the top of the structure (common to all members of the +// union). +// + +#pragma pack(4) +typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR { + UCHAR Type; + UCHAR ShareDisposition; + USHORT Flags; + union { + + // + // Range of port numbers, inclusive. These are physical, bus + // relative. The value should be the same as the one passed to + // HalTranslateBusAddress(). + // + + struct { + PHYSICAL_ADDRESS Start; + ULONG Length; + } Port; + + // + // IRQL and vector. Should be same values as were passed to + // HalGetInterruptVector(). + // + + struct { + ULONG Level; + ULONG Vector; + ULONG Affinity; + } Interrupt; + + // + // Range of memory addresses, inclusive. These are physical, bus + // relative. The value should be the same as the one passed to + // HalTranslateBusAddress(). + // + + struct { + PHYSICAL_ADDRESS Start; // 64 bit physical addresses. + ULONG Length; + } Memory; + + // + // Physical DMA channel. + // + + struct { + ULONG Channel; + ULONG Port; + ULONG Reserved1; + } Dma; + + // + // Device Specific information defined by the driver. + // The DataSize field indicates the size of the data in bytes. The + // data is located immediately after the DeviceSpecificData field in + // the structure. + // + + struct { + ULONG DataSize; + ULONG Reserved1; + ULONG Reserved2; + } DeviceSpecificData; + } u; +} CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR; +#pragma pack() + +// +// A Partial Resource List is what can be found in the ARC firmware +// or will be generated by ntdetect.com. +// The configuration manager will transform this structure into a Full +// resource descriptor when it is about to store it in the regsitry. +// +// Note: There must a be a convention to the order of fields of same type, +// (defined on a device by device basis) so that the fields can make sense +// to a driver (i.e. when multiple memory ranges are necessary). +// + +typedef struct _CM_PARTIAL_RESOURCE_LIST { + USHORT Version; + USHORT Revision; + ULONG Count; + CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1]; +} CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST; + +// +// Define the structures used to interpret configuration data of +// \\Registry\machine\hardware\description tree. +// Basically, these structures are used to interpret component +// sepcific data. +// + +// +// Define DEVICE_FLAGS +// + +typedef struct _DEVICE_FLAGS { + ULONG Failed : 1; + ULONG ReadOnly : 1; + ULONG Removable : 1; + ULONG ConsoleIn : 1; + ULONG ConsoleOut : 1; + ULONG Input : 1; + ULONG Output : 1; +} DEVICE_FLAGS, *PDEVICE_FLAGS; + +// +// Define Component Information structure +// + +typedef struct _CM_COMPONENT_INFORMATION { + DEVICE_FLAGS Flags; + ULONG Version; + ULONG Key; + ULONG AffinityMask; +} CM_COMPONENT_INFORMATION, *PCM_COMPONENT_INFORMATION; + + +/* + * From nt/public/sdk/inc/ntppc.h + */ + +#define KSEG0_BASE 0x00000000 /* ? 0x800000000 */ + + +/* + * From nt/private/ntos/inc/nthal.h + */ + +// +// Time conversion routines +// + +typedef struct _TIME_FIELDS { + CSHORT Year; // range [1601...] + CSHORT Month; // range [1..12] + CSHORT Day; // range [1..31] + CSHORT Hour; // range [0..23] + CSHORT Minute; // range [0..59] + CSHORT Second; // range [0..59] + CSHORT Milliseconds;// range [0..999] + CSHORT Weekday; // range [0..6] == [Sunday..Saturday] +} TIME_FIELDS; +typedef TIME_FIELDS *PTIME_FIELDS; + +// +// PowerPC page size = 4 KB +// + +#define PAGE_SIZE (ULONG)0x1000 + +// +// Define the number of trailing zeroes in a page aligned virtual address. +// This is used as the shift count when shifting virtual addresses to +// virtual page numbers. +// + +#define PAGE_SHIFT 12L + +// +// The device data record for the Floppy peripheral. +// + +typedef struct _CM_FLOPPY_DEVICE_DATA { + USHORT Version; + USHORT Revision; + CHAR Size[8]; + ULONG MaxDensity; + ULONG MountDensity; + // + // New data fields for version >= 2.0 + // + UCHAR StepRateHeadUnloadTime; + UCHAR HeadLoadTime; + UCHAR MotorOffTime; + UCHAR SectorLengthCode; + UCHAR SectorPerTrack; + UCHAR ReadWriteGapLength; + UCHAR DataTransferLength; + UCHAR FormatGapLength; + UCHAR FormatFillCharacter; + UCHAR HeadSettleTime; + UCHAR MotorSettleTime; + UCHAR MaximumTrackValue; + UCHAR DataTransferRate; +} CM_FLOPPY_DEVICE_DATA, *PCM_FLOPPY_DEVICE_DATA; + +// +// The device data record for the serial controller. +// + +typedef struct _CM_SERIAL_DEVICE_DATA { + USHORT Version; + USHORT Revision; + ULONG BaudClock; +} CM_SERIAL_DEVICE_DATA, *PCM_SERIAL_DEVICE_DATA; + +/* +******************************************************************************** +** +** The following is derived from fparch.h in the nthals\halfire\ppc +** directory +** +** +** +******************************************************************************** +*/ +// +// These names are not sacrosanct, and should be revised upon input from Susan, +// Jim, and anyone else interested. +// +enum scope_use { + ENG, + MFG, + TEST, + CUST + }; + +enum rel_state { + GENERAL, + OFFICIAL, + TESTING, + CONTROLLED, + LAB + }; + + diff --git a/private/ntos/boot/veneer/vrio.c b/private/ntos/boot/veneer/vrio.c new file mode 100644 index 000000000..c0a1bd2ae --- /dev/null +++ b/private/ntos/boot/veneer/vrio.c @@ -0,0 +1,1425 @@ +/* + * + * Copyright (c) 1995 FirePower Systems, Inc. + * Copyright (c) 1994 FirePower Systems Inc. + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * + * $RCSfile: vrio.c $ + * $Revision: 1.9 $ + * $Date: 1996/04/15 02:55:53 $ + * $Locker: $ + * + * + * Module Name: + * vrio.c + * + * Author: + * Shin Iwamoto at FirePower Systems Inc. + * + * History: + * 26-Sep-94 Shin Iwamoto at FirePower Systems Inc. + * Added checking SeekMode in VrSeek(). + * 15-Sep-94 Shin Iwamoto at FirePower Systems Inc. + * Added saving the area pointed to by OpenPath in VrOpen(). + * 15-Jul-94 Shin Iwamoto at FirePower Systems Inc. + * Added for XXX_SEEK_IS_BUSTED in VrSeek(). + * 14-Jul-94 Shin Iwamoto at FirePower Systems Inc. + * Added ONE_IO_SIZE in VrRead() and VrWrite(). + * 13-Jul-94 Shin Iwamoto at FirePower Systems Inc. + * Added ENOSPC checking in VrWrite(). + * Added for reading ahead in VrGetReadStatus() and VrRead(). + * 11-Jul-94 Shin Iwamoto at FirePower Systems Inc. + * Added some debugging facilities in VrOpen. These were + * from checked-in veneer source code. + * 16-Jun-94 Shin Iwamoto at FirePower Systems Inc. + * Added when a serial device doesn't read in VrRead(). + * 15-Jun-94 Shin Iwamoto at FirePower Systems Inc. + * When OpenPath inclues console, the path is for a device. + * So, FilePath was set to null. + * 13-Jun-94 Shin Iwamoto at FirePower Systems Inc. + * Added debugging statements. + * Modified some porting from Mike Tooch at FirmWorks. + * 18-May-94 Shin Iwamoto at FirePower Systems Inc. + * Added for unsinged long size in VrWrite. + * Added a part of VrMount. + * Added that DirectoryFile flag is ignored in + * VrSetFileInformation(). + * Added for Delete flag in FileTable in + * VrRead(), VrWrite(), VrSeek(), VrGetReadStatus() + * Added some comments. + * and VrSetFileInformation(). + * 17-May-94 Shin Iwamoto at FirePower Systems Inc. + * Added for NetworkDevice in GetDeviceAttribute(). + * Added for unsinged long size in VrRead. + * 12-May-94 Shin Iwamoto at FirePower Systems Inc. + * Changed the name, strlen and strncmp to + * VfStrlen and VfStrncmp. + * 11-May-94 Shin Iwamoto at FirePower Systems Inc. + * Added FIleTable. Changed rootnode to RootNode. + * Put cast PCAHR to the first parameter of bzero. + * Changed OFPhandle to OfPhandle. + * Changed the name of VrFindCOnfigurationNode. + * 10-May-94 Shin Iwamoto at FirePower Systems Inc. + * Changed Vr{Open|Close|Read|Write|Seek} because of + * changing the file table structure. + * 05-May-94 Shin Iwamoto at FirePower Systems Inc. + * Created. + * + */ + + +#include "veneer.h" + +// +// Some switches +// + +#define MAX_OPEN_PATH_SIZE MAX_PATH_NAME_SIZE +#define ONE_IO_SIZE 1024*1024 + +#define ZERO_LARGE 0 +#define NOT_ZERO_LARGE 1 + +#define Minimum(X,Y) ((X) < (Y) ? (X) : (Y)) + + +// +// File Table definition +// +FILE_TABLE_ENTRY FileTable[FILE_TABLE_SIZE]; + + +// +// Function declarations +// +STATIC ARC_STATUS +GetFileTableEntry( + OUT PULONG + ); +STATIC ARC_STATUS +GetDeviceAttribute( + IN ULONG, + IN PCONFIGURATION_NODE + ); +STATIC VOID +AddLargeInt( + PLARGE_INTEGER, + PLARGE_INTEGER + ); +STATIC VOID +MoveLargeInt( + PLARGE_INTEGER, + PLARGE_INTEGER + ); +STATIC LONG +IsLarge( + PLARGE_INTEGER + ); +STATIC VOID +DecrementLarge( + PLARGE_INTEGER + ); + + + +/* + * Name: VrOpen + * + * Description: + * This function opens the file specified by OpenPath. + * The pathname is translated into the devicename for Open Firmware, + * then OFOpen is called with the devicename. + * + * Arguments: + * OpenPath - ARC compliant pathname of the device/file to be opened. + * OpenMode - Supplies the mode in which the file is opened. + * FileId - Pointer to a variable that receives the fileid for + * this pathname. + * + * Return Value: + * If the file is successfully opened returns ESUCCESS otherwise + * returns an unsuccessful status. + * + */ +ARC_STATUS +VrOpen( + IN PCHAR OpenPath, + IN OPEN_MODE OpenMode, + OUT PULONG FileId + ) +{ + PCHAR FilePath, DevicePath, Partition, Console; + ihandle IHandle; + ARC_STATUS Status; + PCONFIGURATION_NODE ConfNode; + PCHAR pstr1; + LONG DevSpecLen; + + debug(VRDBG_OPEN, "VrOpen: Entry - Path: %s Mode: %x\n", + OpenPath, OpenMode); + + if (strlen(OpenPath) >= MAX_OPEN_PATH_SIZE) { + debug(VRDBG_OPEN, "VrOpen: ENAMETOOLONG: '%s'\n", OpenPath); + return ENAMETOOLONG; + } + + // + // Find Partition, Console and FilePath in OpenPath. + // + FilePath = NULL; + Partition = NULL; + Console = NULL; + for (pstr1 = OpenPath; *pstr1; pstr1++) { + if (strncmp(pstr1, "partition", 9) == 0) { + Partition = pstr1; + while (*pstr1++ != ')') { + ; + } + FilePath = pstr1; + break; + } else if (strncmp(pstr1, "console", 7) == 0) { + Console = pstr1; + while (*pstr1++ != ')') { + ; + } + if (*pstr1 != '\0') { + return EINVAL; + } + FilePath = NULL; // Console is a device. + break; + } + else if (*pstr1 == ')') { + FilePath = pstr1+1; + } + } + // + // Did we eventually wind up with a FilePath after all? + // + if ((FilePath != NULL) && (strlen(FilePath) == 0)) { + FilePath = NULL; + } + debug(VRDBG_OPEN, "VrOpen: Partition '%s' FilePath '%s'\n", + Partition == NULL ? "NULL" : Partition, + FilePath == NULL ? "NULL" : FilePath); + + // + // Check open mode for a device. + // + if ((FilePath == NULL) && (OpenMode > ArcOpenReadWrite)) { + debug(VRDBG_OPEN, "VrOpen: EINVAL: '%s'\n", OpenPath); + return EINVAL; + } + + // + // Extract the device name from OpenPath. + // + ConfNode = ArcPathToNode(OpenPath); + if (ConfNode == NULL) { + debug(VRDBG_OPEN, "VrOpen: ENODEV: '%s'\n", OpenPath); + return ENODEV; + } + + // + // Translate the device name into the device path for Open Firmware. + // Add space for the partition and file components. + // + pstr1 = NodeToPath(ConfNode); + DevSpecLen = strlen(pstr1) + 16; // Enough for a partition specifier. + if (FilePath != NULL) { + DevSpecLen += strlen(FilePath); + } + DevicePath = zalloc(DevSpecLen); + strcpy(DevicePath, pstr1); + free(pstr1); + + // + // Get a free entry in the file table. + // + if (Status = GetFileTableEntry(FileId)) { + debug(VRDBG_OPEN, "VrOpen: GetFileTableEntry returned %x\n", Status); + return Status; + } + + // + // Set flags in the FileTable. + // + if (Status = GetDeviceAttribute(*FileId, ConfNode)) { + debug(VRDBG_OPEN, "VrOpen: GetDeviceAttribute returned %x\n", Status); + return Status; + } + + if ((Partition == NULL) && (FilePath == NULL)) { // A device (not file) + FileTable[*FileId].Flags.Device = 1; + strcat(DevicePath, ":0"); + } else { // A file (not a device) + // + // Convert the partition and the filename (if they exist) as follows: + // + // [partition(key1)][<filepath>] + // --> :[key1][,<filepath>] + // + strcat(DevicePath, ":"); + if (Partition != NULL) { + FileTable[*FileId].Flags.Partition = (FilePath == NULL); + pstr1 = Partition; + while (*pstr1++ != '(') { + ; + } + if (*pstr1 == ')') { + strcat(DevicePath, "0"); + } else { + PCHAR pstr2; + + pstr2 = DevicePath + strlen(DevicePath); + do { + *pstr2++ = *pstr1++; + } while (*pstr1 != ')'); + *pstr2 = '\0'; + } + } + if (FilePath != NULL) { + strcat(DevicePath, ","); + strcat(DevicePath, FilePath); + } + } + + // + // Now we can open the device path (including the file path). + // + IHandle = OFOpen(DevicePath); + debug(VRDBG_OPEN, "OFOpen: IHandle: %x\n", IHandle); + FileTable[*FileId].PathName = DevicePath; + + // + // Checking related to OpenMode. + // + switch (OpenMode) { + case ArcCreateWriteOnly: + case ArcCreateReadWrite: + if (IHandle != 0) { + (VOID)OFClose(IHandle); + return EACCES; + } + break; + default: + if (IHandle == 0) { + return EIO; + } + } + + FileTable[*FileId].Flags.Open = 1; + FileTable[*FileId].IHandle = IHandle; + + debug(VRDBG_OPEN, "VrOpen: Exit - FileId: %d IHandle: %x\n", + *FileId, IHandle); + + return ESUCCESS; +} + + +/* + * Name: VrClose + * + * Description: + * This function closes a file or a device if it is opened. + * + * Arguments: + * FileId - Supplies the file table index. + * + * Return Value: + * If the specified file is open, then a close is attempted via + * OFClose and ESUCCESS is returned. Otherwise, return an unsuccessful + * status. + * + */ +ARC_STATUS +VrClose( + IN ULONG FileId + ) +{ + debug(VRDBG_OPEN, "VrClose: Entry - FileId: %d\n", FileId); + + if (FileId >= FILE_TABLE_SIZE) { + return EBADF; + } + if (FileTable[FileId].Flags.Open != 1) { + return EACCES; + } + + // + // Close the file. + // + (VOID)OFClose(FileTable[FileId].IHandle); + + // + // Release the file table entry. + // + // FileTable[FileId].Flags.Open = 0; + bzero((PCHAR)&FileTable[FileId], sizeof(FILE_TABLE_ENTRY)); + free(FileTable[FileId].PathName); + + debug(VRDBG_OPEN, "VrClose: Exit\n"); + + return ESUCCESS; +} + + +/* + * Name: VrRead + * + * Description: + * This function reads data from the device of file specified by FileId + * into the buffer pointed to by Buffer. + * + * Arguments: + * FileId - Supplies the file table index. + * Buffer - Supplies a pointer to the buffer that receives the read + * data. + * Length - Supplies the maximum number of bytes to be read. + * If this field contains the value zero, then no bytes + * are read. + * Count - Supplies a pointer to a variable that receives the number + * of bytes actually transfered. + * + * Return Value: + * If the specified file is open for read, then a read is attempted + * and the status of the operation is retuned. Otherwise, return + * an unsuccessful status. + * + */ + +STATIC CHAR consin_readahead = 0; + +ARC_STATUS +VrRead( + IN ULONG FileId, + OUT PVOID Buffer, + IN ULONG Length, + OUT PULONG Count + ) +{ + LARGE_INTEGER LInteger; + PCHAR buf = (PCHAR) Buffer; + + if (FileId == 0) { // stdin + if (consin_readahead) { + *buf = consin_readahead; + consin_readahead = 0; + *Count = 1; + } else { + if (ConsoleIn == 0) { + (void) VrFindConsolePath("stdin"); + } + while (((LONG)*Count = OFRead(ConsoleIn, Buffer, Length)) <= 0){ + ; + } + } + return ESUCCESS; + } + + debug(VRDBG_RDWR, "VrRead: Entry - FileId: %d Buf: %x len: %d\n", + FileId, Buffer, Length); + + // + // If Length is zero, return as if the function were successful. + // + if (Length == 0) { + *Count = 0; + return ESUCCESS; + } + if (FileId == 1) { + return EBADF; + } + + if (FileId >= FILE_TABLE_SIZE) { + return EBADF; + } + if (!(FileTable[FileId].Flags.Open == 1 + && FileTable[FileId].Flags.Read == 1)) { + return EACCES; + } + if (FileTable[FileId].Flags.Delete == 1) { + return EACCES; + } + +#ifdef NO_UNSIGNED_LONG_IO + // + // Calls the read routine. + // + (LONG)*Count = OFRead(FileTable[FileId].IHandle, Buffer, Length); + if ((LONG)*Count == -1) { + return EIO; // XXXX + } + +#else // NO_UNSIGNED_LONG_IO + // + // Initialize Counter. + // + *Count = 0; + + // + // Checking read ahead buffer. If already read, the copy the buffer + // into Buffer. + // + if (FileTable[FileId].ReadAheadCount != 0) { + *Count = FileTable[FileId].ReadAheadCount; + bcopy(FileTable[FileId].ReadAheadBuffer, Buffer, *Count); + Buffer = (PCHAR)Buffer + *Count; + Length -= *Count; + FileTable[FileId].ReadAheadCount = 0; + } + + // + // Calls the read routine. + // + while (Length > 0) { + LONG SingleReadSize; + LONG ReadCount; + + SingleReadSize = Minimum(Length, ONE_IO_SIZE); + ReadCount = OFRead(FileTable[FileId].IHandle, Buffer, SingleReadSize); + if (ReadCount == -1) { + LONG Status; + + // + // If an error in the second or later read happes, + // the offset must be put back using OFSeek. + // In reading ahead, this is useful. + // + if (*Count != 0) { + Status = OFSeek(FileTable[FileId].IHandle, + FileTable[FileId].Position.HighPart, + FileTable[FileId].Position.LowPart); + // + // Ignore Status. + // + } + return EIO; // XXXX + } + + // + // Retry to read, when the device is serial and there is no data. + // + if ((ReadCount == -2) && (*Count == 0)) { + continue; + } + + // + // Update the number of bytes read successfully. + // + *Count += ReadCount; + + // + // If the device represented by FileId is a network device, + // read one time. If not yet read, continue. + // + if (FileTable[FileId].Flags.NetworkDevice == 1) { + if ((ReadCount == 0) && (*Count == 0)) { + continue; + } + return ESUCCESS; + } + + // + // Find EOF, then break this loop. + // + if (ReadCount < SingleReadSize) { + break; + } + + // + // Update the remaining length and the buffer to point to + // the next position. + // + Length -= SingleReadSize; + Buffer = (PCHAR)Buffer + SingleReadSize; + } +#endif // NO_UNSIGNED_LONG_IO + + // + // Calculates the position of the file. + // + LInteger.HighPart = 0; + LInteger.LowPart = *Count; + AddLargeInt(&FileTable[FileId].Position, &LInteger); + + debug(VRDBG_RDWR, "VrRead: Exit ReadCount: %d\n", *Count); + + return ESUCCESS; +} + + +/* + * Name: VrWrite + * + * Description: + * This function writes data from memory starting from the buffer + * pointed to by Buffer to the device specified by FileId. + * Upon completion of a successful write, the byte offset for FileId + * is updated; otherwise the byte offset is left unchanged. + * + * Arguments: + * FileId - Supplies the file table index. + * Buffer - Supplies a pointer to the buffer that contains + * the write data. + * Length - Supplies the number of bytes to be written. + * Count - Supplies a pointer to a variable that contains + * the number of bytes actually transfered. + * + * Return Value: + * If the specified file is open for write, then a write is attempted + * using OFWrite and a status is returned. Otherwise, return + * an unsuccessful status. + * + */ +ARC_STATUS +VrWrite( + IN ULONG FileId, + IN PVOID Buffer, + IN ULONG Length, + OUT PULONG Count + ) +{ + LARGE_INTEGER LInteger; + ARC_STATUS Status; + + if (FileId == 1) { // stdout + *Count = OFWrite(ConsoleOut, Buffer, Length); + return ESUCCESS; + } + + debug(VRDBG_RDWR, "VrWrite: Entry - FileId: %d Buf: %x len: %d\n", + FileId, Buffer, Length); + + // + // If Length is zero, return as if the function were successful. + // + if (Length == 0) { + *Count = 0; + return ESUCCESS; + } + if (FileId == 0) { + return EBADF; + } + + if (FileId >= FILE_TABLE_SIZE) { + return EBADF; + } + if (!(FileTable[FileId].Flags.Open == 1 + && FileTable[FileId].Flags.Write == 1)) { + return EACCES; + } + if (FileTable[FileId].Flags.Delete == 1) { + return EACCES; + } + + // + // If Length bytes cannot be placed into a network packet, + // return ENOSPC without sending the packet, placing the number of bytes + // that could be written in Count. + // + if (FileTable[FileId].Flags.NetworkDevice == 1) { + ULONG MaxFrameSize; + + MaxFrameSize = get_int_prop(OFFinddevice(FileTable[FileId].PathName), + "max-frame-size"); + if (Length > MaxFrameSize) { + *Count = MaxFrameSize; + return ENOSPC; + } + } + +#ifdef NO_UNSIGNED_LONG_IO + // + // Calls the write routine. + // + Status = ESUCCESS; + (LONG)*Count = OFWrite(FileTable[FileId].IHandle, Buffer, Length); + if ((LONG)*Count == -1) { + return EIO; // XXXX + } + +#else // NO_UNSIGNED_LONG_IO + + Status = ESUCCESS; + *Count = 0; + while (Length > 0) { + LONG SingleWriteSize; + LONG WriteCount; + + SingleWriteSize = Minimum(Length, ONE_IO_SIZE); + WriteCount = OFWrite(FileTable[FileId].IHandle, Buffer, + SingleWriteSize); + if (WriteCount == -1) { + LONG SeekStatus; + + // + // If an error in the second or later read happens, + // the offset must be put back using OFSeek. + // + if (*Count != 0) { + SeekStatus = OFSeek(FileTable[FileId].IHandle, + FileTable[FileId].Position.HighPart, + FileTable[FileId].Position.LowPart); + // + // Ignore Status. + // + } + return EIO; // XXXX + } + + // + // Update the number of bytes written successfully. + // + *Count += WriteCount; + + // + // If the device represented by FileId is a network device, + // write one time. If not yet written, continue. + // + if (FileTable[FileId].Flags.NetworkDevice == 1) { + if (WriteCount == 0) { + continue; + } + return ESUCCESS; + } + + // + // Find that the device is full. + // + if (WriteCount < SingleWriteSize) { + Status = ENOSPC; + break; + } + + // + // Update the remaining length and the buffer to point to + // the next position. + // + Length -= SingleWriteSize; + Buffer = (PCHAR)Buffer + SingleWriteSize; + } +#endif // NO_UNSIGNED_LONG_IO + + // + // Calculates the position of the file. + // + LInteger.HighPart = 0; + LInteger.LowPart = *Count; + AddLargeInt(&FileTable[FileId].Position, &LInteger); + + if (FileId >= 2) { + debug(VRDBG_RDWR, "VrWrite: Exit WrtCount: %d, Status: %d\n", + *Count, Status); + } + + return Status; +} + + +/* + * Name: VrMount + * + * Description: + * This function is used to load and unload media for devices that + * support removale media. + * + * Arguments: + * MountPath - Supplies a pointer to the variable that contains + * the path of the device. + * Operation - Supplies a indication whether the media is to be + * loaded or unloaded. + * + * Return Value: + * If the specified path is for device, then a mount is attempted + * a status is returned. Otherwise, return an unsuccessful status. + * + */ +ARC_STATUS +VrMount( + IN PCHAR MountPath, + IN MOUNT_OPERATION Operation + ) +{ + PCONFIGURATION_NODE ConfNode; + PCHAR FilePath, pstr1; + + debug(VRDBG_OPEN, "VrMount: Entry - MountPath: %s Operation: %d\n", + MountPath, Operation); + + // + // Check that the MountPath is a device. + // + FilePath = MountPath; + for (pstr1 = MountPath; *pstr1; pstr1++) { + if (strncmp(pstr1, "partition", 9) == 0) { + return EINVAL; + } else if (strncmp(pstr1, "console", 7) == 0) { + return EINVAL; + } else if (*pstr1 == ')') { + FilePath = pstr1+1; + } + } + if (FilePath == MountPath || FilePath[0] != '\0') { + return EINVAL; + } + + // + // Find the configuration node using the MountPath. + // + ConfNode = ArcPathToNode(MountPath); + if (ConfNode == NULL) { + return ENOENT; + } + + // + // Check that the device is removable. + // + if (!(ConfNode->Component.Flags.Removable)) { + return ENOENT; // XXXX + } + + // + // Translate the device name into the device path for Open Firmware. + // + // XXXX + // How do I mount/unmount ? + // If Operation is MountUnloadMedia for not mounted device, + // return ENXIO; + + debug(VRDBG_OPEN, "VrMount: Exit\n"); + + return ESUCCESS; +} + + +/* + * Name: VrSeek + * + * Description: + * This function changes the byte offset associated with the device, + * partition, or file specified by FileId. + * + * Arguments: + * FileId - Supplies the file table index. + * Offset - Supplies a poiner to a structure that contains + * the offset value. + * SeekMode - Supplies the type of positioning to be performed. + * + * Return Value: + * If the specified file is open, then a seek is attempted and + * the status of the operation is returned. Otherwise, return + * an unsuccessful status. + * + */ +ARC_STATUS +VrSeek( + IN ULONG FileId, + IN PLARGE_INTEGER Offset, + IN SEEK_MODE SeekMode + ) +{ + LONG Status; + + debug(VRDBG_RDWR, "VrSeek: Entry - FileId: %d Offset: %x.%x Mode: %x\n", + FileId, Offset->HighPart, Offset->LowPart, SeekMode); + + if (FileId >= FILE_TABLE_SIZE) { + return EBADF; + } + if (FileTable[FileId].Flags.Open != 1) { + return EACCES; + } + if (FileTable[FileId].Flags.Delete == 1) { + return EACCES; + } + if (!(SeekMode == SeekRelative || SeekMode == SeekAbsolute)) { + return EINVAL; + } + + // + // If the specified device is Network, only set Offset into FileTable + // because the Offset is interpreted to be a count of input to ignore. + // The offset is cleared after reading the input packet. + // + if (FileTable[FileId].Flags.NetworkDevice == 1) { + (VOID)MoveLargeInt(&FileTable[FileId].Position, Offset); + return ESUCCESS; + } + + // + // Set the file position according to SeekMode. + // + if (SeekMode == SeekRelative) { + (VOID)AddLargeInt(&FileTable[FileId].Position, Offset); + } else { + (VOID)MoveLargeInt(&FileTable[FileId].Position, Offset); + } + + // + // If FileId is for Network device, the input packets are ignored + // according to Offset and then return with ESUCCESS. + // + if (FileTable[FileId].Flags.NetworkDevice == 1) { + while (IsLarge(&FileTable[FileId].Position) == NOT_ZERO_LARGE) { + LONG ReadSize; + CHAR Buffer[4]; + + if ((ReadSize = OFRead(FileTable[FileId].IHandle, Buffer, 1)) + == -1) { + return EIO; + } + if (ReadSize == 0) { + continue; + } + DecrementLarge(&FileTable[FileId].Position); + } + return ESUCCESS; + } + + Status = OFSeek(FileTable[FileId].IHandle, + FileTable[FileId].Position.HighPart, + FileTable[FileId].Position.LowPart); + if (Status == -1) { + return EINVAL; // XXXX + } + + debug(VRDBG_RDWR, "VrSeek: Exit\n"); + + return ESUCCESS; +} + + +/* + * Name: VrGetDirectoryEntry + * + * Description: + * This function reads directory entries from the system partition + * directory file specified by FileId. + * + * Arguments: + * FileId - Supplies the file table index. + * Buffer - Supplies a pointer to a buffer for the entry data. + * Length - Supplies the number of entries to retrieve. + * Count - Supplies a pointeer to the number of entries read + * into the buffer. + * + * Return Value: + * If the specified file is open for read, then the read is attempted + * and the status is returned. Otherwise, retrun an unsuccessful status. + * + */ +ARC_STATUS +VrGetDirectoryEntry( + IN ULONG FileId, + OUT PDIRECTORY_ENTRY Buffer, + IN ULONG Length, + OUT PULONG Count + ) +{ + debug(VRDBG_OPEN, "VrGetDirectoryEntry: Entry - FileId: %d Length: %d\n", + FileId, Length); + + if (FileId >= FILE_TABLE_SIZE) { + return EBADF; + } + if (FileTable[FileId].Flags.Device) { + return ENOTDIR; + } + if (!(FileTable[FileId].Flags.Open == 1 + && FileTable[FileId].Flags.Read == 1)) { + return EBADF; + } + + // XXXX + // Get Director Entry if (FileID != directory) return ENOTDIR; + + debug(VRDBG_OPEN, "VrGetDirectoryEntry: Exit\n"); + + return ESUCCESS; +} + + +/* + * Name: VrGetFileInformation + * + * Description: + * This function retunrs an information structure about the specified + * file or partition. + * + * Arguments: + * FileId - Supplies the file table index. + * FileInformation - Supplies a pointer to the location of the file + * information data. + * + * Return Value: + * If the specified file is open, then getting the file information is + * attempted and the status is returned. Otherwise, retrun an unsuccessful + * status. + * + */ +ARC_STATUS +VrGetFileInformation( + IN ULONG FileId, + OUT PFILE_INFORMATION pFI + ) +{ + PFILE_TABLE_ENTRY fte; + ihandle ih; + PCONFIGURATION_NODE node; + ULONG size_thang[2]; + + debug(VRDBG_OPEN, "VrGetFileInformation: Entry - FileId: %d\n", FileId); + + if (FileId >= FILE_TABLE_SIZE) { + debug(VRDBG_OPEN, "VrGetFileInformation: Exit EBADF\n"); + return EBADF; + } + fte = &FileTable[FileId]; + if (fte->Flags.Open != 1) { + debug(VRDBG_OPEN, "VrGetFileInformation: Exit EACCES\n"); + return EACCES; + } + if (fte->Flags.Device == 1) { + debug(VRDBG_OPEN, "VrGetFileInformation: Exit EINVAL\n"); + return EINVAL; + } + + ih = fte->IHandle; + node = InstanceToNode(ih); + pFI->CurrentPosition = fte->Position; + pFI->Type = node->Component.Type; + + (void) OFCallMethod(2, 2, size_thang, "size", ih); + pFI->EndingAddress.HighPart = size_thang[0]; + pFI->EndingAddress.LowPart = size_thang[1]; + + if (fte->Flags.Partition == 1) { + (void) OFCallMethod( 1, 2, &(pFI->StartingAddress.HighPart), + "offset-high", ih); + (void) OFCallMethod( 1, 2, &(pFI->StartingAddress.LowPart), + "offset-low", ih); + AddLargeInt(&pFI->EndingAddress, &pFI->StartingAddress); + pFI->FileName[0] = '\0'; + pFI->FileNameLength = 0; + } else { + /* + * It's a file. + */ + pFI->StartingAddress.HighPart = 0; + pFI->StartingAddress.LowPart = 0; + strcpy(pFI->FileName, fte->PathName); // XXX s.b. strncpy(&,&,32) + pFI->FileNameLength = strlen(fte->PathName) + 1; + } +#ifdef XXX + pFI->Attributes = // Get this from the firmware, somehow. +#endif + debug(VRDBG_OPEN, "VrGetFileInformation:\n"); + debug(VRDBG_OPEN, "\tStarting %x.%x\n", pFI->StartingAddress.HighPart, + pFI->StartingAddress.LowPart); + debug(VRDBG_OPEN, "\tEnding %x.%x\n", pFI->EndingAddress.HighPart, + pFI->EndingAddress.LowPart); + debug(VRDBG_OPEN, "\tCurrent %x.%x\n", pFI->CurrentPosition.HighPart, + pFI->CurrentPosition.LowPart); + debug(VRDBG_OPEN, "\tType %d FileNameLength %d\n", pFI->Type, + pFI->FileNameLength); + debug(VRDBG_OPEN, "\tFileName '%s'\n", + pFI->FileNameLength ? pFI->FileName : "NULL"); + return ESUCCESS; +} + +/* + * Name: VrGetReadStatus + * + * Description: + * This function determines if any bytes would be returned if a read + * operation were performed on FileId. + * + * Arguments: + * FileId - Supplies the file table index. + * + * Return Value: + * If the specified file is open, then the getting read status is + * attempted and the status is returned. Otherwise, retrun an unsuccessful + * status. + * + */ +ARC_STATUS +VrGetReadStatus( + IN ULONG FileId + ) +{ + LONG Count; + + if (FileId == 0) { // stdin + if (consin_readahead != 0) { + return (ESUCCESS); + } + if (ConsoleIn == 0) { + (void) VrFindConsolePath("stdin"); + } + if (OFRead(ConsoleIn, &consin_readahead, 1) != 1) { + return (EAGAIN); + } + return (ESUCCESS); + } + + debug(VRDBG_RDWR, "VrGetReadStatus: Entry - FileId: %d\n", FileId); + + if (FileId >= FILE_TABLE_SIZE) { + return EBADF; + } + if (!(FileTable[FileId].Flags.Open == 1 + && FileTable[FileId].Flags.Read == 1)) { + return EACCES; + } + if (FileTable[FileId].Flags.Delete == 1) { + return EACCES; + } + + // + // Try to read one byte. + // + Count = OFRead(FileTable[FileId].IHandle, + FileTable[FileId].ReadAheadBuffer, + 1); + if (Count != 1) { + FileTable[FileId].ReadAheadCount = 0; // For safety. + debug(VRDBG_RDWR, "VrGetReadStatus: Exit - with EAGAIN\n"); + return EAGAIN; + } + + // + // Now read ahead one byte. + // + FileTable[FileId].ReadAheadCount = 1; + + if (FileId >= 2) { + debug(VRDBG_RDWR, "VrGetReadStatus: Exit\n"); + } + + return ESUCCESS; +} + + +/* + * Name: VrSetFileInformation + * + * Description: + * This function sets the file attributes for the specified FileId. + * + * Arguments: + * FileId - Supplies the file table index. + * AttributeFlags - Supplies the attributes to be set for the file. + * AttributeMask - Supplies the attribute Mask. + * + * Return Value: + * If the specified file is open, then the setting file information is + * attempted and the status is returned. Otherwise, retrun an unsuccessful + * status. + * + */ +ARC_STATUS +VrSetFileInformation( + IN ULONG FileId, + IN ULONG AttributeFlags, + IN ULONG AttributeMask + ) +{ + debug(VRDBG_OPEN, "VrSetFileInformation: Entry - FileId: %d AttributeFlags: %x AttributeMask: %x\n", + FileId, AttributeFlags, AttributeMask); + + if (FileId >= FILE_TABLE_SIZE) { + return EBADF; + } + if (!(FileTable[FileId].Flags.Open == 1)) { + return EACCES; + } + if (FileTable[FileId].Flags.Device == 1) { + return EINVAL; + } + + // + // The attribute DirectoryFile is ignored for this function. + // + AttributeMask &= ~ArcDirectoryFile; + + // + // A file is marked for deletion by setting the DeleteFile flag + // in voth the AttributeFlags and AttributeMask parameters. + // In this case, the file can be access only by Close(). + // + if ((AttributeMask & ArcDeleteFile) && (AttributeFlags & ArcDeleteFile)) { + + // + // When the file is a derectroy which is not empty or a read-only file, + // EACCESS is retuned. + // + // XXXX not empy check is needed + // + if (!(FileTable[FileId].Flags.Read == 1 + && FileTable[FileId].Flags.Write == 0)) { + return EACCES; + } + + + FileTable[FileId].Flags.Delete = 1; + } + + // XXX return OFSetFileInformation(FileId, Buffer, Length, Count); + + debug(VRDBG_OPEN, "VrSetFileInformation: Exit\n"); + return(ESUCCESS); +} + + +/* + * Name: VrIoInitialize + * + * Description: + * This function initializes the I/O entry points in the firmware + * transfer vector and the file table. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrIoInitialize( + VOID + ) +{ + ULONG Index; + + // + // Initialize the I/O entry points in the firmware transfer vector. + // + debug(VRDBG_ENTRY, "VrIoInitialize BEGIN......\n"); + (PARC_CLOSE_ROUTINE) SYSTEM_BLOCK->FirmwareVector[CloseRoutine] = VrClose; + (PARC_MOUNT_ROUTINE) SYSTEM_BLOCK->FirmwareVector[MountRoutine] = VrMount; + (PARC_OPEN_ROUTINE) SYSTEM_BLOCK->FirmwareVector[OpenRoutine] = VrOpen; + (PARC_READ_ROUTINE) SYSTEM_BLOCK->FirmwareVector[ReadRoutine] = VrRead; + (PARC_SEEK_ROUTINE) SYSTEM_BLOCK->FirmwareVector[SeekRoutine] = VrSeek; + (PARC_WRITE_ROUTINE) SYSTEM_BLOCK->FirmwareVector[WriteRoutine] = VrWrite; + + (PARC_READ_STATUS_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[ReadStatusRoutine] = VrGetReadStatus; + + (PARC_GET_FILE_INFO_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetFileInformationRoutine] = + VrGetFileInformation; + (PARC_SET_FILE_INFO_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[SetFileInformationRoutine] = + VrSetFileInformation; + (PARC_GET_DIRECTORY_ENTRY_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetDirectoryEntryRoutine] = + VrGetDirectoryEntry; + + // + // Initialize the file table. + // + for (Index = 0; Index < FILE_TABLE_SIZE; Index++) { + FileTable[Index].Flags.Open = 0; + } + + debug(VRDBG_ENTRY, "VrIoInitialize ......END\n"); + return; +} + + +/* + * Name: GetFileTableEntry (internal) + * + * Description: + * This function looks for an unused entry in the FileTable. + * + * Arguments: + * Entry - Pointer to the variable that gets an index + * for the file table. + * + * Return Value: + * + * Returns ESUCCESS if a free entry is found + * or EMFILE if no entry is available. + * + */ +STATIC ARC_STATUS +GetFileTableEntry( + OUT PULONG Entry + ) +{ + ULONG Index; + + for (Index = 2; Index < FILE_TABLE_SIZE; Index++) { + if (FileTable[Index].Flags.Open == 0) { +#ifdef notdef + FileTable[Index].Position.LowPart = 0; + FileTable[Index].Position.HighPart = 0; +#endif // notdef + bzero((PCHAR)&FileTable[Index], sizeof(FILE_TABLE_ENTRY)); + *Entry = Index; + return ESUCCESS; + } + } + return EMFILE; +} + + +/* + * Name: GetDeviceAttribute (internal) + * + * Description: + * This function sets the specified File Table entry to the attribute. + * + * Arguments: + * FileId - Supplies the file table index. + * ConfNode - Supplies a pointer to the Configuration Node. + * + * Return Value: + * If the Configuration node is not peripheral, then return ENODEV. + * Otherwise, returns ESUCCESS. + * + */ +STATIC ARC_STATUS +GetDeviceAttribute( + IN ULONG FileId, + IN PCONFIGURATION_NODE ConfNode + ) +{ + if (ConfNode->Component.Class != PeripheralClass) { + warn("GetDeviceAttribute: node %s(%d) not PeripheralClass.\n", + ConfNode->ComponentName, ConfNode->Component.Key); + return ENODEV; + } + + if (ConfNode->Component.Type == MonitorPeripheral) { + FileTable[FileId].Flags.DisplayDevice = 1; + } + if (ConfNode->Component.Flags.Removable) { + FileTable[FileId].Flags.RemovableDevice = 1; + } + if (ConfNode->Component.Type == NetworkPeripheral) { + FileTable[FileId].Flags.NetworkDevice = 1; + } + if (ConfNode->Component.Flags.Input) { + FileTable[FileId].Flags.Read = 1; + } + if (ConfNode->Component.Flags.Output && + !(ConfNode->Component.Flags.ReadOnly)) { + FileTable[FileId].Flags.Write = 1; + } + + return ESUCCESS; +} + + +/* + * Name: AddLargeInt (internal) + * + * Description: + * This function adds a large integer into another large ingeger. + * + * Arguments: + * Position - Supplies a pointer to a variable to be added. + * Value - Supplies a pointer to a variable to add. + * + * Return Value: + * None. + * + */ +STATIC VOID +AddLargeInt( + PLARGE_INTEGER Position, + PLARGE_INTEGER Value + ) +{ + if ((Position->LowPart += Value->LowPart) < Value->LowPart) { + Position->HighPart++; + } + Position->HighPart += Value->HighPart; +} + + +/* + * Name: DecrementLarge (internal) + * + * Description: + * This function decrements a large integer. + * + * Arguments: + * Position - Supplies a pointer to a variable to be decremented. + * + * Return Value: + * None. + * + */ +STATIC VOID +DecrementLarge( + PLARGE_INTEGER Position + ) +{ + ULONG ULong = Position->LowPart; + + Position->LowPart--; + if (Position->LowPart > ULong) { + Position->HighPart--; + } +} + + +/* + * Name: MoveLargeInt (internal) + * + * Description: + * This function copies a large integer into another large ingeger. + * + * Arguments: + * Position - Supplies a pointer to a variable to be copied. + * Value - Supplies a pointer to a variable to copy. + * + * Return Value: + * None. + * + */ +STATIC VOID +MoveLargeInt( + PLARGE_INTEGER Position, + PLARGE_INTEGER Value + ) +{ + Position->LowPart = Value->LowPart; + Position->HighPart = Value->HighPart; +} + + +/* + * Name: IsLarge (internal) + * + * Description: + * This function determines whether a large integer contains zero. + * + * Arguments: + * Position - Supplies a pointer to a variable to be checked. + * + * Return Value: + * If the large integer is zero, then returns ZERO_LARGE. Otherwise, + * returns NOT_ZERO_LARGE. + * + */ +STATIC LONG +IsLarge( + PLARGE_INTEGER Position + ) +{ + if (Position->LowPart != 0) { + return NOT_ZERO_LARGE; + } + if (Position->HighPart != 0) { + return NOT_ZERO_LARGE; + } + return ZERO_LARGE; +} + diff --git a/private/ntos/boot/veneer/vrlib.c b/private/ntos/boot/veneer/vrlib.c new file mode 100644 index 000000000..6d8753887 --- /dev/null +++ b/private/ntos/boot/veneer/vrlib.c @@ -0,0 +1,614 @@ +/* + * + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * Copyright (c) 1995 FirePower Systems, Inc. + * Copyright (c) 1996 FirePower Systems, Inc. + * + * $RCSfile: vrlib.c $ + * $Revision: 1.14 $ + * $Date: 1996/06/27 18:36:55 $ + * $Locker: $ + */ + +#include "veneer.h" + +STATIC VOID doprnt(VOID (*)(), char *, va_list); +STATIC VOID printbase(VOID (*)(), ULONG x, int base); + +int +get_bool_prop(phandle node, char *key) +{ + return(OFGetproplen(node, key) != -1); +} + +int +decode_int(UCHAR *p) +{ + ULONG i = *p++ << 8; + i = (i + *p++) << 8; + i = (i + *p++) << 8; + return (i + *p); +} + +int +get_int_prop(phandle node, char *key) +{ + int res; + char buf[sizeof(int)]; + + res = OFGetprop(node, key, buf, sizeof(int)); + if (res != sizeof(int)) { + return(-1); + } + /* + * The NT veneer is always little-endian. + */ + return(decode_int((UCHAR *) buf)); +} + +reg * +decode_reg(UCHAR *buf, int buflen, int addr_cells, int size_cells) +{ + static reg staticreg; + reg *r = &staticreg; + + bzero((PCHAR) r, sizeof(reg)); + + if (buflen < addr_cells + size_cells) { + fatal("reg property smaller than #address-cell plus #size-cells\n"); + } + + r->lo = decode_int(buf + ((addr_cells-1) * 4)); + r->hi = decode_int(buf); + r->size = decode_int(buf + ((addr_cells + size_cells - 1) * 4)); + + return (r); +} + +reg * +get_reg_prop(phandle node, char *key, int index) +{ + int res; + char *buf; + reg *regp; + int len = OFGetproplen(node, key); + int addr_cells, size_cells, offset; + + buf = (char *)malloc(len); + res = OFGetprop(node, key, buf, len); + if (res != len) { + fatal("get_reg_prop(node %x, key '%s', len %x) returned %x\n", + node, key, len, res); + free(buf); + return ((reg *) 0); + } + + + addr_cells = get_int_prop(OFParent(node), "#address-cells"); + if (addr_cells < 0) { + addr_cells = 2; + } + size_cells = get_int_prop(OFParent(node), "#size-cells"); + if (size_cells < 0) { + size_cells = 1; + } + + offset = index * (addr_cells + size_cells) * 4; + key = buf + offset; + len -= offset; + if (len) { + debug(VRDBG_TEST, "key %x len %x\n", key, len); + regp = decode_reg(key, len, addr_cells, size_cells); + } else { + debug(VRDBG_TEST, "returning NULL regp\n"); + regp = NULL; + } + + free(buf); + return (regp); +} + +char * +get_str_prop(phandle node, char *key, allocflag alloc) +{ + int len, res; + static char *priv_buf, priv_buf_len = 0; + char *cp; + + len = OFGetproplen(node, key); + if (len == -1 || len == 0) { + return((char *) 0); + } + + /* + * Leave room for a null terminator, on the off chance that the + * property isn't null-terminated. + */ + len += 1; + if (alloc == ALLOC) { + cp = (char *) zalloc(len); + } else { + if (len > priv_buf_len) { + if (priv_buf_len) { + free(priv_buf); + } + priv_buf = (char *) zalloc(len); + priv_buf_len = len; + } else { + bzero(priv_buf, len); + } + cp = priv_buf; + } + len -= 1; + + res = OFGetprop(node, key, cp, len); + if (res != len) { + fatal( "get_str_prop(node %x, key '%s', len %x) returned len %x\n", + node, key, len, res); + return((char *) 0); + } + return(cp); +} + +int +strcmp(const char *s, const char *t) +{ + int i; + + for (i = 0; s[i] == t[i]; ++i) { + if (s[i] == '\0') { + return (0); + } + } + return((int) (s[i] - t[i])); +} + + +int +strncmp(const char *s, const char *t, size_t len) +{ + int i; + + for (i = 0; (s[i] == t[i]) && (i != (int) len); ++i) { + if (s[i] == '\0') { + return (0); + } + } + if (i == (int) len) { + return(0); + } + return((int) (s[i] - t[i])); +} + +int +strncasecmp(const char *s, const char *t, size_t len) +{ + int i; + char s1 = 0, t1 = 0; + + for (i = 0; i != (int) len; ++i) { + if (s[i] == '\0') { + return (0); + } + s1 = s[i]; + if (s1 >= 'a' && s1 <= 'z') { + s1 -= 0x20; + } + t1 = t[i]; + if (t1 >= 'a' && t1 <= 'z') { + t1 -= 0x20; + } + if (s1 == t1) { + break; + } + } + if (i == (int) len) { + return(0); + } + return((int) (s1 - t1)); +} + +size_t +strlen(const char *s) +{ + int i; + + for (i = 0; s[i] != '\0'; ++i) { + ; + } + return((size_t) i); +} + +char * +strcpy(char *to, const char *from) +{ + int i = 0; + + while (to[i] = from[i]) { + i += 1; + } + return(to); +} + +char * +strcat(char *to, const char *from) +{ + char *ret = to; + + while (*to) { + to += 1; + } + strcpy(to, from); + return (ret); +} + +VOID +bcopy(char *from, char *to, int len) +{ + while (len--) { + *to++ = *from++; + } +} + +VOID +bzero(char *cp, int len) +{ + while (len--) { + *(cp + len) = 0; + } +} + +VOID * +zalloc(int size) +{ + VOID *vp; + + vp = malloc(size); + bzero(vp, size); + return (vp); +} + +VOID +sleep(ULONG delay) +{ + delay += VrGetRelativeTime(); + while (VrGetRelativeTime() < delay) { + ; + } +} + +int +claim(void *adr, int bytes) +{ + return(OFClaim((PCHAR) MAP(adr), bytes, 0)); +} + +VOID * +alloc(int size, int align) +{ + return((VOID *) OFClaim(0, size, align)); +} + +int +atoi(char *s) +{ + int temp = 0, base = 10; + char *start; + + if (*s == '0') { + ++s; + if (*s == 'x') { + ++s; + base = 16; + } else { + base = 8; + } + } + start = s; +again: + while (*s) { + switch (*s) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + temp = (temp * base) + (*s++ - '0'); + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + if (base == 10) { + base = 16; + temp = 0; + s = start; + goto again; + } + temp = (temp * base) + (*s++ - 'a' + 10); + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + if (base == 10) { + base = 16; + temp = 0; + s = start; + goto again; + } + temp = (temp * base) + (*s++ - 'A' + 10); + break; + default: + return (temp); + } + } + return (temp); +} + +char * +index(char *s, int c) +{ + while (*s) { + if (*s == c) { + return (s); + } + ++s; + } + return ((char *) 0); +} + +char * +strcsep(char *s, const char sep) +{ + static char *saved_str = NULL; + char *temp; + + if (s != NULL) { + saved_str = s; + } + if (saved_str == NULL) { + return(NULL); + } + s = index(saved_str, sep); + if (s != NULL) { + *s++ = '\0'; + } + temp = saved_str; + saved_str = s; + return(temp); +} + +char * +strctok(char *s, const char sep) +{ + static char *saved_str = NULL; + char *temp; + + if (s != NULL) { + saved_str = s; + } + if (saved_str == NULL) { + return(NULL); + } + s = index(saved_str, sep); + if (s != NULL) { + *s++ = '\0'; + while (*s && (*s == sep)) { + ++s; + } + } + temp = saved_str; + saved_str = s; + return(temp); +} + +char * +capitalize(char *s) +{ + char *p; + + p = s; + while (*p) { + *p = islower(*p) ? toupper(*p) : *p; + ++p; + } + return(s); +} + + + +STATIC ihandle stdout = 0; +STATIC char outbuf[128]; +STATIC int outbufc = 0; + +VOID +putchar(char c) +{ + phandle ph; + + if (stdout == 0) { + ph = OFFinddevice("/chosen"); + if (ph == -1) { + /* What to do here?!? */ + while (1) { + ; + } + } + stdout = get_int_prop(ph, "stdout"); + } + + if (c == '\n') { + outbuf[outbufc++] = '\r'; + } + outbuf[outbufc++] = c; + if ((c == '\n') || (outbufc == 127)) { + OFWrite(stdout, outbuf, outbufc); + outbufc = 0; + return; + } +} + +VOID +puts(char *s) +{ + int count; + + if (stdout == 0) { + putchar(*s++); + } + if (outbufc) { + OFWrite(stdout, outbuf, outbufc); + outbufc = 0; + } + if (count = strlen(s)) { + OFWrite(stdout, s, count); + } + putchar('\n'); +} + +STATIC ihandle stdin = 0; + +VOID +gets(char *inbuf) +{ + int count; + phandle ph; + + if (stdin == 0) { + ph = OFFinddevice("/chosen"); + if (ph == -1) { + /* What to do here?!? */ + while (1) { + ; + } + } + stdin = get_int_prop(ph, "stdin"); + } + + count = OFRead(stdin, inbuf, 127); + inbuf[count] = '\0'; +} + +#include <stdarg.h> + +VOID +warn(char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + doprnt(putchar, fmt, args); + va_end(args); +} + +VOID +fatal(char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + doprnt(putchar, fmt, args); + OFExit(); + va_end(args); +} + +int level = 0; + +VOID +debug(int debug_level, char *fmt, ...) +{ + va_list args; + int i; + + if (!(debug_level & VrDebug)) { + return; + } + va_start(args, fmt); + for (i = 0; i < level; ++i) { + putchar('\t'); + } + doprnt(putchar, fmt, args); + va_end(args); +} + +STATIC char *sprintf_buf; + +STATIC VOID +putbuf(char c) +{ + *sprintf_buf++ = c; +} + +VOID +sprintf(char *buf, char *fmt, ...) +{ + va_list args; + + sprintf_buf = buf; + va_start(args, fmt); + doprnt(putbuf, fmt, args); + va_end(args); + putbuf('\0'); +} + +STATIC VOID +doprnt(VOID (*func)(), char *fmt, va_list args) +{ + ULONG x; + LONG l; + char c, *s; + + while (c = *fmt++) { + if (c != '%') { + func(c); + continue; + } + switch (c = *fmt++) { + case 'x': + x = va_arg(args, ULONG); + printbase(func, x, 16); + break; + case 'o': + x = va_arg(args, ULONG); + printbase(func, x, 8); + break; + case 'd': + l = va_arg(args, LONG); + if (l < 0) { + func('-'); + l = -l; + } + printbase(func, (ULONG) l, 10); + break; + case 'c': + c = va_arg(args, char); + func(c); + break; + case 's': + s = va_arg(args, char *); + while (*s) { + func(*s++); + } + break; + default: + func(c); + break; + } + } +} + +STATIC VOID +printbase(VOID (*func)(), ULONG x, int base) +{ + static char itoa[] = "0123456789abcdef"; + ULONG j; + char buf[16], *s = buf; + + if (x == 0) { + func('0'); + return; + } + bzero(buf, 16); + while (x) { + j = x % base; + *s++ = itoa[j]; + x -= j; + x /= base; + } + + for (--s; s >= buf; --s) { + func(*s); + } +} diff --git a/private/ntos/boot/veneer/vrload.c b/private/ntos/boot/veneer/vrload.c new file mode 100644 index 000000000..9fdfc412d --- /dev/null +++ b/private/ntos/boot/veneer/vrload.c @@ -0,0 +1,1035 @@ +/* + * + * Copyright (c) 1995 FirePower Systems, Inc. + * Copyright (c) 1994 FirePower Systems Inc. + * + * $RCSfile: vrload.c $ + * $Revision: 1.12 $ + * $Date: 1996/04/15 02:55:48 $ + * $Locker: $ + * + * + * Module Name: + * vrload.c + * + * Author: + * Shin Iwamoto at FirePower Systems Inc. + * + * History: + * 28-Jul-94 Shin Iwamoto at FirePower Systems Inc. + * Added for DOS signature of PE in VrLoad(); + * 18-Jul-94 Shin Iwamoto at FirePower Systems Inc. + * Created. + */ + + +#include "veneer.h" + +#define XXX_MAKE_DESCRIPTOR + +// +// This must be defined in some header file. But for 3.5 it is not defined. +// +#define IMAGE_FILE_16BIT_MACHINE 0x0040 + + +typedef struct _VR_MEMORY_DESCRIPTOR { + struct _VR_MEMORY_DESCRIPTOR *NextEntry; + MEMORY_DESCRIPTOR MemoryEntry; +} VR_MEMORY_DESCRIPTOR, *PVR_MEMORY_DESCRIPTOR; + +extern PVR_MEMORY_DESCRIPTOR VrMemoryListOrig; + +// +// Some type definitions. +// +typedef struct _SECTION_RELOCATION_ENTRY { + ULONG FixupValue; + ULONG PointerToRelocations; + USHORT NumberOfRelocations; +} SECTION_RELOCATION_ENTRY, *PSECTION_RELOCATION_ENTRY; + +// +// Some definitions. +// +// These must be defined in veneer.h or ntimage.h? +// +#define HEADER_CHAR (IMAGE_FILE_EXECUTABLE_IMAGE | \ + IMAGE_FILE_BYTES_REVERSED_LO | \ + IMAGE_FILE_32BIT_MACHINE | \ + IMAGE_FILE_BYTES_REVERSED_HI) +#define HEADER_NOCHAR (IMAGE_FILE_16BIT_MACHINE | \ + IMAGE_FILE_DLL) +#define OPTIONAL_MAGIC_STD 0x010B + +// +// Section numbers for local relocation entries +// +#define R_SN_TEXT 0 +#define R_SN_DATA 1 +#define R_SN_BSS 2 +#define R_SN_MAX 3 + + +#define MAX_ARGUMENT (512 - sizeof(ULONG) - 16*sizeof(PUCHAR)) +typedef struct _SAVED_ARGUMENTS { + ULONG Argc; + PUCHAR Argv[16]; + UCHAR Arguments[MAX_ARGUMENT]; +} SAVED_ARGUMENTS, *PSAVED_ARGUMENTS; + + +STATIC PSAVED_ARGUMENTS SavedArgs; +STATIC ULONG VrActualBasePage; +STATIC ULONG VrPageCount; + + +// +// Function declarations. +// +ARC_STATUS +VrRelocateImage( + IN ULONG FileId, + IN PSECTION_RELOCATION_ENTRY RelocationTable, + IN ULONG NumberOfSections, + IN ULONG PointerToSymbolTable + ); +VOID +VrCopyArguments( + IN ULONG Argc, + IN PCHAR Argv[] + ); +ARC_STATUS +VrGenerateDescriptor( + IN PMEMORY_DESCRIPTOR MemoryDescriptor, + IN MEMORY_TYPE MemoryType, + IN ULONG BasePage, + IN ULONG PageCount + ); +VOID +VrResetMemory( + VOID + ); +VOID +PxInvoke( + IN ULONG EntryAddress, + IN ULONG StackAddress, + IN ULONG Argc, + IN PCHAR Argv[], + IN PCHAR Envp[] + ); +VOID +InsertMemDescriptor( + IN PVR_MEMORY_DESCRIPTOR MemDescriptor + ); + + +/* + * Name: VrLoad + * + * Description: + * This function reads a program into memory at a specified address + * an;d stores the execution address. + * + * Arguments: + * ImagePath - Supplies a pointer to the path of the file to load. + * TopAddress - Supplies the top address of a region of memory into + * which the file is to be loaded. + * EntryAddress- Supplies a pointer to a variable to receive the entry + * point of the image, if defined. + * LoaAddress - Supplies a pointer to a variable to receive the low address + * of the loaded file. + * + * Return Value: + * ESUCCESS is returned if the specified image file is loaded successfully. + * Otherwise, an unsuccessufl status is returned that describes the reason + * for failure. + * + */ +ARC_STATUS +VrLoad( + IN PCHAR ImagePath, + IN ULONG TopAddress, + OUT PULONG EntryAddress, + OUT PULONG LowAddress + ) +{ + PSECTION_RELOCATION_ENTRY RelocationTable; + IMAGE_DOS_HEADER DosHeader; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; + PIMAGE_SECTION_HEADER SectionHeader, SHeader; + ULONG FileId, NumberOfSections, Count; + ULONG ActualBase, ClaimSize, SectionOffset; + LARGE_INTEGER SeekPosition; + ARC_STATUS Status; + LONG NT_Signature; + LONG size, i; + PCHAR ReadAddr; + ULONG ReadSize; + + + debug(VRDBG_LOAD, "VrLoad: Entry - ImagePath: %s TopAddress: %x\n", + ImagePath, TopAddress); + + // + // Attempt to open the load file. + // + if ((Status = VrOpen(ImagePath, ArcOpenReadOnly, &FileId)) != ESUCCESS) { + return Status; + } + + // + // Read DOS Signature. + // + if ((Status = VrRead(FileId, &DosHeader, 2, &Count)) != ESUCCESS) { + (VOID)VrClose(FileId); + return Status; + } + + // + // If the file isn't a PE file including DOS header, + // it's probably a COFF file. + // + if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) { + bcopy((char *)&DosHeader, (char *)&FileHeader, 2); + ReadAddr = (PCHAR)&FileHeader + 2; + ReadSize = IMAGE_SIZEOF_FILE_HEADER - 2; + goto DirectCOFF; + } + + // + // Read the remainder of DOS header. + // + if ((Status = VrRead(FileId, (PCHAR)&DosHeader+2, sizeof(DosHeader) - 2, + &Count)) != ESUCCESS) { + (VOID)VrClose(FileId); + return Status; + } + if (Count != sizeof(DosHeader) - 2) { + (VOID)VrClose(FileId); + return EBADF; // XXXX + } + SeekPosition.HighPart = 0; + SeekPosition.LowPart = DosHeader.e_lfanew; + if (Status = VrSeek(FileId, &SeekPosition, SeekAbsolute)) { + (VOID)VrClose(FileId); + return EBADF; // XXXX + } + + // + // Read NT Signature and confirm it. + // + if ((Status = VrRead(FileId, &NT_Signature, sizeof(NT_Signature), &Count)) + != ESUCCESS) { + (VOID)VrClose(FileId); + return Status; + } + if (Count != sizeof(NT_Signature) || NT_Signature != IMAGE_NT_SIGNATURE) { + (VOID)VrClose(FileId); + return EBADF; // XXXX + } + + ReadAddr = (PCHAR)&FileHeader; + ReadSize = IMAGE_SIZEOF_FILE_HEADER; + + DirectCOFF: + // + // Read the image header from the file. + // + if ((Status = VrRead(FileId, ReadAddr, ReadSize, &Count)) != ESUCCESS) { + (VOID)VrClose(FileId); + return Status; + } + if (Count != ReadSize) { + (VOID)VrClose(FileId); + return EBADF; // XXXX + } + + // + // Check the header. + // + if ((FileHeader.Machine != IMAGE_FILE_MACHINE_POWERPC) || + ((FileHeader.Characteristics & HEADER_CHAR) != HEADER_CHAR) || + ((FileHeader.Characteristics & HEADER_NOCHAR) != 0) ) { + + (VOID)VrClose(FileId); + return ENOEXEC; + } + + // + // Read the optional header. + // + if ((Status = VrRead(FileId, &OptionalHeader, + FileHeader.SizeOfOptionalHeader, &Count)) != ESUCCESS) { + (VOID)VrClose(FileId); + return Status; + } + if (Count != FileHeader.SizeOfOptionalHeader) { + (VOID)VrClose(FileId); + return EBADF; // XXXX + } + + // + // More check with the optional header. + // + if (OptionalHeader.Magic != OPTIONAL_MAGIC_STD) { + (VOID)VrClose(FileId); + return ENOEXEC; + } + + // + // If the image cannot be relocated, set the ActualBase to the code + // base, and compute the image size by subtracting the code base from + // the data base plus the data size. If the image can be relocated, + // set ActualBase to the TopAddress minus the image size, compute + // image size by adding the code size, initialized data, and + // uninitialized data. + // + if ((FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) { + ActualBase = OptionalHeader.BaseOfCode; + ClaimSize = OptionalHeader.BaseOfData + + OptionalHeader.SizeOfInitializedData - ActualBase; + } else { + ClaimSize = OptionalHeader.SizeOfCode + + OptionalHeader.SizeOfInitializedData + + OptionalHeader.SizeOfUninitializedData; + // ActualBase = OptionalHeader.ImageBase; +#ifdef XXX_I_KNOW_PE + ActualBase = (TopAddress - ClaimSize) & ~(PAGE_SIZE - 1); +#else + ActualBase = OptionalHeader.ImageBase; + ActualBase &= 0x7fffffff; +#endif XXX_I_KNOW_PE + } + + // + // Allocate and read the section headers. + // + size = FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); + SectionHeader = (PIMAGE_SECTION_HEADER)malloc(size); + if ((Status = VrRead(FileId, (PCHAR)SectionHeader, size, &Count)) + != ESUCCESS) { + (VOID)VrClose(FileId); + return Status; + } + if (Count != (ULONG) size) { + (VOID)VrClose(FileId); + return EBADF; // XXXX + } + + // + // + // + NumberOfSections = FileHeader.NumberOfSections; + if (strcmp((PCHAR)(SectionHeader[NumberOfSections-1].Name), ".debug") + == 0) { + NumberOfSections--; + ClaimSize -= SectionHeader[NumberOfSections].SizeOfRawData; + } + + // + // Allocate the relocation table. + // + size = NumberOfSections * sizeof(SECTION_RELOCATION_ENTRY); + RelocationTable = (PSECTION_RELOCATION_ENTRY) malloc(size); + + // + // Zero the relocation table. + // + bzero((char *)RelocationTable, size); + + // + // Convert ClaimSize to be page-aligned. + // + ClaimSize = (ClaimSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + // + // Convert ActualBase and ClaimSize to be in units of pages instead of + // bytes. This is the interface between VrExecute and VrLoad. + // + VrActualBasePage = (ActualBase & 0x7fffffff) >> PAGE_SHIFT; + VrPageCount = ClaimSize >> PAGE_SHIFT; + + // + // Claim memory at specified virtual address + // + if (claim((void *)ActualBase, ClaimSize) == -1) { + fatal("Veneer: Couldn't claim %x bytes of VM at %x\n", + ClaimSize, ActualBase); + } + + // + // Set output parametes. + // + *LowAddress = ActualBase; +#ifdef XXX_I_KNOW_PE + *EntryAddress = ActualBase + + (OptionalHeader.AddressOfEntryPoint - OptionalHeader.BaseOfCode); +#else + *EntryAddress = ActualBase + OptionalHeader.AddressOfEntryPoint; +#endif XXX_I_KNOW_PE + + // + // Scan through the sections and either read them into memory or + // clear the memory as appropriate. + // + SectionOffset = 0; + for (i = 0, SHeader = SectionHeader; (ULONG) i < NumberOfSections; + i++, SHeader++) { + ULONG SectionBase; + + if ((FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) { + SectionBase = SHeader->VirtualAddress; + } else { +#ifdef XXX_I_KNOW_PE + SectionBase = ActualBase + SectionOffset; +#else + SectionBase = ActualBase + SHeader->VirtualAddress; +#endif XXX_I_KNOW_PE + + (RelocationTable+i)->PointerToRelocations = + SHeader->PointerToRelocations; + (RelocationTable+i)->NumberOfRelocations = + SHeader->NumberOfRelocations; + (RelocationTable+i)->FixupValue = + SectionBase - SHeader->VirtualAddress; + } + + // + // If the section is code or initialized data, then read + // the code or data into memory. + // + if ((SHeader->Characteristics & ( IMAGE_SCN_CNT_CODE | + IMAGE_SCN_CNT_INITIALIZED_DATA) ) != 0) { + SeekPosition.LowPart = SHeader->PointerToRawData; + SeekPosition.HighPart = 0; + if ((Status = VrSeek(FileId, &SeekPosition, SeekAbsolute)) + != ESUCCESS) { + break; + } + if ((Status = VrRead(FileId, (PVOID)SectionBase, + SHeader->SizeOfRawData, &Count)) != ESUCCESS) { + break; + } + if (Count != SHeader->SizeOfRawData) { + Status = EBADF; // XXXX + break; + } + + // + // Set the offset of the next section. + // + SectionOffset += SHeader->SizeOfRawData; + } else + if ((SHeader->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) + != 0) { + bzero((PVOID)SectionBase, SHeader->SizeOfRawData); + + // + // Set the offset of the next section. + // + SectionOffset += SHeader->SizeOfRawData; + } + } + + // + // If code has to be relocated, do so. + // + if ((FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) == 0) { + if (ActualBase != OptionalHeader.ImageBase) { + Status = VrRelocateImage( FileId, RelocationTable, + NumberOfSections, + FileHeader.PointerToSymbolTable); + } + } + + // + // Deallocate allocated area and close the file. + // + free((char*) SectionHeader); + free((char*) RelocationTable); + (VOID)VrClose(FileId); + + debug(VRDBG_LOAD, "VrLoad: Exit - EntryAddress: %x LowAddress: %x Status:%d\n", + *EntryAddress, *LowAddress, Status); + + return Status; +} + + + +/* + * Name: VrInvoke + * + * Description: + * This function invokes a previously loaded program. + * + * Arguments: + * EntryAddress- Supplies the execution address of the program to be loaded. + * StackAddress- Supplies the stack address that is used to reset the stack + * pointer before the program is invoked. + * Argc - Supplies the argument count for the program. + * Argv - Supplies a pointer to the argument list for the program. + * Envp - Supplies a pointer to the environment for the program. + * + * Return Value: + * ESUCCESS is returned if the address is invalid. + * EFAULT indicates an invalid address. + * + */ +ARC_STATUS +VrInvoke( + IN ULONG EntryAddress, + IN ULONG StackAddress, + IN ULONG Argc, + IN PCHAR Argv[], + IN PCHAR Envp[] + ) +{ + // + // Check for aligend address. + // + if ((EntryAddress & 0x3) == 0 && (StackAddress & 0x3) == 0) { +#ifdef notdef + free(VrDescriptorMemory); + VrMemoryListOrig = (PVR_MEMORY_DESCRIPTOR)NULL; +#endif // notdef + + PxInvoke(EntryAddress, StackAddress, Argc, Argv, Envp); + } else { + return EFAULT; + } + + return ESUCCESS; +} + + + +/* + * Name: VrExecute + * + * Description: + * This function reads the program specified by ImagePath into memory + * and then starts the program. If the loaded program returns, then + * control returns to the platform firmware, not to the caller. + * + * Arguments: + * ImagePath - Supplies a pointer to the pathname of the program + * to be loaded. + * Argc - Supplies the argument count for the program. + * Argv - Supplies a pointer to the argument list for the program. + * Envp - Supplies a pointer to the environment for the program. + * + * Return Value: + * ESUCCESS is returned if the address is invalid. + * EFAULT indicates an invalid address. + * + */ +ARC_STATUS +VrExecute( + IN PCHAR ImagePath, + IN ULONG Argc, + IN PCHAR Argv[], + IN PCHAR Envp[] + ) +{ + ARC_STATUS Status; + PMEMORY_DESCRIPTOR MemoryDescriptor; + ULONG BottomAddress; + CHAR TempPath[256]; + PULONG TransferRoutine; + + if (strlen(ImagePath) >= sizeof(TempPath)) { + return ENAMETOOLONG; + } + + // + // Copy the Arguments to a safe place as they can be in the running + // program space which can be overwritten by the program about + // to be loaded. + // + (VOID)VrCopyArguments(Argc, Argv); + strcpy(TempPath, ImagePath); + + // + // Reinitialize the memory descriptors + // + VrResetMemory(); + + // + // Look for a piece of free memory. + // + MemoryDescriptor = VrGetMemoryDescriptor(NULL); + while (MemoryDescriptor != NULL ) { + + // + // If the memory is at least 4 megabytes and is free attempt to + // load the program. + // + if ((MemoryDescriptor->MemoryType == MemoryFree) + && (MemoryDescriptor->PageCount >= 1024)) { + + // + // Set the top address to the top of the descriptor. + // + Status = VrLoad(TempPath, + ((MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) + << PAGE_SHIFT), + (PULONG)&TransferRoutine, + &BottomAddress); + + if (Status == ESUCCESS) { + + // + // Find the actual area of memory that was used, and generate + // a descriptor for it. Also, claim the according memory + // from OpenFirmware. + // +#ifdef XXX_MAKE_DESCRIPTOR + MemoryDescriptor = VrGetMemoryDescriptor(NULL); + while (MemoryDescriptor != NULL) { + if ((MemoryDescriptor->MemoryType == MemoryFree) + && (VrActualBasePage >= MemoryDescriptor->BasePage) + && ((VrActualBasePage + VrPageCount) <= + (MemoryDescriptor->BasePage + + MemoryDescriptor->PageCount)) ) { + break; + } + MemoryDescriptor = VrGetMemoryDescriptor(MemoryDescriptor); + } + if (MemoryDescriptor != NULL) { + Status = VrGenerateDescriptor(MemoryDescriptor, +#ifdef EXEC_MEM_TO_LOADED + MemoryLoadedProgram, +#else + MemoryFirmwareTemporary, +#endif // EXEC_MEM_TO_LOADED + VrActualBasePage, + VrPageCount); + if (Status != ESUCCESS) { + return Status; + } +#endif // XXX_MAKE_DESCRIPTOR + + + Status = VrInvoke((ULONG)TransferRoutine, + BottomAddress, + SavedArgs->Argc, + SavedArgs->Argv, + Envp ); +#ifdef EXEC_MEM_TO_LOADED +#else + MemoryDescriptor->MemoryType = MemoryLoadedProgram; +#endif // EXEC_MEM_TO_LOADED + return Status; + +#ifdef XXX_MAKE_DESCRIPTOR + } +#endif // XXX_MAKE_DESCRIPTOR + } + if (Status != ENOMEM) { + return Status; + } + } + + MemoryDescriptor = VrGetMemoryDescriptor(MemoryDescriptor); + } + + return ENOMEM; +} + + +/* + * Name: VrLoadInitialize + * + * Description: + * This routine initializes the firmware load services. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrLoadInitialize( + VOID + ) +{ + debug(VRDBG_ENTRY, "VrLoadInitialize BEGIN....\n"); + (PARC_LOAD_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[LoadRoutine] = VrLoad; + + (PARC_INVOKE_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[InvokeRoutine] = VrInvoke; + + (PARC_EXECUTE_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[ExecuteRoutine] = VrExecute; + + SavedArgs = new(SAVED_ARGUMENTS); + debug(VRDBG_ENTRY, "VrLoadInitialize ....END\n"); +} + + +/* + * Name: VrRelocateImage + * + * Description: + * This function relocates an image file that was not loaded into memory + * at the prefered address. + * + * Arguments: + * FileId - Supplies the file identifier for the image file. + * RelocationTable + * - Supplies a pointer to a table of section relocation info. + * + * Return Value: + * ESUCCESS is returned in the scan if\s successful. Otherwise, return + * an unsuccessful status. + * + */ +STATIC +ARC_STATUS +VrRelocateImage( + IN ULONG FileId, + IN PSECTION_RELOCATION_ENTRY RelocationTable, + IN ULONG NumberOfSections, + IN ULONG PointerToSymbolTable + ) +{ + IMAGE_RELOCATION RelocationEntry; + IMAGE_SYMBOL ImageSymbol; + LARGE_INTEGER SeekPosition; + ULONG Section, Index, Count, Offset; + PULONG FixupAddress; + ARC_STATUS Status; + + // + // Read the relocation table for each section. + // + for (Section = 0; Section < NumberOfSections; Section++) { + for (Index = 0; Index < RelocationTable[Section].NumberOfRelocations; + Index++) { + if (Index == 0) { + SeekPosition.LowPart = + RelocationTable[Section].PointerToRelocations; + SeekPosition.HighPart = 0; + if ((Status = VrSeek(FileId, &SeekPosition, SeekAbsolute)) + != ESUCCESS) { + return Status; + } + } + if ((Status = VrRead(FileId, (PCHAR)&RelocationEntry, + sizeof(RelocationEntry), &Count)) != ESUCCESS) { + return Status; + } + if (Count != sizeof(RelocationEntry)) { + return EBADF; + } + + // + // Get the address for the fixup. + // + FixupAddress = (PULONG)RelocationEntry.VirtualAddress + + RelocationTable[Section].FixupValue; + + // + // Read the symbol table. + // + SeekPosition.LowPart = PointerToSymbolTable + + RelocationEntry.SymbolTableIndex * sizeof(IMAGE_SYMBOL); + if ((Status = VrRead(FileId, (PCHAR)&ImageSymbol, + sizeof(ImageSymbol), &Count)) != ESUCCESS) { + return Status; + } + if (Count != sizeof(ImageSymbol)) { + return EBADF; + } + + // + // Apply the fixup. + // + if (ImageSymbol.StorageClass != IMAGE_SYM_CLASS_EXTERNAL) { + Offset = RelocationTable[ImageSymbol.SectionNumber].FixupValue; + } else { + Offset = 0; + } + + switch (RelocationEntry.Type) { + + // + // Absolute - no fixup required. + // + case IMAGE_REL_PPC_ABSOLUTE: + break; + + // + // 32-bit address - relocate the entire address. + // + case IMAGE_REL_PPC_ADDR32: + *FixupAddress += (ULONG)Offset; + break; + + // + // 26-bit address, 26-bit PC-relative offset + // + case IMAGE_REL_PPC_ADDR24: + case IMAGE_REL_PPC_REL24: + *FixupAddress = ((*FixupAddress) & 0xfc000003) + + ((*FixupAddress) & 0x03fffffc + (Offset << 2)) & 0x03fffffc; + break; + + // + // 16-bit address, 16-bit offset from TOC base + // + case IMAGE_REL_PPC_ADDR16: + case IMAGE_REL_PPC_TOCREL16: + *FixupAddress = ((*FixupAddress) & 0xffff0000) + + ((*FixupAddress) & 0x0000ffff + Offset) & 0x0000ffff; + break; + + // + // 14-bit address, 14-bit PC-relative offset, + // 14-bit offset from TOC base + // + case IMAGE_REL_PPC_ADDR14: + case IMAGE_REL_PPC_REL14: + case IMAGE_REL_PPC_TOCREL14: + *FixupAddress = ((*FixupAddress) & 0xffff0003) + + ((*FixupAddress) & 0x0000fffc + (Offset << 2)) & 0x0000fffc; + break; + + default: + fatal("Veneer: unknown relocation type %d\n", + RelocationEntry.Type); + } + } + } + + return ESUCCESS; +} + + +/* + * Name: VrCopyArguments + * + * Description: + * This routine copies the supplied arguments into the Veneer space. + * + * Arguments: + * Argc, Argv - Supply the arguments to be copied. + * + * Return Value: + * None. + * + */ +STATIC VOID +VrCopyArguments( + IN ULONG Argc, + IN PCHAR Argv[] + ) +{ + PUCHAR Source, Destination; + ULONG Index; + + SavedArgs->Argc = Argc; + Destination = &SavedArgs->Arguments[0]; + for (Index = 0; Index < Argc; Index++) { + Source = Argv[Index]; + SavedArgs->Argv[Index] = Destination; + while (*Destination++ = *Source++) ; + } +} + + +/* + * Name: VrResetMemory + * + * Description: + * This loops through and clears all of the appropriate memory, + * releasing the memory to OpenFirmware, and then calls VrCreateMemory + * to reset the memory descriptors. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrResetMemory( + VOID + ) +{ + PMEMORY_DESCRIPTOR MemoryDescriptor; + PVR_MEMORY_DESCRIPTOR CurDesc, FreeDesc; + + // + // Release all memory not used by the firmware. + // + MemoryDescriptor = VrGetMemoryDescriptor(NULL); + while (MemoryDescriptor != NULL) { + +#ifdef notdef + DisplayMemoryDescriptor(MemoryDescriptor); +#endif // notdef + + if ((MemoryDescriptor->MemoryType == MemoryLoadedProgram) || + (MemoryDescriptor->MemoryType == MemoryFreeContiguous)) { + + bzero((PVOID) (MemoryDescriptor->BasePage << PAGE_SHIFT), + (MemoryDescriptor->PageCount << PAGE_SHIFT)); + + OFRelease((PVOID)(MemoryDescriptor->BasePage << PAGE_SHIFT), + (MemoryDescriptor->PageCount << PAGE_SHIFT)); + } + + MemoryDescriptor = VrGetMemoryDescriptor(MemoryDescriptor); + } + + CurDesc = VrMemoryListOrig; + while(CurDesc != NULL) { + FreeDesc = CurDesc; + CurDesc = CurDesc->NextEntry; + free((char*)FreeDesc); + } + VrMemoryListOrig = (PVR_MEMORY_DESCRIPTOR) NULL; + VrCreateMemoryDescriptors(); +} + + +/* + * Name: VrGenerateDescriptor + * + * Description: + * This routine allocates a new memory descriptor to describe the + * specified region of memory. + * + * Arguments: + * MemoryDescriptor - Supplies a pointer to a free memory descriptor + * from which the specified memory is to be allocated. + * MemoryType - Supplies the type that is assigned to the allocated + * memory. + * BasePage - Supplies the base page number. + * PageCount - Supplies the number of pages. + * + * Return Value: + * + */ +ARC_STATUS +VrGenerateDescriptor( + IN PMEMORY_DESCRIPTOR MemoryDescriptor, + IN MEMORY_TYPE MemoryType, + IN ULONG BasePage, + IN ULONG PageCount + ) +{ + PVR_MEMORY_DESCRIPTOR MemDescriptor, NewDescriptor; + ULONG Offset; + + + MemDescriptor = (PVR_MEMORY_DESCRIPTOR) MemoryDescriptor; + + // + // Claim the memory from OpenFirmware. + // + if ((claim((void *)(BasePage << PAGE_SHIFT), PageCount << PAGE_SHIFT)) + == -1) { + return ENOMEM; + } + + // + // If the specified region totally consumes the free region, then no + // additional descriptors need to be allocated. If the specified region + // is at the start or end of the free region, then only one descriptor + // needs to be allocated. Otherwise, two additional descriptors need to + // be allocated. + // + Offset = BasePage - MemDescriptor->MemoryEntry.BasePage; + if ((Offset == 0) && (PageCount == MemDescriptor->MemoryEntry.PageCount)) { + + // + // The specified region totally consumes the free region. + // + MemDescriptor->MemoryEntry.MemoryType = MemoryType; + + } else { + + // + // A memory descriptor must be generated to describe the allocated + // memory. + // + NewDescriptor = new(VR_MEMORY_DESCRIPTOR); + NewDescriptor->MemoryEntry.MemoryType = MemoryType; + NewDescriptor->MemoryEntry.BasePage = BasePage; + NewDescriptor->MemoryEntry.PageCount = PageCount; + + // + // Insert Memory Descriptor List. + // + InsertMemDescriptor(NewDescriptor); + + // + // Determine whether an additional memory descriptor must be generated. + // + if (BasePage == MemDescriptor->MemoryEntry.BasePage) { + MemDescriptor->MemoryEntry.BasePage += PageCount; + MemDescriptor->MemoryEntry.PageCount -= PageCount; + } else { + if ((Offset + PageCount) == (MemDescriptor->MemoryEntry.BasePage + + MemDescriptor->MemoryEntry.PageCount)) { + + // + // The specified region lies at the end of the free region. + // + MemDescriptor->MemoryEntry.PageCount -= PageCount; + + } else { + + // + // The specified region lies in the middle of the free region. + // Another memory descriptor must be generated. + // + NewDescriptor = new(VR_MEMORY_DESCRIPTOR); + NewDescriptor->MemoryEntry.MemoryType = MemoryFree; + NewDescriptor->MemoryEntry.BasePage = BasePage + PageCount; + NewDescriptor->MemoryEntry.PageCount = + MemDescriptor->MemoryEntry.PageCount - PageCount - Offset; + + // + // Insert Memory Descriptor List. + // + InsertMemDescriptor(NewDescriptor); + + + MemDescriptor->MemoryEntry.PageCount = Offset; + } + } + } + + return ESUCCESS; +} + + +VOID +InsertMemDescriptor( + IN PVR_MEMORY_DESCRIPTOR MemDescriptor + ) +{ + PVR_MEMORY_DESCRIPTOR Entry; + + for (Entry = VrMemoryListOrig; Entry; Entry = Entry->NextEntry) { + if ((Entry->MemoryEntry.BasePage < MemDescriptor->MemoryEntry.BasePage) + && ((Entry->NextEntry == NULL) || + (Entry->NextEntry->MemoryEntry.BasePage > + MemDescriptor->MemoryEntry.BasePage))) { + + MemDescriptor->NextEntry = Entry->NextEntry; + Entry->NextEntry = MemDescriptor; + break; + } + } +} diff --git a/private/ntos/boot/veneer/vrmain.c b/private/ntos/boot/veneer/vrmain.c new file mode 100644 index 000000000..a90970420 --- /dev/null +++ b/private/ntos/boot/veneer/vrmain.c @@ -0,0 +1,1314 @@ +/* + * Copyright (c) 1994, 1996 FirePower Systems, Inc. + * Copyright 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * + * $RCSfile: vrmain.c $ + * $Revision: 1.41 $ + * $Date: 1996/06/25 03:02:44 $ + * $Locker: $ + * + * + * + * + * + * HISTORY + * 09-21-94 Shin Iwamoto at FirePower Systems Inc. + * Added some information in the system parameter block, + * such as signature. + * 07-21-94 Shin Iwamoto at FirePower Systems Inc. + * Added calling VrEnvInitialize() and VrMemoryInitialize() + * in VrInitSystem(). + * 07-20-94 Shin Iwamoto at FirePower Systems Inc. + * Moved here from VrInitSystem() and VrNotYet() originally + * in vrconfig.c. + * + */ + + +#include "veneer.h" + + +int VrDebug = 0; +BOOLEAN use_bat_mapping; + +/* + * Bootdev is either specified in the command line or if not is the device + * whence you booted. + * See create_argv() below for the magic used to fill in XYZZY. + */ +char *Bootpath = 0; +char *Osloader = 0; +char *SystemPath = 0; + +#define STR_XYZZY "xyzzy" +#define STR_OSLOADER "\\os\\winnt\\osloader.exe" +#define STR_OSLOADFN "\\WINNT" +#define STR_OSLOADPART STR_XYZZY +#define STR_LDIDENT "Windows NT 3.5" +#define STR_FWSEARCH STR_XYZZY +#define STR_FWTEST STR_XYZZY + +#define MAX_ARGC 16 +#define MAX_ENVC 16 +char *VrArgv[MAX_ARGC], *VrEnvp[MAX_ENVC]; +int VrArgc, VrEnvc; + +#define NEITHER 0 +#define ARGVONLY 1 +#define ENVONLY 2 +#define BOTH 3 + +struct argv_tab { + char *key; + char *val; + int which; + +} argv_tab[MAX_ARGC] = { + { "OsLoader", STR_OSLOADER, BOTH }, + { "SystemPartition", STR_XYZZY, BOTH }, + { "OSLoadFilename", STR_OSLOADFN, BOTH }, + { "OSLoadPartition", STR_OSLOADPART, BOTH }, + { "OSLoadOptions", "nodebug", BOTH }, + { "LoadIdentifier", STR_LDIDENT, BOTH }, + { "AutoLoad", "yes", ENVONLY }, + { "FWSearchPath", STR_FWSEARCH, ENVONLY }, + { "LastKnownGood", "False", ENVONLY }, + { "FWTEST", STR_FWTEST, ENVONLY } +}; + +STATIC VOID parse_args(VOID); +STATIC VOID find_boot_dev(VOID); +STATIC VOID collect_argv(VOID); +STATIC VOID create_argv(VOID); +STATIC VOID update_argv(char *, char *); +STATIC VOID add_argv(char *, char *); +STATIC VOID read_ARC_env_vars(VOID); +STATIC VOID add_envp(char *, char *); +STATIC VOID VrInitSystem (VOID); +STATIC VOID VrInitSystemBlock (VOID); +STATIC VOID VrNotYet(VOID); +STATIC VOID VrKseg0(VOID); +STATIC VOID move_amd_to_isa_hack(VOID); +STATIC VOID move_ide_to_isa_hack(VOID); +STATIC VOID move_scsi_children_to_ide_hack(VOID); +STATIC VOID move_multi_to_root(PCONFIGURATION_NODE); +STATIC CHAR *choose_args( char *, char *, int); +PCHAR VrCanonicalName( IN PCHAR Variable); + +/* LONG claimreal(PVOID, ULONG); */ +STATIC LONG claimphys(PVOID, ULONG, ULONG); +STATIC LONG map(PVOID, PVOID, ULONG, ULONG); +STATIC VOID check_mmu_type (VOID); +extern ULONG VrGetProcRev(); + +typedef VOID (*VR_NOT_YET_ROUTINE) (VOID); + +main(VOID *resid, VOID *entry, int (cif_handler)(long *)) +{ + ihandle bootih; + ULONG FileId; + ARC_STATUS res; + void (*jump_osloader)(int, char **, char**); + extern VOID Salutation(); + + Salutation(); + + VrInitSystemBlock(); + + check_mmu_type(); + + read_ARC_env_vars(); + + /* + * Do something with the arg string. + */ + parse_args(); + + // + // Set up the "kseg0" translation. + // + VrKseg0(); + + // + // Build the device tree. + // + debug(VRDBG_MAIN, "Building the device tree...\n"); + walk_obp((phandle) 0, + (PCONFIGURATION_NODE) 0, + (PCONFIGURATION_NODE) 0, + (PCONFIGURATION_NODE) 0 + ); + + // + // Move all MultiFunction adapters (usually PCI or ISA, + // presumably) to be children of the System Class (i.e., RootNode). + // This is because the NT kernel prefers to limit the complexity + // of nested bus nodes. + // + + debug(VRDBG_MAIN, "main: move all multi nodes to children of root...\n"); + move_multi_to_root(RootNode); + + debug(VRDBG_MAIN, "main: AMD nodes become children of isa...\n"); + move_amd_to_isa_hack(); + + debug(VRDBG_MAIN, "Done with the device tree.\n"); + if (VrDebug & VRDBG_DUMP) { + dump_tree(RootNode); + sleep(10); + } else if (VrDebug & VRDBG_CONFIG) { + quick_dump_tree(RootNode); + sleep(10); + } + + // + // Build the system parameter block. + // + debug(VRDBG_MAIN, "main: Build the system parameter block...\n"); + VrInitSystem(); + + // + // Determine the boot path and translate it to ARC form. + // + debug(VRDBG_MAIN, "main: find boot device...\n"); + find_boot_dev(); + debug(VRDBG_MAIN, "main: create argument and environment lists...\n"); + create_argv(); + warn("Booting from '%s'\n", VrArgv[0]); + + res = VrOpen(VrArgv[0], ArcOpenReadOnly, &FileId); + if (res != ESUCCESS) { + fatal("VrOpen returned %x\n", res); + } + + debug(VRDBG_MAIN, "main: setup boot ihandle, jump_osloader handle...\n"); + bootih = FileTable[FileId].IHandle; + jump_osloader = load_file(bootih); + VrClose(FileId); + VrFlushAllCaches(); + + debug(VRDBG_MAIN, "main: create memory descriptor list...\n"); + VrCreateMemoryDescriptors(); + if (VrDebug & VRDBG_MEM) { + DisplayMemory(); + } + + if (VrDebug & VRDBG_HOLDIT) { + + warn("Jumping to 0x%x\n", (char *)jump_osloader); + puts("This time for sure!"); + OFEnter(); + } else { + puts("\233H\233J"); // Clear screen + } + debug(VRDBG_MAIN, "main: launch OSLOADER!!! ...\n"); + jump_osloader(VrArgc, VrArgv, VrEnvp); + OFExit(); + return (0); +} + +STATIC VOID +check_mmu_type(VOID) +{ + ihandle ih; + + ih = get_int_prop (OFFinddevice("/chosen"), "cpu"); + if (ih == -1) { + use_bat_mapping = TRUE; + } else { + use_bat_mapping = + (OFGetproplen(OFInstanceToPackage(ih),"603-translation") == -1); + } +} + +#define NEXT_TOKEN() if ((bootargs = strctok(NULL, ' ')) == NULL) return; + +STATIC VOID +parse_args(VOID) +{ + phandle ph; + char *bootargs; + char *key, *val; + struct argv_tab *atp = argv_tab; + + ph = OFFinddevice("/chosen"); + if (ph == 0) { + warn("parse_args: No phandle for '/chosen'\n"); + return; + } + + debug(VRDBG_MAIN, "parse_args: /chosen phandle %x\n", ph); + bootargs = get_str_prop(ph, "bootargs", ALLOC); + if (bootargs == NULL || *bootargs == '\0') { + return; + } + debug(VRDBG_MAIN, "bootargs: '%s'\n", bootargs); + + bootargs = strctok(bootargs, ' '); + if (bootargs[0] != '-') { + + debug(VRDBG_MAIN, "Boot file '%s'\n", bootargs); + if (bootargs[0] == '\\') { + + // + // We're just specifying the file to boot: + // update the OsLoader argument but nothing else. + // + update_argv("OsLoader", bootargs); + + } else { + + // + // Without a leading backslash, bootargs presumably + // contains a full device path. + // If so, update both Bootpath and OsLoader. + // + Bootpath = bootargs; + if (key = index(Bootpath, '\\')) { + val = (char *) malloc(strlen(key)+1); + strcpy(val, key); + update_argv("OsLoader", val); + *key = '\0'; + } + } + + debug(VRDBG_MAIN, "Bootpath '%s'\n", Bootpath); + for ( ; atp->key != NULL; ++atp) { + if (strcmp("OsLoader", atp->key) == 0) { + debug(VRDBG_MAIN, "OsLoader '%s'\n", atp->val); + break; + } + } + NEXT_TOKEN(); + } + + while (bootargs && (*bootargs != '\0')) { + if (strncmp(bootargs, "-vrdebug", 8) == 0) { + NEXT_TOKEN(); + debug(VRDBG_MAIN, "-vrdebug: '%s'\n", bootargs); + VrDebug = atoi(bootargs); + continue; + } + if (strncmp(bootargs, "-env", 4) == 0) { + NEXT_TOKEN(); + key = bootargs; + NEXT_TOKEN(); + val = bootargs; + debug(VRDBG_MAIN, "-env: '%s' '%s'\n", key, val); + update_argv(key, val); + } + if (strncmp(bootargs, "-h", 2) == 0) { + VrDebug |= VRDBG_HOLDIT; + } + NEXT_TOKEN(); + } +} + +STATIC VOID +update_argv(char *key, char *val) +{ + struct argv_tab *atp = argv_tab; + + for ( ; atp->key != NULL; ++atp) { + if (strcmp(key, atp->key) == 0) { + atp->val = val; + return; + } + } + if (atp >= &argv_tab[MAX_ARGC]) { + warn("You can't define any more argument variables\n"); + return; + } + atp->key = key; + atp->val = val; + atp->which = BOTH; +} + +#define CSI '\233' +#define ESC '\033' + +STATIC INT +select_boot(VOID) +{ + char *ids[16]; + char *prop, c; + int i= 0, choices, chosen, countdown, csi, count; + debug(VRDBG_ENTRY,"select_boot: VOID BEGIN....\n"); + + // + // Determine how long to display the list of options: + // + prop = VrGetEnvironmentVariable("COUNTDOWN"); + if (prop == NULL) { + countdown = 10; + } else { + countdown = atoi(prop); + } + + // + // get the text list of possible options. + // + prop = VrGetEnvironmentVariable("LOADIDENTIFIER"); + if (prop == NULL) { + return(0); + } + + // + // tokenize the string of load options, creating pointers to each + // component of the string. Don't use strctok, since we need to + // worry about detecting null entries in the OsLoadOptions list. + // + ids[i++] = prop; // stuff the first one in the array.... + while ((prop = index(prop, ';')) != NULL) { + *prop = '\0'; // change the separator to a null + prop++; + ids[i++] = prop; + } + choices = i; + while (i < 16) { + ids[i++] = NULL; + } + + // + // here be the wheel of fortune: Makes yer choice and be off wid ya + // + chosen = 0; + csi = 0; + warn("\233H\233J"); // Clear screen + Salutation(); + puts("\233""24;1HMake selection using arrow keys and 'Enter', or press ESC to cancel"); + countdown += VrGetRelativeTime(); +again: + for (i = 0; i < choices; ++i) { + if (i == chosen) { + warn("\233%d;1H\233K\233%d;3H\233""7m* %s\233""m\n", + i+3, i+3, ids[i]); + } else { + warn("\233%d;1H\233K\233%d;5H%s\n", i+3, i+3, ids[i]); + } + } + i = 0; + warn("\233%d;1H\233K\n", choices+5); + while (VrGetReadStatus(0)) { + if (countdown == -1) { + continue; + } + if (VrGetRelativeTime() > (unsigned) countdown) { + goto out; + } + if (VrGetRelativeTime() != (unsigned) i) { + warn("\233%d;1H\233K\233%d;5HSeconds remaining: %d\n", + choices+5, choices+5, countdown - VrGetRelativeTime()); + i = VrGetRelativeTime(); + } + } + countdown = -1; + (void) VrRead(0, &c, 1, &count); + if (csi) { + switch (c) { + case 'A': chosen = max(chosen - 1, 0); break; + case 'B': chosen = min(chosen + 1, choices-1); break; + } + csi = 0; + } else { + switch (c) { + case CSI: csi = 1; break; + case '\r': goto out; + case '\n': goto out; + case ESC: OFExit(); + + case 'k': // vi + case '\020': // emacs + case '+': // good guesses + case '<': + chosen = max(chosen - 1, 0); break; + case 'j': + case '\016': + case '-': + case '>': + chosen = min(chosen + 1, choices-1); break; + + case '\t': + if (++chosen == choices) { + chosen = 0; + } + break; + } + } + goto again; + +out: + warn("\233H\233J"); // Clear screen + // + // Given the chosen number, pull out the corresponding string, and + // setup the Bootpath and SystemPath variables: + // + Bootpath = choose_args("OSLOADER", "OsLoader", chosen); + SystemPath = choose_args("SYSTEMPARTITION", "SystemPartition", chosen); + + // + // get the rest of the options..... + // + choose_args("OSLOADPARTITION", "OSLoadPartition", chosen); + choose_args("OSLOADOPTIONS", "OSLoadOptions", chosen); + choose_args("LOADIDENTIFIER", "LoadIdentifier", chosen); + choose_args("OSLOADFILENAME", "OSLoadFilename", chosen); + + debug(VRDBG_ENTRY,"select_boot: VOID ....END\n"); + return(1); +} + +STATIC CHAR * +choose_args( char *EnvVar, char *Varrrg, int achoice ) +{ + char *prop, *cp; + int i= 0; + debug(VRDBG_ENTRY, + "choose_args: EnvVar: %s Varrrg: %s achoice: 0x%x BEGIN....\n", + *EnvVar, *Varrrg, achoice); + prop = VrGetEnvironmentVariable(EnvVar); + //debug(VRDBG_TEST, "\n@%d: prop is currently...%s:\n",i,prop); + if (prop == NULL) { + return(0); + } + prop = strcsep(prop, ';'); + for (i = 0; i < achoice; ++i) { + if ((prop = strcsep(NULL, ';')) == NULL) { + return(0); + } + } + cp = zalloc(strlen(prop) +1 ); + strcpy(cp, prop); + update_argv(Varrrg, cp); + //debug(VRDBG_TEST, "@%d: cp is set to...%s:\n",i,cp); + debug(VRDBG_ENTRY, "choose_args: ....END\n"); + return( cp ); +} + +STATIC VOID +find_boot_dev(VOID) +{ + phandle ph; + char *bootpath; + PCONFIGURATION_NODE node; + + if (Bootpath) { + debug(VRDBG_MAIN, "Bootpath has been set from the command line\n"); + return; + } + if (select_boot()) { + debug(VRDBG_MAIN, "We chose a boot device from LOADIDENTIFIER menu.\n"); + return; + } + + // Use whatever device we booted the veneer from. + ph = OFFinddevice("/chosen"); + bootpath = get_str_prop(ph, "bootpath", NOALLOC); + if (bootpath == NULL) { + warn("find_boot_dev: No property '/chosen:bootpath'\n"); + return; + } + debug(VRDBG_MAIN, "find_boot_dev: bootpath (len %d) '%s'\n", + strlen(bootpath), bootpath); + node = PathToNode(bootpath); + if (node == NULL) { + warn("find_boot_dev: Couldn't find node for '%s'\n", bootpath); + return; + } + Bootpath = NodeToArcPath(node); + bootpath = (char *)malloc(strlen(Bootpath) + strlen("partition(1)") + 1); + strcpy(bootpath, Bootpath); + strcat(bootpath, "partition(1)"); /* XXX */ + free(Bootpath); + Bootpath = bootpath; + debug(VRDBG_MAIN, "find_boot_dev: bootpath '%s'\n", Bootpath); +} + +/* + * + * ROUTINE: VOID read_ARC_env_vars(VOID) + * + * DESCRIPTIN: + * Initialize the arc argument table with the values contained in open + * firmware. + * + */ + +STATIC VOID +read_ARC_env_vars(VOID) +{ + struct argv_tab *atp; + char *val, *newval; + + // + // for each variable in the argv_tab array, find the actual value + // this system has in firmware. + // + for (atp = argv_tab; atp < &argv_tab[MAX_ARGC] && atp->key; ++atp) { + if ((val = VrGetEnvironmentVariable(atp->key)) != NULL) { + newval = (char *) malloc(strlen(val) + 1); + strcpy(newval, val); + atp->val = newval; + } + } +} + +STATIC VOID +create_argv(VOID) +{ + struct argv_tab *atp; + char *osloader, *old_osloader = ""; + char *buf; + phandle ph; + extern char *VeneerVersion(); + + /* + * First instantiate the boot partition string in the + * OS Loader arguments table. By the way, when we find + * STR_OSLOADER, save it to produce the argv[0] and OsLoader + * arguments. + */ + for (atp = argv_tab; atp < &argv_tab[MAX_ARGC] && atp->key; ++atp) { + if (strcmp(atp->val, STR_XYZZY) == 0) { + atp->val = Bootpath; + } + if (strcmp(atp->key, "OsLoader") == 0) { + old_osloader = atp->val; + } + } + + /* + * Initialize the argv/envp arrays. + */ + VrArgc = VrEnvc = 0; + bzero((PCHAR) VrArgv, MAX_ARGC * sizeof(PCHAR)); + bzero((PCHAR) VrEnvp, MAX_ENVC * sizeof(PCHAR)); + VrEnvp[VrEnvc] = ""; + + /* + * Construct argv[0], the boot string (special case). + */ + if (old_osloader[0] == '\\') { + osloader = zalloc(strlen(Bootpath) + strlen(old_osloader) + 1); + strcpy(osloader, Bootpath); + strcat(osloader, old_osloader); + } else { + osloader = old_osloader; + } + add_argv("", osloader); + + /* + * Now walk the argv table, building the argv and envp + * arrays. When we encounter OsLoader, be sure to use the + * buffer we just built, rather than the table value. + */ + for (atp = argv_tab; atp < &argv_tab[MAX_ARGC] && atp->key; ++atp) { + if (strcmp(atp->key, "OsLoader") == 0) { + atp->val = osloader; + } + if (atp->which != ENVONLY) { + add_argv(atp->key, atp->val); + } + if (atp->which != ARGVONLY) { + add_envp(atp->key, atp->val); + } + if (strcmp(atp->key, "SystemPartition" ) == 0 ){ + atp->val = SystemPath; + } + } + + /* + * Record the version strings. + */ + ph = OFFinddevice("/openprom"); + add_envp("FirmwareVersion", get_str_prop(ph, "model", NOALLOC)); + add_envp("VeneerVersion", VeneerVersion()); + + /* + * Finally, take care of the console paths, set at runtime. + */ + buf = VrFindConsolePath("stdin"); + add_argv("ConsoleIn", buf); + add_envp("ConsoleIn", buf); + free(buf); + + buf = VrFindConsolePath("stdout"); + add_argv("ConsoleOut", buf); + add_envp("ConsoleOut", buf); + free(buf); +} + + +STATIC VOID +add_argv(PCHAR key, PCHAR val) +{ + char *buf; + int len; + + len = strlen(key); + if (len) { + len += 1; // for '=' + } + len += strlen(val); + buf = (char *) zalloc(len+1); + strcpy(buf, key); + if (*buf != '\0') { + strcat(buf, "="); + } + strcat(buf, val); + VrArgv[VrArgc] = buf; + if ((buf = index(buf, ';')) != NULL) { + *buf = '\0'; + } + debug(VRDBG_ARGV, "Argv[%d]: %s\n", VrArgc, VrArgv[VrArgc]); + VrArgc += 1; +} + +/* + * ROUTINE: VOID add_envp( PCHAR, PCHAR ) + * + * DESCRIPTION: + * Add the passed in name string and value into an array + * of string/value pairs that describes the environment for + * the arc program to be executed. The entry in the array is + * of the form "name=value", and is added to the beginning of + * the array. + * + * RETURN: + * Returns nothing. + * + */ + +STATIC VOID +add_envp(PCHAR key, PCHAR val) +{ + char *buf; + int len; + + len = strlen(key); + if (len) { + len += 1; // for '=' + } + len += strlen(val); + buf = (char *) zalloc(len+1); + strcpy(buf, VrCanonicalName(key)); + if (*buf != '\0') { + strcat(buf, "="); + } + strcat(buf, val); + VrEnvp[VrEnvc+1] = VrEnvp[VrEnvc]; + VrEnvp[VrEnvc] = buf; + debug(VRDBG_ENV, " Env[%d]: %s\n", VrEnvc, VrEnvp[VrEnvc]); + VrEnvc += 1; +} + +static +int +is_mp_capable(ULONG VerRev) +{ + ULONG ver = (VerRev >> 16) & 0xFFFF; + ULONG rev = VerRev & 0xFFFF; + + switch(ver) { + + case PPC_604: + if ( rev > 0x0304 ) + return(1); + break; + + case PPC_604E: + return(1); + + default: + return(0); + + } + return(0); + +} + + +// +// The routines that follow initialize the System Parameter Block, +// Firmware Vector Table, and Restart Blocks. +// +// Note the use of MAP() and UNMAP() macros. The kernel requires that +// addresses in the System Parameter Block and Restart Blocks be +// VIRTUAL, not physical. Therefore, all addresses that may be presented +// to the kernel must be mapped to KSEG0; i.e., they must be in the +// range starting at 0x80000000. +// + +STATIC PRESTART_BLOCK last_rstb = 0; + +STATIC PRESTART_BLOCK +InitRestartBlocks(PCONFIGURATION_NODE node, PRESTART_BLOCK rstb) +{ + PRESTART_BLOCK new_rstb; + + debug(VRDBG_ENTRY, "InitRestartBlocks: Begin(0x%x, 0x%x)...\n",node, rstb); + VRDBG(VRDBG_ENTRY, vr_dump_config_node(node)); + + if (node->Component.Class == ProcessorClass && + node->Component.Type == CentralProcessor) { + + // Figure out where the next node's space should be. + if (rstb) { + new_rstb = (PRESTART_BLOCK) ((PCHAR) rstb + sizeof(RESTART_BLOCK)); + } else { + new_rstb = (PRESTART_BLOCK) ((PCHAR) SYSTEM_BLOCK + + SYSTEM_BLOCK->Length + SYSTEM_BLOCK->FirmwareVectorLength); + } + + // Claim the space and turn it into a restart block. + if (CLAIM((VOID *)new_rstb, sizeof(RESTART_BLOCK)) == -1) { + fatal("Couldn't claim RESTART BLOCK\n"); + } + + if (rstb) { + rstb->NextRestartBlock = (PRESTART_BLOCK) UNMAP(new_rstb); + } + rstb = new_rstb; + last_rstb = new_rstb; + + bzero((PCHAR) rstb, sizeof(RESTART_BLOCK)); + rstb->Signature = ARC_RESTART_BLOCK_SIGNATURE; + rstb->Version = 1; + rstb->Revision = 2; + rstb->Length = sizeof(RESTART_BLOCK); + rstb->SaveAreaLength = sizeof(PPC_RESTART_STATE); +// rstb->BootStatus.BootFinished = 1; + rstb->BootStatus.ProcessorReady = 1; + rstb->ProcessorId = node->Component.Key; + if (rstb->ProcessorId == 0) { + rstb->BootStatus.ProcessorStart = 1; + rstb->BootStatus.ProcessorRunning = 1; + } else { + rstb->BootStatus.ProcessorStart = 0; + } + } + + if (node->Child) { + rstb = InitRestartBlocks(node->Child, rstb); + } + if (node->Peer) { + rstb = InitRestartBlocks(node->Peer, rstb); + } + + debug(VRDBG_ENTRY, "InitRestartBlocks: ....Exit\n"); + return (rstb); +} + +STATIC VOID +SumRestartBlocks(PRESTART_BLOCK rstb) +{ + PLONG up = (PLONG) rstb; + LONG accum = 0; + + debug(VRDBG_ENTRY, "SumRestartBlocks: Begin(0x%x)....\n", rstb); + rstb->CheckSum = 0; + while (up < (PLONG) ((PCHAR) rstb + sizeof(RESTART_BLOCK))) { + accum += *up++; + } + rstb->CheckSum = -accum; + debug(VRDBG_ENTRY, "SumRestartBlocks: ....Exit\n", rstb); +} + +STATIC int +IdleCPU(PRESTART_BLOCK rstb, int stopFlag) +{ + STATIC PVOID IdleLoop = 0; + STATIC PULONG Bootp; + STATIC ULONG ProcRev=0; + STATIC INT mismatchFlag = 0; + ULONG IdleLoopSize; + ULONG res, timeout; + extern PVOID ArcPoll, EndArcPoll; + + // cpu0 is always successful so that we can have a + // uniprocessor system in hand + if (rstb->ProcessorId == 0) { + ProcRev = VrGetProcRev(); + if (!is_mp_capable(ProcRev)) + mismatchFlag = 1; + return(0); + } + + // The processor idle loop must be in FirmwarePermanent memory, + // so that it's not disturbed by kernel startup. Identify a piece + // of memory just after the last restart block and copy in the + // idle loop code. + + if (IdleLoop == 0) { + IdleLoop = (PCHAR) last_rstb + sizeof(RESTART_BLOCK); + IdleLoopSize = (ULONG) &EndArcPoll - (ULONG) &ArcPoll; + + // Pad to make room for BootStatus and SaveArea variables. + Bootp = (PULONG) IdleLoop; + (PCHAR) IdleLoop += 3 * sizeof(ULONG); + IdleLoopSize += 3 * sizeof(ULONG); + + if (CLAIM(IdleLoop, IdleLoopSize) == -1) { + fatal("Couldn't claim MP idle loop\n"); + } + bcopy((PCHAR) &ArcPoll, IdleLoop, IdleLoopSize); + VrFlushAllCaches(); + } + + // + // Set this processor spinning in the new idle loop. + // XXX - To do: change this to CIF. + // Since we're running in virtual mode that is mapped virtual 0 + // to physical 0, this assignment translates directly into the + // real mode addresses the IdleCPU routine will end up executing. + // + Bootp[0] = 0; // processor version returned by the cpu + Bootp[1] = (ULONG) &rstb->BootStatus; + Bootp[2] = (ULONG) &rstb->u.SaveArea; + + // Give the other processor plenty of time to start up: he may be + // executing debug printouts and other slow tasks before switching. + // Five seconds should be more than adequate. + + debug(VRDBG_TMP, "Executing non 0 processor at 0x%x\n", IdleLoop); + res = 0; + if (OFInterpret(1, 3, &res, "cpu-execute-code", rstb->ProcessorId, IdleLoop) != 0) { + return(-1); + } + if (res == 0) + return(-1); + + // + // wait a small amount of time for the other processor to + // start up. Since VrGetRelative time returns the time since + // power-on/reset, tack on a few seconds for the waiting period. + // + //timeout = VrGetRelativeTime() + (5 * 1000); + timeout = VrGetRelativeTime() + (5 * 1); // 5 seconds should be + // long enough + + do { + if (Bootp[1] == 0x1234) { + debug(VRDBG_TMP,"ProcRev = 0x%x; return = 0x%x\n", + Bootp[0], Bootp[1]); + if ( Bootp[0] != ProcRev || mismatchFlag || stopFlag) { + Bootp[1] = 0xBAD; + return(-1); + } else { + Bootp[1] = 0xCAFE; + return(0); + } + } + } while (VrGetRelativeTime() < timeout); + fatal("Processor %d failed to enter MP idle loop.\n", rstb->ProcessorId); +} + + +/* + * Routine Description: + * This routine initializes the firmware vector in the system parameter + * block. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ + +STATIC VOID +VrInitSystem(VOID) +{ + LONG i; + LONG FirmwareVectorLen; + PRESTART_BLOCK rstb, PrevRstb; + int NumOfCpu = 0 , NumProc = 0; + ULONG ProcMask = 0, maskscan = 0; + PCHAR evp; + + debug(VRDBG_ENTRY, "VrInitSystem: BEGIN....\n"); + // + // Initialize the system parameter block + // + FirmwareVectorLen = (ULONG)MaximumRoutine * sizeof(ULONG); + i = sizeof(SYSTEM_PARAMETER_BLOCK) + FirmwareVectorLen; + debug(VRDBG_ENTRY, "VrInitSystem: i(0x%x), FirmwareVectorLen(0x%x) set:\n", + i, FirmwareVectorLen); + +#if 0 + // + // THis is now down in a different routine called by main. + // + // + // attempting to setup all the claiming early on + // + if (use_bat_mapping) { + res = claim((PVOID) SYSTEM_BLOCK, i); + } else { + res = claimreal((PVOID) SYSTEM_BLOCK, i); + } + if (res == -1) { + fatal("Couldn't claim SYSTEM PARAMETER BLOCK\n"); + } + bzero((PCHAR)SYSTEM_BLOCK, i); +#endif + + + debug(VRDBG_ENTRY, "VrInitSystem: Init SYSTEM_BLOCK.. \n"); + SYSTEM_BLOCK->Signature = SYSTEM_BLOCK_SIGNATURE; + SYSTEM_BLOCK->Version = ARC_VERSION; + SYSTEM_BLOCK->Revision = ARC_REVISION; + SYSTEM_BLOCK->Length = sizeof(SYSTEM_PARAMETER_BLOCK); + + SYSTEM_BLOCK->FirmwareVector = + (PVOID) UNMAP((PCHAR) SYSTEM_BLOCK + SYSTEM_BLOCK->Length); + SYSTEM_BLOCK->FirmwareVectorLength = FirmwareVectorLen; + + // + // Initialize the restart blocks. + // + debug(VRDBG_ENTRY, "VrInitSystem: Init restart blocks\n"); + SYSTEM_BLOCK->RestartBlock = (PRESTART_BLOCK) UNMAP((PCHAR) SYSTEM_BLOCK + + SYSTEM_BLOCK->Length + SYSTEM_BLOCK->FirmwareVectorLength); + if (InitRestartBlocks(RootNode, 0)) { + rstb = (PRESTART_BLOCK) MAP(SYSTEM_BLOCK->RestartBlock); + PrevRstb = 0; + NumOfCpu = 0; + ProcMask = 0xFFFFFFFF; + if ( (evp = VrGetEnvironmentVariable("PROCESSORS")) != NULL ) + ProcMask = atoi(evp) | 1; + maskscan = 1; + while (rstb) { + SumRestartBlocks(rstb); + + if (IdleCPU(rstb,(ProcMask&maskscan) == 0 ) == -1) { + ProcMask &= ~maskscan; // clear the bit + // remove the restart block + PrevRstb->NextRestartBlock = rstb->NextRestartBlock; + } else { + NumOfCpu++; + PrevRstb = rstb; + } + maskscan <<= 1; + rstb = (PRESTART_BLOCK) MAP(PrevRstb->NextRestartBlock); + } + } else { + SYSTEM_BLOCK->RestartBlock = 0; + } + + + // + // Temporarily make all firmware vector to point to an error routine. + // + for (i=LoadRoutine; i < MaximumRoutine; i++) { + (VR_NOT_YET_ROUTINE)SYSTEM_BLOCK->FirmwareVector[i] = VrNotYet; + } + + // + // Initialize the firmware vectors for other functions. + // + VrEnvInitialize(); + VrMemoryInitialize(); + VrIoInitialize(); + VrDisplayInitialize(); + VrLoadInitialize(); + VrRestartInitialize(); + VrConfigInitialize(); + VrTimeInitialize(); + debug(VRDBG_ENTRY, "VrInitSystem: .....END\n"); +} + +STATIC VOID +VrNotYet( VOID ) +{ + fatal("This ARC function is not yet implemented\n"); +} + + +STATIC VOID +move_multi_to_root(PCONFIGURATION_NODE node) +{ + PCONFIGURATION_NODE child = node->Child; + PCONFIGURATION_NODE peer = node->Peer; + PCONFIGURATION_NODE n; + ULONG key; + + debug(VRDBG_ENTRY, "move_multi_to_root: node 0x%x\n", node); + if (node == 0) { + debug(VRDBG_TREE, "move_multi_to_root: node is 0, return.\n"); + return; + } + debug(VRDBG_TREE, "MMTR: move node: 0x%x to child of ROOT\n",node); + VRDBG(VRDBG_TREE, vr_dump_config_node(node)); + + // Examine the first child, and keep promoting it/them until + // the first child is no longer of type multi. + + while ( (child) && (child->Component.Type == MultiFunctionAdapter)) { + for (n = RootNode->Child, key = 0; n->Peer; n = n->Peer) { + if (n->Component.Type == MultiFunctionAdapter) { + key = max(key, n->Component.Key); + } + } + if (n->Component.Type == MultiFunctionAdapter) { + key = max(key, n->Component.Key); + } + child->Parent = RootNode; + n->Peer = child; + node->Child = child->Peer; + child->Peer = 0; + child->Component.Key = key + 1; + child = node->Child; + } + + // Process the entire Child branch. + + move_multi_to_root(child); + + // Now for the Peer branch: first, if our parent is the root, + // there's no need to promote the peer node, so skip the next step. + + if (node->Parent != RootNode) { + + // As before, promote peers until the peer isn't a multi node... + + while (peer && peer->Component.Type == MultiFunctionAdapter) { + for (n = RootNode->Child, key = 0; n->Peer; n = n->Peer) { + if (n->Component.Type == MultiFunctionAdapter) { + key = max(key, n->Component.Key); + } + } + if (n->Component.Type == MultiFunctionAdapter) { + key = max(key, n->Component.Key); + } + peer->Parent = RootNode; + n->Peer = peer; + node->Peer = peer->Peer; + peer->Peer = 0; + peer->Component.Key = key + 1; + peer = node->Peer; + } + } + + // ...and process the Peer branch. Since our traversal is depth-first + // and promoted nodes are appended to the RootNode's Child's Peer branch + // (and are thus processed last), this routine should suffice to traverse + // the entire tree. + + move_multi_to_root(peer); +} + + +LONG +claimreal(PVOID addr, ULONG size) +{ + if (claimphys((PVOID) MAP(addr), size, 0) == -1) { + return(-1); + } + return(map((PVOID) MAP(addr), addr, size, (ULONG) -1)); +} + +STATIC LONG +claimphys(PVOID physical, ULONG size, ULONG align) +{ + static ihandle memih = 0; + ULONG base; + + if (memih == 0) { + if((memih = get_int_prop(OFFinddevice("/chosen"), "memory")) == 0) { + fatal("Couldn't open the memory node"); + } + } + return(OFCallMethod(1, 5, &base, + "claim", memih, align, size, (ULONG) physical)); +} + +STATIC LONG +map(PVOID physical, PVOID virtual, ULONG size, ULONG mode) +{ + static ihandle mmuih = 0; + + if (mmuih == 0) { + if((mmuih = get_int_prop(OFFinddevice("/chosen"), "mmu")) == 0) { + fatal("Couldn't open the MMU node"); + } + } + return(OFCallMethod(0, 6, 0, + "map", mmuih, mode, size, virtual, (ULONG) physical)); +} + +/* + * Because the PowerPC port is based on the MIPS port, and no one saw fit + * to re-examine assumptions in the light of the PowerPC architecture, + * the NT kernel et al. are expected to reside in kseg0 (8000.0000-a000.000). + * Set up a virtual mapping for this region. + */ +STATIC VOID +VrKseg0(VOID) +{ + ihandle ih; + + debug(VRDBG_MAIN, "Mapping in kseg0...\n"); + ih = get_int_prop(OFFinddevice("/chosen"), "mmu"); + if (ih == 0) { + fatal("Couldn't open the MMU node; kseg0 translation not set up.\n"); + } + OFCallMethod(0, 6, 0, "map", ih, -2, 0x800000, 0x80000000, 0); + return; +} + +/* + * XXX - This is a hack for the AMD79C974 Ethernet chip driver: the driver + * assumes the chip is on the ISA bus. + */ + +STATIC void +move_amd_to_isa_hack(void) +{ + phandle ph; + PCONFIGURATION_NODE amdnode, peernode, isanode; + + if ((ph = OFFinddevice("/pci/AMD,79c970@4")) == -1) { + debug(VRDBG_MAIN, "No AMD ethernet found\n"); + return; + } + + peernode = PathToNode("/pci"); + peernode = peernode->Child; + + if (peernode->OfPhandle == ph) { + amdnode = peernode; + peernode->Parent->Child = peernode->Peer; + } else { + while (peernode->Peer && (peernode->Peer->OfPhandle != ph)) { + peernode = peernode->Peer; + } + amdnode = peernode->Peer; + peernode->Peer = amdnode->Peer; + } + + isanode = PathToNode("/pci/isa"); + if (isanode->Child == NULL) { + isanode->Child = amdnode; + amdnode->Peer = NULL; + } else { + peernode = isanode->Child; + while (peernode->Peer) { + peernode = peernode->Peer; + } + amdnode->Peer = peernode->Peer; + peernode->Peer = amdnode; + } + amdnode->Parent = isanode; +} + +STATIC void +move_ide_to_isa_hack(void) +{ + PCONFIGURATION_NODE node, idenode = 0, isanode; + int lastkey = 0; + + isanode = PathToNode("/pci/isa"); + node = isanode->Child; + while (node) { + if (strcmp(node->ComponentName, "disk") == 0) { + lastkey = max(lastkey, (int) node->Component.Key); + } + if (strcmp(node->Component.Identifier, "IDE") == 0) { + idenode = node; + } + node = node->Peer; + } + if (idenode == 0) { + return; + } + + node = isanode->Child; + while (node->Peer != idenode) { + node = node->Peer; + } + node->Peer = node->Peer->Peer; /* Bypass ide node */ + while (node->Peer) { + node = node->Peer; + } + node->Peer = idenode->Child; + + while (node->Peer) { + node->Peer->Parent = node->Parent; + if (strcmp(node->Peer->ComponentName, "disk") == 0) { + node->Peer->Component.Key = ++lastkey; + } + node = node->Peer; + } +} + +/* + * move_scsi_children_to_ide_hack() moves the children (e.g. disk and cdrom) + * of the SCSI node to be children of the IDE node, and changes the IDE's + * phandle pointer to point to the Open Firmware SCSI node. + * + * This egregious hack is necessary for the initial release of IBM's "Harley" + * evaluation system. On that system, IBM's portable boot loader misrepresents + * the hardware by reporting the SCSI disk and SCSI CD-ROM devices as children + * of the IDE node in the ARC tree! The IDE and SCSI nodes themselves are in + * the correct places in the ARC tree, but the children are in the wrong + * place. The enviroment variables that specify the locations of the OSLOADER + * and so forth collude in this fiction by specifying paths like + * multi(1)scsi(0)disk(0)rdisk(3)partition(2), which is the path through + * the IDE node (which, for reasons not specific to Harley, is of class + * "scsi"). I do not know exactly what NT does in order to compensate for + * this lie. + */ + +STATIC void +move_scsi_children_to_ide_hack(void) +{ + PCONFIGURATION_NODE node, idenode = 0, scsinode = 0; + + if (OFGetproplen(OFFinddevice("/openprom"),"arc-scsi-to-ide") < 0) { + return; + } + + idenode = PathToNode("/pci/isa/ide"); + scsinode = PathToNode("/pci/scsi"); + + if (idenode == 0 || scsinode == 0) { + return; + } + + /* Move SCSI children underneath IDE */ + idenode->Child = scsinode->Child; + + scsinode->Child = 0; + + /* Reparent SCSI children to IDE */ + for (node = idenode->Child; node != 0; node = node->Peer) { + node->Parent = idenode; /* Reparent nodes */ + } + + /* Point the IDE node to the Open Firmware SCSI node so Open will work */ + idenode->OfPhandle = scsinode->OfPhandle; + + idenode->Component.Type = ScsiAdapter; + idenode->ComponentName = "scsi"; +} + +STATIC VOID +VrInitSystemBlock() +{ + LONG i; + LONG FirmwareVectorLen; + // + // Initialize the system parameter block + // + FirmwareVectorLen = (ULONG)MaximumRoutine * sizeof(ULONG); + i = sizeof(SYSTEM_PARAMETER_BLOCK) + FirmwareVectorLen; + + if (CLAIM((PVOID) SYSTEM_BLOCK, i) == -1) { + fatal("Couldn't claim SYSTEM PARAMETER BLOCK\n"); + } + bzero((PCHAR)SYSTEM_BLOCK, i); + return; +} + diff --git a/private/ntos/boot/veneer/vrmalloc.c b/private/ntos/boot/veneer/vrmalloc.c new file mode 100644 index 000000000..c0872f254 --- /dev/null +++ b/private/ntos/boot/veneer/vrmalloc.c @@ -0,0 +1,355 @@ +/* + * + * Copyright 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * Copyright (c) 1995 FirePower Systems, Inc. + * + * $RCSfile: vrmalloc.c $ + * $Revision: 1.6 $ + * $Date: 1996/02/17 00:41:29 $ + * $Locker: $ + * + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * A "smarter" malloc William L. Sebok + * Sept. 24, 1984 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * If n = the size of an area rounded DOWN to the nearest power of two, + * all free areas of memory whose length is the same index n is organized + * into a chain with other free areas of index n. A request for memory + * takes the first item in the chain whose index is the size of the + * request rounded UP to the nearest power of two. If this chain is + * empty the next higher chain is examined. If no larger chain has memory + * then new memory is allocated. Only the amount of new memory needed is + * allocated. Any old free memory left after an allocation is returned + * to the free list. Extra new memory returned because of rounding + * to page boundaries is returned to free list. + * + * All memory areas (free or busy) handled by malloc are also chained + * sequentially by increasing address. When memory is freed it is + * merged with adjacent free areas, if any. If a free area of memory + * ends at the end of memory (i.e. at the break), the break is + * contracted, freeing the memory back to the system. + * + * Notes: + * ov_length field includes sizeof(struct overhead) + * adjacency chain includes all memory, allocated plus free. + */ + +#include "veneer.h" + +#define MAGIC_FREE 0x548a934c +#define MAGIC_BUSY 0xc139569a + +#define NBUCKETS 24 +#define NALIGN 4 + +struct qelem { + struct qelem *q_forw; + struct qelem *q_back; +}; + +struct overhead { + struct qelem ov_adj; /* adjacency chain pointers */ + struct qelem ov_buk; /* bucket chain pointers */ + long ov_magic; + unsigned long ov_length; +}; + +char endfree = 0; +struct qelem adjhead = { &adjhead, &adjhead }; +struct qelem buckets[NBUCKETS] = { + &buckets[0], &buckets[0], + &buckets[1], &buckets[1], + &buckets[2], &buckets[2], + &buckets[3], &buckets[3], + &buckets[4], &buckets[4], + &buckets[5], &buckets[5], + &buckets[6], &buckets[6], + &buckets[7], &buckets[7], + &buckets[8], &buckets[8], + &buckets[9], &buckets[9], + &buckets[10], &buckets[10], + &buckets[11], &buckets[11], + &buckets[12], &buckets[12], + &buckets[13], &buckets[13], + &buckets[14], &buckets[14], + &buckets[15], &buckets[15], + &buckets[16], &buckets[16], + &buckets[17], &buckets[17], + &buckets[18], &buckets[18], + &buckets[19], &buckets[19], + &buckets[20], &buckets[20], + &buckets[21], &buckets[21], + &buckets[22], &buckets[22], + &buckets[23], &buckets[23], +}; + +/* + * The following macros depend on the order of the elements in struct overhead + */ +#define TOADJ(p) ((struct qelem *)(p)) +#define FROMADJ(p) ((struct overhead *)(p)) +#define FROMBUK(p) ((struct overhead *)( (char *)p - sizeof(struct qelem))) +#define TOBUK(p) ((struct qelem *)( (char *)p + sizeof(struct qelem))) + +#ifndef CURBRK +#define CURBRK sbrk(0) +#endif CURBRK + +STATIC void insque(), remque(); + +#ifdef NULL +#undef NULL +#endif +#define NULL 0 +#ifdef debug +# define ASSERT(p,q) if (!(p)) fatal(q) +#else +# define ASSERT(p,q) +#endif + +#define ALIGN(n, granule) ((n + ((granule)-1)) & ~((granule)-1)) + +char * +malloc(nbytes) + unsigned nbytes; +{ + register struct overhead *p, *q; + register int surplus = 0; + register struct qelem *bucket; + nbytes = ALIGN(nbytes, NALIGN) + sizeof(struct overhead); + bucket = &buckets[log2(nbytes-1) + 1]; /* log2 rounded up */ + for (p = NULL; bucket < &buckets[NBUCKETS]; bucket++) { + if (bucket->q_forw != bucket) { + /* remove from bucket chain */ + p = FROMBUK(bucket->q_forw); + ASSERT(p->ov_magic == MAGIC_FREE, "\nmalloc: Entry \ +not marked FREE found on Free List!\n"); + remque(TOBUK(p)); + surplus = p->ov_length - nbytes; + break; + } + } + if (p == NULL) { +#ifdef USE_SBRK + register int i; + p = (struct overhead *)CURBRK; + if ((int)p == -1) { + return(NULL); + } + if (i = (int)p&(NALIGN-1)) { + sbrk(NALIGN-i); + } + p = (struct overhead *)sbrk(nbytes); + if ((int)p == -1) { + return(NULL); + } + q = (struct overhead *)CURBRK; + if ((int)q == -1) { + return(NULL); + } + p->ov_length = (char *)q - (char *)p; + surplus = p->ov_length - nbytes; + /* add to end of adjacency chain */ + ASSERT((FROMADJ(adjhead.q_back)) < p, "\nmalloc: Entry in \ +adjacency chain found with address lower than Chain head!\n" ); + insque(TOADJ(p),adjhead.q_back); +#else + struct qelem *pp; + int alloc_size = ALIGN(nbytes, PAGE_SIZE); + + p = (struct overhead *)alloc(alloc_size, NALIGN); + if ((int)p == -1) { + return(NULL); + } + p->ov_length = alloc_size; + surplus = p->ov_length - nbytes; + + /* add to adjacency chain in the correct place */ + for (pp = adjhead.q_forw; pp != &adjhead; pp = pp->q_forw) { + if (p < FROMADJ(pp)) { + break; + } + } + ASSERT(pp == &adjhead || (p < FROMADJ(pp)), + "\nmalloc: Bogus insertion in adjacency list\n"); + insque(TOADJ(p),pp->q_back); +#endif + } + if (surplus > sizeof(struct overhead)) { + /* if big enough, split it up */ + q = (struct overhead *)( (char *)p + nbytes); + q->ov_length = surplus; + p->ov_length = nbytes; + q->ov_magic = MAGIC_FREE; + /* add surplus into adjacency chain */ + insque(TOADJ(q),TOADJ(p)); + /* add surplus into bucket chain */ + insque(TOBUK(q),&buckets[log2(surplus)]); + } + p->ov_magic = MAGIC_BUSY; + return((char*)p + sizeof(struct overhead)); +} + +void +free(mem) +register char *mem; +{ + register struct overhead *p, *q; + if (mem == NULL) { + return; + } + p = (struct overhead *)(mem - sizeof(struct overhead)); + if (p->ov_magic == MAGIC_FREE) { + return; + } + if (p->ov_magic != MAGIC_BUSY) { + fatal("attempt to free memory not allocated with malloc!\n"); + } + q = FROMADJ((TOADJ(p))->q_back); + if (q != FROMADJ(&adjhead)) { /* q is not the first list item */ + ASSERT(q < p, "\nfree: While trying to merge a free area with \ +a lower adjacent free area,\n addresses were found out of order!\n"); + /* If lower segment can be merged */ + if ((q->ov_magic == MAGIC_FREE) && + ((char *)q + q->ov_length == (char *)p) ) { + + /* remove lower address area from bucket chain */ + remque(TOBUK(q)); + /* remove upper address area from adjacency chain */ + remque(TOADJ(p)); + q->ov_length += p->ov_length; + p->ov_magic = NULL; + p = q; + } + } + q = FROMADJ((TOADJ(p))->q_forw); + if (q != FROMADJ(&adjhead)) { /* q is not the last list item */ + /* upper segment can be merged */ + ASSERT(q > p, "\nfree: While trying to merge a free area with \ +a higher adjacent free area,\n addresses were found out of order!\n"); + if ( (q->ov_magic == MAGIC_FREE) && + ((char *)p + p->ov_length == (char *)q) ) { + + /* remove upper from bucket chain */ + remque(TOBUK(q)); + /* remove upper from adjacency chain */ + remque(TOADJ(q)); + p->ov_length += q->ov_length; + q->ov_magic = NULL; + } + } +#ifdef USE_SBRK + /* freed area is at end of memory */ + if ((endfree && adjhead.q_back == TOADJ(p)) && + ((char*)p + p->ov_length == (char *)CURBRK) ) { + + /* remove from end of adjacency chain */ + remque(adjhead.q_back); + /* release memory to system */ + sbrk( -((int)(p->ov_length))); + return; + } +#endif + p->ov_magic = MAGIC_FREE; + /* place in bucket chain */ + insque(TOBUK(p),&buckets[log2(p->ov_length)]); + return; +} + +char * +realloc(mem,nbytes) +register char *mem; unsigned nbytes; +{ + register char *newmem; + register struct overhead *p, *q; + register int surplus; + if (mem == NULL) { + return(malloc(nbytes)); + } + if(mem > (char*)FROMADJ(adjhead.q_back) + sizeof(struct overhead)) { + return(NULL); + } + + p = (struct overhead *)(mem - sizeof(struct overhead)); + nbytes = (nbytes + (NALIGN-1)) & (~(NALIGN-1)); + if ( (p->ov_magic == MAGIC_BUSY) && (q = FROMADJ(adjhead.q_back)) != p + && (q->ov_magic != MAGIC_FREE || (FROMADJ(q->ov_adj.q_back) != p)) ) { + + free(mem); + } + if( (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE) + && (surplus = p->ov_length - nbytes - sizeof(struct overhead)) >= 0 ) { + if (surplus > sizeof(struct overhead)) { + /* return surplus to free list */ + nbytes += sizeof(struct overhead); +#ifdef USE_SBRK + /* freed area is at end of memory */ + if ( endfree && adjhead.q_back == TOADJ(p) + && (char*)p + p->ov_length == (char *)CURBRK ) { + /* release memory to system */ + sbrk(-surplus); + } else +#endif + { + q = (struct overhead *)( (char *)p + nbytes); + q->ov_length = surplus; + q->ov_magic = MAGIC_FREE; + insque(TOADJ(q),TOADJ(p)); + insque(TOBUK(q),&buckets[log2(surplus)]); + } + p->ov_length = nbytes; + } + if (p->ov_magic == MAGIC_FREE) { + remque(TOBUK(p)); + p->ov_magic = MAGIC_BUSY; + } + return(mem); + } + newmem = malloc(nbytes); + if (newmem != mem && newmem != NULL) { + register unsigned n; + if (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE) { + n = p->ov_length - sizeof(struct overhead); + nbytes = (nbytes < n) ? nbytes : n ; + } + bcopy(mem,newmem,nbytes); + } + if (p->ov_magic == MAGIC_BUSY) { + free(mem); + } + return(newmem); +} + +log2(n) +register int n; +{ + register int i = 0; + while ((n >>= 1) > 0) { + i++; + } + return(i); +} + +void +insque(item,queu) +register struct qelem *item, *queu; +{ + register struct qelem *pueu; + pueu = queu->q_forw; + item->q_forw = pueu; + item->q_back = queu; + queu->q_forw = item; + pueu->q_back = item; +} + +void +remque(item) +register struct qelem *item; +{ + register struct qelem *queu, *pueu; + pueu = item->q_forw; + queu = item->q_back; + queu->q_forw = pueu; + pueu->q_back = queu; +} diff --git a/private/ntos/boot/veneer/vrmemory.c b/private/ntos/boot/veneer/vrmemory.c new file mode 100644 index 000000000..da9568e7c --- /dev/null +++ b/private/ntos/boot/veneer/vrmemory.c @@ -0,0 +1,481 @@ +/* + * + * Copyright (c) 1994 FirePower Systems, Inc. + * Copyright (c) 1995 FirePower Systems, Inc. + * + * $RCSfile: vrmemory.c $ + * $Revision: 1.19 $ + * $Date: 1996/06/17 02:55:43 $ + * $Locker: $ + * + * Module Name: + * vrmemory.c + * + * Authour: + * Shin Iwamoto at FirePower Systems, Inc. + * + * History: + * 10-Sep-94 Shin Iwamoto at FirePower Systems, Inc. + * Added for ExecuteProg. Added comments. + * 07-Sep-94 Shin Iwamoto at FirePower Systems, Inc. + * Recreated. + */ + + +#include "veneer.h" + +// +// Define memory allocation structure. +// +typedef struct _VR_MEMORY_DESCRIPTOR { + struct _VR_MEMORY_DESCRIPTOR *NextEntry; + MEMORY_DESCRIPTOR MemoryEntry; +} VR_MEMORY_DESCRIPTOR, *PVR_MEMORY_DESCRIPTOR; + +PVR_MEMORY_DESCRIPTOR VrMemoryListOrig = (PVR_MEMORY_DESCRIPTOR) NULL; + +// +// Function declaration +// +STATIC PVR_MEMORY_DESCRIPTOR SearchMemoryList(ULONG, ULONG); +STATIC VOID SplitDesc(PVR_MEMORY_DESCRIPTOR, ULONG, ULONG, MEMORY_TYPE); + +STATIC PCHAR +MemoryTypeTable[] = { + "MemoryExceptionBlock", + "MemorySystemBlock", + "MemoryFree", + "MemoryBad", + "MemoryLoadedProgram", + "MemoryFirmwareTemporary", + "MemoryFirmwarePermanent", + "MemoryFreeContiguous", + "MemorySpecialMemory" +}; + + +/* + * Name: VrGetmemoryDescriptor + * + * Description: + * This routine returns a pointer to the next memory descriptor. If + * the specified memory descriptor is NULL, then a pointer to the + * first memory descriptor is returned. If there are no more memory + * descriptors, then NULL is returned. + * + * Arguments: + * MemoryDescriptor - Supplies a optional pointer to a memory descriptor. + * + * Return Value: + * If there are any more entries in the memory descriptor list, the + * address of the next descriptor is returned. Otherwise, NULL is + * returned. + * + */ +PMEMORY_DESCRIPTOR +VrGetMemoryDescriptor( + IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL + ) +{ + PMEMORY_DESCRIPTOR P; + PVR_MEMORY_DESCRIPTOR Entry; + + debug(VRDBG_MEM, "VrGetMemoryDescriptor(%x): ", MemoryDescriptor); + + if (MemoryDescriptor == (PMEMORY_DESCRIPTOR) NULL) { + P = &(VrMemoryListOrig->MemoryEntry); + debug(VRDBG_MEM, "%x (%s %x %x)\n", P, MemoryTypeTable[P->MemoryType], + P->BasePage, P->PageCount); + return (P); + } + + for (Entry = VrMemoryListOrig; Entry; Entry = Entry->NextEntry) { + if (&Entry->MemoryEntry == MemoryDescriptor) { + break; + } + } + if (Entry->NextEntry == NULL) { + debug(VRDBG_MEM, "NULL\n"); + return ((PMEMORY_DESCRIPTOR) NULL); + } else { + P = &(Entry->NextEntry->MemoryEntry); + debug(VRDBG_MEM, "%x (%s %x %x)\n", P, MemoryTypeTable[P->MemoryType], + P->BasePage, P->PageCount); + return (P); + } +} + + +/* + * Name: VrCreateMemoryDescriptor + * + * Description: + * This function creates the list of memory descriptors. + * + */ +VOID +VrCreateMemoryDescriptors( + VOID + ) +{ + phandle ph; + char *regp; + reg *cur_reg; + int addr_cells, size_cells, regsize; + PVR_MEMORY_DESCRIPTOR pre_desc, cur_desc; + PVR_MEMORY_DESCRIPTOR FoundDesc; + ULONG proplen, cur_basepage, cur_pagecount; + ULONG i; + debug(VRDBG_MEM|VRDBG_ENTRY, + "VrCreateMemoryDescriptors:____________________BEGIN...\n"); + + // + // Get phandle for /memory. + // + ph = OFFinddevice("/chosen"); + if (ph == -1) { + fatal("Cannot access /chosen node.\n"); + } + ph = OFInstanceToPackage(get_int_prop(ph, "memory")); + if (ph == -1) { + fatal("Cannot access /memory node.\n"); + } + + // + // Get information of installed memory from OpenFirmware. + // + if ((proplen = OFGetproplen(ph, "reg")) <= 0) { + fatal("No memory reg structs. proplen = %d\n", proplen); + } + regp = malloc(proplen); + if (OFGetprop(ph, "reg", regp, proplen) != (long) proplen) { + warn("Getprop(memory.reg) return != %d\n", proplen); + } + // + // How big are the descriptors? How many "cells" are required to + // represent addresses. + // + addr_cells = get_int_prop(OFParent(ph), "#address-cells"); + if (addr_cells == -1) { + addr_cells = 2; + } + + // + // How many ints is an address cell? + // + size_cells = get_int_prop(OFParent(ph), "#size-cells"); + if (size_cells == -1) { + size_cells = 1; + } + + regsize = (addr_cells + size_cells) * sizeof(int); + debug(VRDBG_MEM, "regsize: %x, proplen: %x\n",regsize, proplen); + + + // + // Look at the "reg" property list for the /memory node. This list + // shows what memory the firmware has already "claimed" for any reason. + // + pre_desc = (PVR_MEMORY_DESCRIPTOR) &VrMemoryListOrig; + debug(VRDBG_MEM, "VrCreateMemoryDescriptors: Base Page Page Count\n"); + for (i = 0; i < proplen/regsize; i++) { + cur_desc = new(VR_MEMORY_DESCRIPTOR); + cur_desc->NextEntry = NULL; + pre_desc->NextEntry = cur_desc; + cur_desc->MemoryEntry.MemoryType = MemoryFirmwareTemporary; + cur_reg = decode_reg( regp + (i * regsize), + regsize, + addr_cells, + size_cells + ); + cur_desc->MemoryEntry.BasePage = + (cur_reg->lo >> PAGE_SHIFT) + (cur_reg->hi << (32-PAGE_SHIFT)); + + cur_desc->MemoryEntry.PageCount = cur_reg->size >> PAGE_SHIFT; + debug(VRDBG_MEM, "\t\t\t\t\t0x%x\t0x%x\n", + cur_desc->MemoryEntry.BasePage,cur_desc->MemoryEntry.PageCount); + + pre_desc = cur_desc; + + } + + // + // Release the area for "reg" property + // + free(regp); + + // + // Get information of available memory from OpenFirmware. + // + if ((proplen = OFGetproplen(ph, "available")) <= 0) { + fatal("No memory available structs. proplen = %d\n", proplen); + } + regp = malloc(proplen); + if (OFGetprop(ph, "available", regp, proplen) != (long) proplen) { + warn("Getprop(memory.available) return != %d\n", proplen); + } + + // + // Search the chunk specified by each "available" memory + // in the installed memory. Then make the chunk MemoryFree. + // + for (i = 0; i < proplen/regsize; i++) { + cur_reg = decode_reg(regp + (i * regsize), regsize, 1, 1); + cur_basepage = + (cur_reg->lo >> PAGE_SHIFT) + (cur_reg->hi << (32-PAGE_SHIFT)); + + cur_pagecount = cur_reg->size >> PAGE_SHIFT; + + FoundDesc = SearchMemoryList(cur_basepage, cur_pagecount); + if (FoundDesc == NULL) { + fatal("Available memory (0x%x, 0x%x) is not in installed memory", + cur_basepage, cur_pagecount); + } + + if ((FoundDesc->MemoryEntry.BasePage == cur_basepage) && + (FoundDesc->MemoryEntry.PageCount == cur_pagecount)) { + + FoundDesc->MemoryEntry.MemoryType = MemoryFree; + } else { + SplitDesc(FoundDesc, cur_basepage, cur_pagecount, MemoryFree); + } + debug(VRDBG_MEM, "\t\t\t\t\t0x%x\t0x%x\n", + FoundDesc->MemoryEntry.BasePage, FoundDesc->MemoryEntry.PageCount); + } + + // + // Release the area for "available" property + // + free(regp); + + // + // For some memory chunks, mark specific attributes. + // + cur_desc = VrMemoryListOrig; + while (cur_desc != NULL) { + PMEMORY_DESCRIPTOR cur_mem; + + cur_mem = &cur_desc->MemoryEntry; + + // + // The loaded program must be MemoryLoadedProgram. + // + + if ( cur_mem->BasePage == 0x600) { + cur_mem->MemoryType = MemoryLoadedProgram; + } + + // + // The first N pages are marked Permanent. + // + + if ( cur_mem->BasePage == 0x0) { + cur_mem->MemoryType = MemoryFirmwarePermanent; + } + + // + // If a descriptor crosses the 8MB line, split it. + // + + if (cur_mem->BasePage < 0x800 && + (cur_mem->BasePage + cur_mem->PageCount > 0x800)) { + + SplitDesc(cur_desc, cur_mem->BasePage, + 0x800 - cur_mem->BasePage, MemoryFree); + } + + // + // Descriptors > 8MB are marked FirmwareTemporary. + // + + if (cur_mem->MemoryType == MemoryFree && cur_mem->BasePage >= 0x800) { + cur_mem->MemoryType = MemoryFirmwareTemporary; + } + cur_desc = cur_desc->NextEntry; + } + debug(VRDBG_MEM|VRDBG_ENTRY, + "VrCreateMemoryDescriptors:____________________...END\n"); +} + + +/* + * Name: VrMemoryInitialize + * + * Description: + * This function initializes the Memory entry points in the firmware + * transfer vector and the file table. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrMemoryInitialize( + VOID + ) +{ + // + // Initialize the I/O entry points in the firmware transfer vector. + // + debug(VRDBG_ENTRY, "VrMemoryInitialize: BEGIN....\n"); + (PARC_MEMORY_ROUTINE) SYSTEM_BLOCK->FirmwareVector[MemoryRoutine] = + VrGetMemoryDescriptor; + debug(VRDBG_ENTRY, "VrMemoryInitialize: ....END\n"); +} + + +STATIC +PVR_MEMORY_DESCRIPTOR +SearchMemoryList( + ULONG CurBasePage, + ULONG CurPageCount + ) +{ + PVR_MEMORY_DESCRIPTOR search_desc; + + search_desc = VrMemoryListOrig; + while(search_desc != NULL) { + if (search_desc->MemoryEntry.BasePage <= CurBasePage + && search_desc->MemoryEntry.BasePage + + search_desc->MemoryEntry.PageCount >= CurBasePage+CurPageCount) { + + return search_desc; + } + search_desc = search_desc->NextEntry; + } + return (PVR_MEMORY_DESCRIPTOR) NULL; +} + +/* + * + * Routine: VOID SplitDesc(PVR_MEMORY_DESCRIPTOR, ULONG, ULONG, MEMORY_TYPE) + * + * + * Description: + * This routine is called to split a memory descriptor into two + pieces. The only issue is whether the left over piece is the + first or the second of the two pieces. + + The original descriptor looks like..... + + CurBasePage + |-----------------------PageCount-------------->| + ________________________________________________ + | | + | Original Type (OType) | + | | + | | + ------------------------------------------------ + + The new arrangement will have pieces that are either + + + CurBasePage + |---------CurPageCount-------->| + ________________________________________________ + | | | + | Original Piece, | New Piece | + | MemType passed in | OType | + | | | + ------------------------------------------------ + + OR it will look like:..... + + CurBasePage + | |--CurPageCount->| + ________________________________________________ + | | | + | OType, Original Descript. | New Piece | + | | MemType | + | | | + ------------------------------------------------ + * + */ + +STATIC +VOID +SplitDesc( + PVR_MEMORY_DESCRIPTOR MemDesc, + ULONG CurBasePage, + ULONG CurPageCount, + MEMORY_TYPE MemType + ) +{ + PVR_MEMORY_DESCRIPTOR new_desc; + + // + // If the descriptor passed in points the the base page passed in, + // then take the current descriptor and retype it the MemType, size + // it as CurPageCount, and then create a new descriptor to describe + // what's left over maintaining the original mem type. + // + if (MemDesc->MemoryEntry.BasePage == CurBasePage) { + new_desc = new(VR_MEMORY_DESCRIPTOR); + new_desc->NextEntry = MemDesc->NextEntry; + MemDesc->NextEntry = new_desc; + + new_desc->MemoryEntry.MemoryType = MemDesc->MemoryEntry.MemoryType; + new_desc->MemoryEntry.BasePage = + MemDesc->MemoryEntry.BasePage + CurPageCount; + + new_desc->MemoryEntry.PageCount = + MemDesc->MemoryEntry.PageCount - CurPageCount; + + MemDesc->MemoryEntry.MemoryType = MemType; + MemDesc->MemoryEntry.BasePage = CurBasePage; + MemDesc->MemoryEntry.PageCount = CurPageCount; + + return; + } + + // + // If the base page value passed in is not the base page of the + // descriptor passed in, then the size and type refer to a region to + // carve out of the end of this descriptor rather than the beginning. + // + new_desc = new(VR_MEMORY_DESCRIPTOR); + new_desc->NextEntry = MemDesc->NextEntry; + MemDesc->NextEntry = new_desc; + + new_desc->MemoryEntry.MemoryType = MemType; + new_desc->MemoryEntry.BasePage = CurBasePage; + new_desc->MemoryEntry.PageCount = CurPageCount; + + MemDesc->MemoryEntry.PageCount -= CurPageCount; + + if (MemDesc->MemoryEntry.BasePage + MemDesc->MemoryEntry.PageCount + != new_desc->MemoryEntry.BasePage) { + ULONG old_size = MemDesc->MemoryEntry.PageCount; + + new_desc = new(VR_MEMORY_DESCRIPTOR); + new_desc->NextEntry = MemDesc->NextEntry->NextEntry; + MemDesc->NextEntry->NextEntry = new_desc; + + MemDesc->MemoryEntry.PageCount = + MemDesc->NextEntry->MemoryEntry.BasePage - + MemDesc->MemoryEntry.BasePage; + + new_desc->MemoryEntry.MemoryType = MemDesc->MemoryEntry.MemoryType; + new_desc->MemoryEntry.BasePage = + MemDesc->NextEntry->MemoryEntry.BasePage + + MemDesc->NextEntry->MemoryEntry.PageCount; + + new_desc->MemoryEntry.PageCount = + old_size - MemDesc->MemoryEntry.PageCount; + } + + return; +} + +VOID +DisplayMemory(VOID) +{ + PMEMORY_DESCRIPTOR P = NULL; + while ((P = VrGetMemoryDescriptor(P)) != NULL) { + debug(VRDBG_MEM, "MemoryType=%s, BasePage=0x%x, PageCount=0x%x\n", + MemoryTypeTable[P->MemoryType], P->BasePage, P->PageCount); + } +} diff --git a/private/ntos/boot/veneer/vrmisc.c b/private/ntos/boot/veneer/vrmisc.c new file mode 100644 index 000000000..e91bd966e --- /dev/null +++ b/private/ntos/boot/veneer/vrmisc.c @@ -0,0 +1,221 @@ +/* + * + * Copyright (c) 1995 FirePower Systems, Inc. + * Copyright (c) 1994 FirePower Systems Inc. + * + * $RCSfile: vrmisc.c $ + * $Revision: 1.10 $ + * $Date: 1996/06/17 02:55:38 $ + * $Locker: $ + * + * + * Module Name: + * vrmisc.c + * + * Author: + * Shin Iwamoto at FirePower Systems Inc. + * + * History: + * 07-Sep-94 Shin Iwamoto at FirePower System Inc. + * Modifying the existence of L2 cache. + * 16-Jun-94 Shin Iwamoto at FirePower System Inc. + * Changed the property getting code using get_str_prop() + * in VrGetTime(). + * 14-Jun-94 Shin Iwamoto at FirePower System Inc. + * Added a pointer to VRTime because a type mismatch happened. + * 19-May-94 Shin Iwamoto at FirePower System Inc. + * Added some logic in VrGetTime(). + * Added some comments. + * 05-May-94 Shin Iwamoto at FirePower System Inc. + * Created. + * + */ + + +#include "veneer.h" + +// +// Static data. +// +STATIC TIME_FIELDS VrTime; +STATIC LONG StartTime; // XXXX structure + + +/* + * Name: VrGetTime + * + * Description: + * This function returns a pointer to a time structure. + * + * Arguments: + * None. + * + * Return Value: + * Returns a pointer to a time structure. If the time infomation is + * valid, valid data is returned, otherwise all fields are returned + * as zero. + * + */ +PTIME_FIELDS +VrGetTime(VOID) +{ + PTIME_FIELDS PVrTime = &VrTime; // Satisfy the compiler. + phandle ph; + ihandle ih; + int res[7]; + + // + // "The experienced programmer puts a known elephant in + // Cairo so the search will always terminate." + // + VrTime.Year = 0; + VrTime.Month = 0; + VrTime.Day = 0; + VrTime.Hour = 0; + VrTime.Minute = 0; + VrTime.Second = 0; + VrTime.Milliseconds = 0; + VrTime.Weekday = 0; + + ph = FindNodeByType("rtc"); + if (ph == 0) { + warn("VrGetTime: Could not find the RTC node.\n"); + goto out; + } + ih = OpenPackage(ph); + if (ih == 0) { + goto out; + } + OFCallMethod(7, 2, res, "get-time", ih); + OFClose(ih); + if (res[0] != 0) { + goto out; + } + + VrTime.Year = res[6]; + VrTime.Month = res[5]; + VrTime.Day = res[4]; + VrTime.Hour = res[3]; + VrTime.Minute = res[2]; + VrTime.Second = res[1]; + +out: + return (PVrTime); +} + + +/* + * Name: VrGetRelativeTime + * + * Description: + * This routine returns the time in seconds since Veneer starts. + * + * Arguments: + * None. + * + * Return Value: + * If the time information is valid, valid data is returned. + * Otherwise a zero is returned. + * + */ +ULONG +VrGetRelativeTime( VOID ) +{ + return OFMilliseconds()/1000; +} + + +/* + * Name: VrTimeInitialize + * + * Description: + * This function initializes the time routine addresses in the firmware + * transfer vector and the internal counter for the relative time. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrTimeInitialize( + VOID + ) +{ + debug(VRDBG_ENTRY, "VrTimeInitialize BEGIN....\n"); + // + // Initialize the Time routine addresses in the firmware transfer vector. + // + (PARC_GET_TIME_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetTimeRoutine] = VrGetTime; + + (PARC_GET_RELATIVE_TIME_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetRelativeTimeRoutine] = + VrGetRelativeTime; + (PARC_FLUSH_ALL_CACHES_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[FlushAllCachesRoutine] = + VrFlushAllCaches; + debug(VRDBG_ENTRY, "VrTimeInitialize ....END\n"); + +} + +VOID +VrFlushAllCaches(VOID) +{ + ULONG start; + phandle ph; + char *regp; + reg *cur_reg; + int i, size_cells, addr_cells, proplen, regsize; + extern VOID HalpSweepPhysicalRangeInBothCaches(ULONG, ULONG, ULONG); + + /* + * Flush each chunk of physical memory. Use the memory scanning + * code from vrmemory.c; see that file for comments. + */ + + ph = OFFinddevice("/chosen"); + if (ph == -1) { + fatal("Cannot access /chosen node.\n"); + } + ph = OFInstanceToPackage(get_int_prop(ph, "memory")); + + if (ph == -1) { + fatal("Cannot access /memory node.\n"); + } + + if ((proplen = OFGetproplen(ph, "reg")) <= 0) { + fatal("No memory reg structs. proplen = %d\n", proplen); + } + regp = malloc(proplen); + if (OFGetprop(ph, "reg", regp, proplen) != (long) proplen) { + fatal("Getprop(memory.reg) return != %d\n", proplen); + } + + addr_cells = get_int_prop(OFParent(ph), "#address-cells"); + if (addr_cells == -1) { + addr_cells = 2; + } + size_cells = get_int_prop(OFParent(ph), "#size-cells"); + if (size_cells == -1) { + size_cells = 1; + } + regsize = (addr_cells + size_cells) * sizeof(int); + + + for (i = 0; i < proplen/regsize; i++) { + cur_reg = decode_reg( regp + (i * regsize), + regsize, + addr_cells, + size_cells + ); + start = cur_reg->lo >> PAGE_SHIFT; + start += cur_reg->hi << (32-PAGE_SHIFT); + HalpSweepPhysicalRangeInBothCaches(start, 0, cur_reg->size); + } + + free(regp); + +} diff --git a/private/ntos/boot/veneer/vrpehdr.c b/private/ntos/boot/veneer/vrpehdr.c new file mode 100644 index 000000000..d8528ac55 --- /dev/null +++ b/private/ntos/boot/veneer/vrpehdr.c @@ -0,0 +1,138 @@ +/*++ + * + * Copyright (c) 1996 FirePower Systems, Inc. + * Copyright (c) 1995 FirePower Systems, Inc. + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * Copyright (c) 1994 FirePower Systems Inc. + * + * $RCSfile: vrpehdr.c $ + * $Revision: 1.7 $ + * $Date: 1996/02/17 00:50:30 $ + * $Locker: $ + +Module Name: + + vrpehdr.c + +Abstract: + + These routines read and parse the Microsoft PE header. + +Author: + + Mike Tuciarone 9-May-1994 + + +Revision History: + +--*/ + + +#include "veneer.h" + + + + +#define HEADER_CHR (IMAGE_FILE_EXECUTABLE_IMAGE | \ + IMAGE_FILE_BYTES_REVERSED_LO | \ + IMAGE_FILE_32BIT_MACHINE | \ + IMAGE_FILE_BYTES_REVERSED_HI) + +/* + * For some reason NT 3.5 changed the OSLoader header. + */ +#define HEADER_CHR_35 (IMAGE_FILE_EXECUTABLE_IMAGE | \ + IMAGE_FILE_32BIT_MACHINE | \ + IMAGE_FILE_LINE_NUMS_STRIPPED) + +void * +load_file(ihandle bootih) +{ + IMAGE_FILE_HEADER FileHdr; + IMAGE_OPTIONAL_HEADER OptHdr; + IMAGE_SECTION_HEADER *SecHdr, *hdr; + int res, size, i; + PCHAR BaseAddr; + + if ((res = OFRead(bootih, (char *) &FileHdr, IMAGE_SIZEOF_FILE_HEADER)) + != IMAGE_SIZEOF_FILE_HEADER) { + fatal("Couldn't read entire file header: got %d\n", res); + } + + /* + * Sanity check. + */ + if (FileHdr.Machine != IMAGE_FILE_MACHINE_POWERPC) { + fatal("Wrong machine type: %x\n", FileHdr.Machine); + } +#ifdef NOT + /* + * Don't bother to check the flags. They change every release anyway. + */ + if ((FileHdr.Characteristics & HEADER_CHR ) != HEADER_CHR && + (FileHdr.Characteristics & HEADER_CHR_35) != HEADER_CHR_35) { + fatal("Wrong header characteristics: %x\n", + FileHdr.Characteristics); + } +#endif + + size = FileHdr.SizeOfOptionalHeader; + if ((res = OFRead(bootih, (char *) &OptHdr, size)) != size) { + fatal("Couldn't read optional header: expect %x got %x\n", + size, res); + } + + /* + * More sanity. + */ + if (OptHdr.Magic != 0x010b) { + fatal("Wrong magic number in header: %x\n", OptHdr.Magic); + } + + /* + * Compute image size and claim memory at specified virtual address. + * We assume the SizeOfImage field is sufficient. + */ + BaseAddr = (PCHAR) OptHdr.ImageBase; + if (CLAIM(BaseAddr, OptHdr.SizeOfImage) == -1) { + fatal("Couldn't claim %x bytes of VM at %x\n", + OptHdr.SizeOfImage, BaseAddr); + } + bzero(BaseAddr, OptHdr.SizeOfImage); + + /* + * Allocate section headers. + */ + size = FileHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); + SecHdr = (PIMAGE_SECTION_HEADER) malloc(size); + if ((res = OFRead(bootih, (char *) SecHdr, size)) != size) { + fatal("Couldn't read section headers: expect %x got %x\n", + size, res); + } + + /* + * Loop through section headers, reading in each piece at the + * specified virtual address. + */ + for (i = 0; i < FileHdr.NumberOfSections; ++i) { + hdr = &SecHdr[i]; + debug(VRDBG_PE, "Processing section %d: %s\n", i, hdr->Name); + if (hdr->SizeOfRawData == 0) { + continue; + } + if (OFSeek(bootih, 0, hdr->PointerToRawData) == -1) { + fatal("seek to offset %x failed\n", + hdr->PointerToRawData); + } + res = OFRead(bootih, + (PCHAR) hdr->VirtualAddress + (ULONG) BaseAddr, + hdr->SizeOfRawData); + if ((ULONG)res != hdr->SizeOfRawData) { + fatal("Couldn't read data: exp %x got %x\n", + hdr->SizeOfRawData, res); + } + } + free((char *)SecHdr); + + return (void *)(BaseAddr + OptHdr.AddressOfEntryPoint); +} diff --git a/private/ntos/boot/veneer/vrrstart.c b/private/ntos/boot/veneer/vrrstart.c new file mode 100644 index 000000000..7d4ebc3f6 --- /dev/null +++ b/private/ntos/boot/veneer/vrrstart.c @@ -0,0 +1,274 @@ +/* + * + * Copyright (c) 1994 FirePower Systems Inc. + * Copyright (c) 1995 FirePower Systems, Inc. + * + * $RCSfile: vrrstart.c $ + * $Revision: 1.7 $ + * $Date: 1996/04/15 02:55:36 $ + * $Locker: $ + * + * + * Module Name: + * vrrstart.c + * + * Author: + * Shin Iwamoto at FirePower Systems Inc. + * + * History: + * 16-Jun-94 Shin Iwamoto at FirePower Systems Inc. + * Changed the property getting code using get_str_prop() + * in VrGetSystemId(). + * 14-Jun-94 Shin Iwamoto at FirePower Systems Inc. + * Added the pointer to SystemId because type mismatch happened. + * 19-May-94 Shin Iwamoto at FirePower Systems Inc. + * Added some comments. + * 13-May-94 Shin Iwamoto at FirePower Systems Inc. + * Added jump-logic to the restart address in VrRestart(). + * Added VrRestartInitialize(). + * 12-May-94 Shin Iwamoto at FirePower Systems Inc. + * Created. + * + */ + + + +#include "veneer.h" + + +// +// Static data. +// +STATIC SYSTEM_ID SystemId; + + +/* + * Name: VrEnterInteractiveMode + * + * Description: + * This function terminates the executing program and enters + * interactive mode. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrEnterInteractiveMode( + VOID + ) +{ + (VOID)OFEnter(); +} + + +/* + * Name: VrGetSystemId + * + * Description: + * This function returns a pointer to a system identification + * structure that contains information used to uniquely identify + * each system. + * + * Arguments: + * None. + * + * Return Value: + * The 16-byte system identification structure is returned. + * + */ +PSYSTEM_ID +VrGetSystemId( + VOID + ) +{ + phandle PHandle; + PCHAR Property; + PSYSTEM_ID PSystemId = &SystemId; + + if ((LONG)(PHandle = OFFinddevice("/")) == -1) { + fatal("Veneer: cannot find the root node in Open Firmware.\n"); + } + + if ((Property = get_str_prop(PHandle, "name", NOALLOC)) == (PCHAR)NULL) { + fatal("Veneer: cannot get the name property for the root node.\n"); + } + bcopy(Property, SystemId.VendorId, 8); + + if ((Property = get_str_prop(PHandle, "id", NOALLOC)) == (PCHAR)NULL) { + fatal("Veneer: cannot get the name property for the root node.\n"); + } + bcopy(Property, SystemId.ProductId, 8); + + return PSystemId; +} + + +/* + * Name: VrPowerDown + * + * Description: + * This function is identical to the VrHalt() with the additional + * feature that, the power to a system is removed if the system is + * equipped so. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrPowerDown(VOID) +{ + // XXX - This must use the HALT interface; see the PPC binding. + OFExit(); +} + + +/* + * Name: VrReboot + * + * Description: + * This function reboots the system with the same parameters used + * for the previous system load sequence. If the parameters cannot + * be reproduced, then the default system load sequence is performed. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrReboot( + VOID + ) +{ + // XXXX + // Make sure that this funciton reboots the system with the same + // parameters used for the previous system load sequence. If the + // parameters cannot be reporduced, then the default system load + // sequence is performed. + (VOID)OFBoot((PCHAR)NULL); +} + + +/* + * Name: VrRestart + * + * Description: + * This function performs the equivalent of a power-on reset. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrRestart( + VOID + ) +{ + + PRESTART_BLOCK PRestartBlock; + + // + // Detect the presence of a valid Restart Block + // + PRestartBlock = SYSTEM_BLOCK->RestartBlock; + while (PRestartBlock != (PRESTART_BLOCK)NULL) { + if (PRestartBlock->Signature == RSTB_SIGNATURE && + (PRestartBlock->Version == ARC_VERSION) && + (PRestartBlock->Revision == ARC_REVISION)) { + + break; + } + PRestartBlock = PRestartBlock->NextRestartBlock; + } + + // + // Perform a normal power-on sequence if a valid RestartBlock + // is not found. + // + if (PRestartBlock == (PRESTART_BLOCK)NULL) { + (VOID)OFBoot((PCHAR)NULL); + } + // + // Reboot the system. + // + + // + // Goto the RestartAddress, not return; + // + (VOID)(*(VOID (*)())(PRestartBlock->RestartAddress))(); +} + + +/* + * Name: VrHalt + * + * Description: + * This function exits the program. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrHalt( + VOID + ) +{ + (VOID)OFExit(); +} + + +/* + * Name: VrRestartInitialize + * + * Description: + * This function initializes restart routine addresses in the firmware + * transfer vector. + * + * Arguments: + * None. + * + * Return Value: + * None. + * + */ +VOID +VrRestartInitialize( + VOID + ) +{ + debug(VRDBG_ENTRY, "VrRestartInitialize BEGIN....\n"); + // + // Initialize Restart routine addresses in the firmware transfer vector. + // + (PARC_INTERACTIVE_MODE_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[InteractiveModeRoutine] = + VrEnterInteractiveMode; + (PARC_GET_SYSTEM_ID_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[GetSystemIdRoutine] = VrGetSystemId; + (PARC_POWERDOWN_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[PowerDownRoutine] = VrPowerDown; + (PARC_REBOOT_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[RebootRoutine] = VrReboot; + (PARC_RESTART_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[RestartRoutine] = VrRestart; + (PARC_HALT_ROUTINE) + SYSTEM_BLOCK->FirmwareVector[HaltRoutine] = VrHalt; + debug(VRDBG_ENTRY, "VrRestartInitialize ....END\n"); +} diff --git a/private/ntos/boot/veneer/vrsup.c b/private/ntos/boot/veneer/vrsup.c new file mode 100644 index 000000000..4b067dd67 --- /dev/null +++ b/private/ntos/boot/veneer/vrsup.c @@ -0,0 +1,369 @@ +/*++ + * + * Copyright (c) 1995 FirePower Systems, Inc. + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * Copyright (c) 1994 FirePower Systems, Inc. + * + * $RCSfile: vrsup.c $ + * $Revision: 1.7 $ + * $Date: 1996/02/17 00:42:16 $ + * $Locker: $ + * + + +Module Name: + + vrsup.c + +Abstract: + + A given physical device may be represented by a variety + of objects. More importantly, the veneer must be able to + translate freely between these objects. + + ______________ ____________________ + | 1275 | | ARC | + | | | | + | | | | + | Path | | ArcPath | + | \ | | / | + | \ | | / | + | \ | | / | + | \ | | / | + | \| |/ | + | \ / | + | |\ /| | + | | \ / | | + | | \ / | | + | | \ / | | + | | \ / | | + | | \ / | | + | | \ / | | + | Package---+-------Node | | + | | / \ | | + | | / \ | | + | | / \ | | + | | / \ | | + | | / \ | | + | | / \ | | + | |/ \| | + | / \ | + | /| |\ | + | / | | \ | + | / | | \ | + | Instance | | File Descriptor | + | | | | + |______________| |____________________| + + 1275 objects include the "Package," the "Instance," + and the device specifier, here simply termed the "Path." + ARC objects include the ARC device specifier, here the + "ArcPath," and the File Descriptor which does not appear + in this module. + + The CONFIGURATION_NODE object, a.k.a. the "Node," is the + central data object in the veneer, and is used to translate + from 1275 to ARC and vice versa. + + This file contains the routines which do path traversal + and translation for both 1275 and ARC trees. The general + form of the publicly accessible functions is + + P<yyy> <xxx>To<yyy>(P<xxx>); + + where <xxx> and <yyy> are one of + + Path + Package + Instance + Node + ArcPath + + and P<xxx> and P<yyy> are types <xxx> and <yyy> if + <xxx> and <yyy> are scalar, and pointers-to-<xxx>/<yyy> + if not. + + This sounds a lot more confusing than it is; see below. + +Author: + + Mike Tuciarone 9-May-1994 +--*/ + + +#include "veneer.h" + +/* + * Given a configuration node, traverse the Veneer Configuration tree + * looking for a matching component name. Call this initially with + * Node = RootNode. Return the matching node (if any). + */ +STATIC PCONFIGURATION_NODE +DoArcPathToNode( + PCHAR Path, + PCONFIGURATION_NODE Node + ) +{ + PCONFIGURATION_NODE MatchedNode; + CHAR *name, *cp; + LONG TokenLen; + ULONG Key = 0; + + if (Node == NULL) { + return (0); + } + + if (cp = index(Path, '(')) { + TokenLen = cp - Path; + cp += 1; + Key = atoi(cp); + } else { + TokenLen = strlen(Path); + } + + if (Node == RootNode) { + Node = RootNode->Child; + } + + name = Node->ComponentName; + if (!strncmp(name, Path, TokenLen) && (Key == Node->Component.Key)) { + /* + * A match! Trim off the matching component. + */ + debug(VRDBG_CONF, + "ArcPathToNode: path '%s' matched node '%s' %x\n", + Path, Node->ComponentName, Node->OfPhandle); + cp = index(Path, ')'); + if (cp == NULL) { + fatal("Malformed string: '%s'\n", Path); + } + cp += 1; + if (*cp == '\0') { + debug(VRDBG_CONF, + "String exhausted, returning %x\n", Node); + return(Node); + } + /* + * If this call returns non-NULL, then we had a match + * further down the tree. Otherwise this is the best + * we can do: return this node. + */ + MatchedNode = DoArcPathToNode(cp, Node->Child); + debug(VRDBG_CONF, "ArcPathToNode('%s') returning %x\n", + Path, MatchedNode ? MatchedNode->OfPhandle : 0); + return(MatchedNode ? MatchedNode : Node); + } + if (Node->Peer) { + return(DoArcPathToNode(Path, Node->Peer)); + } + return (0); +} + +/* + * External entry point: + */ +PCONFIGURATION_NODE +ArcPathToNode(PCHAR Path) +{ + return (DoArcPathToNode(Path, RootNode)); +} + + +/* + * Create the fully-qualified ARC path to describe the argument node. + */ +PCHAR +NodeToArcPath(PCONFIGURATION_NODE node) +{ + CHAR *oldbuf, *newbuf; + LONG len; + + // Add 3 to each length for the key. + len = 1; + newbuf = zalloc(len); + do { + oldbuf = newbuf; + len += strlen(node->ComponentName) + 3; + newbuf = zalloc(len); + strcpy(newbuf, node->ComponentName); + strcat(newbuf, "( )"); + newbuf[strlen(newbuf) - 2] = (char) node->Component.Key + '0'; + strcat(newbuf, oldbuf); + free(oldbuf); + } while ((node = node->Parent) && node != RootNode); + + return (newbuf); +} + + +/* + * Search the tree rooted at Node for a node containing the phandle Ph. + * NOTE: Phandles are not unique! This routine does a depth-first + * search to find the *deepest* node matching the phandle. + */ +STATIC PCONFIGURATION_NODE +FindNodeUsingPhandle(PCONFIGURATION_NODE Node, phandle Ph) +{ + PCONFIGURATION_NODE Found; + extern int level; + + debug(VRDBG_CONF, "FindNodeUsingPhandle: Node %x (%s) phandle %x\n", + Node, Node ? Node->ComponentName : "NULL", Ph); + if (Node == NULL) { + return (NULL); + } + /* + * First check to see if this node matches *and* is a wildcard. + * If so, return immediately. + */ + if (Node->OfPhandle == Ph && Node->Wildcard) { + debug(VRDBG_CONF, "FindNodeUsingPhandle: return %x\n", Node); + return (Node); + } + /* + * Check descendants, since the terminal node may be a child of + * this one. See the comments in add_new_child() in vrtree.c. + */ + level++; + Found = FindNodeUsingPhandle(Node->Child, Ph); + level--; + if (Found) { + debug(VRDBG_CONF, "FindNodeUsingPhandle: return %x\n", Node); + return (Found); + } + if (Node->OfPhandle == Ph) { + debug(VRDBG_CONF, "FindNodeUsingPhandle: return %x\n", Node); + return (Node); + } + return (FindNodeUsingPhandle(Node->Peer, Ph)); +} + +PCONFIGURATION_NODE +PackageToNode(phandle ph) +{ + return (FindNodeUsingPhandle(RootNode, ph)); +} + +PCONFIGURATION_NODE +PathToNode(PCHAR path) +{ + PCONFIGURATION_NODE node, tmpnode; + phandle ph; + PCHAR cp; + + ph = OFFinddevice(path); + node = FindNodeUsingPhandle(RootNode, ph); + if (node->Wildcard) { + // trim off final address + while ((cp = index(path, '@')) != NULL) { + path = cp + 1; + } + // XXX run decode-unit on it + // XXX search peers for match using wildcard criteria + if ((tmpnode = FindNodeUsingPhandle(node->Child, ph)) != NULL) { + return (tmpnode); + } + } + return (node); +} + +PCONFIGURATION_NODE +InstanceToNode(ihandle ih) +{ + char buf[1024]; + + OFInstanceToPath(ih, buf, 1024); + return (PathToNode(buf)); +} + +phandle +NodeToPackage(PCONFIGURATION_NODE node) +{ + return (node->OfPhandle); // "It's a gift to be simple..." +} + +PCHAR +NodeToPath(PCONFIGURATION_NODE node) +{ + phandle ph = NodeToPackage(node); + int len; + char *bufp; + + // + // Translate the device name into the device path for Open Firmware. + // Add 1 to the reported length to account for the null terminator. + // (See IEEE 1275-1994, Sec. 6.3.2.2.) + // + len = OFPackageToPath(ph, (char *)0, 0) + 1; + bufp = (char *) zalloc(len); + (VOID) OFPackageToPath(ph, bufp, len); + debug(VRDBG_CONF, "NodeToPath found '%s'\n", bufp); + + if (node->Wildcard) { + char *newp; + + while (node->Parent->Wildcard) { + node = node->Parent; + } + // XXX Generate AddrPath by running encode-unit + // XXX on wildcard criteria + len += strlen(node->WildcardAddrPath); + newp = (char *) zalloc(len); + strcpy(newp, bufp); + free(bufp); + bufp = newp; + debug(VRDBG_CONF, "NodeToPath adding '%s'\n", + node->WildcardAddrPath); + strcat(bufp, node->WildcardAddrPath); + } + debug(VRDBG_CONF, "NodeToPath returning '%s'\n", bufp); + return (bufp); +} + +/* + * This routine is hopelessly naive. See VrOpen() for a version + * that's been around. + */ +ihandle +NodeToInstance(PCONFIGURATION_NODE node) +{ + char *path = NodeToPath(node); + ihandle ih = OFOpen(path); + + free(path); + return (ih); +} + +STATIC phandle +DoFindNodeByType(char *type, phandle ph) +{ + phandle res; + + if (ph == 0) { + return(0); + } + if (strcmp(get_str_prop(ph, "device_type", NOALLOC), type) == 0) { + return(ph); + } + res = DoFindNodeByType(type, OFChild(ph)); + if (res != 0) { + return(res); + } + return(DoFindNodeByType(type, OFPeer(ph))); +} + +phandle +FindNodeByType(char *type) +{ + return(DoFindNodeByType(type, OFPeer(0))); +} + +ihandle +OpenPackage(phandle ph) +{ + char buf[256]; + + (void) OFPackageToPath(ph, buf, 256); + return (OFOpen(buf)); +} + diff --git a/private/ntos/boot/veneer/vrtree.c b/private/ntos/boot/veneer/vrtree.c new file mode 100644 index 000000000..9d33fd651 --- /dev/null +++ b/private/ntos/boot/veneer/vrtree.c @@ -0,0 +1,2012 @@ +/* + * Copyright (c) 1995,1996 FirePower Systems, Inc. + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * + * $RCSfile: vrtree.c $ + * $Revision: 1.51 $ + * $Date: 1996/06/19 23:13:29 $ + * $Locker: $ + * + * + */ + +#include "veneer.h" +#include "vrtree.h" + +extern CHAR *VeneerVersion(); + +/* + * This table contains some rudimentary plug-n-play-style mappings + * to assist in assigning the proper Identifiers to device nodes. + */ +static struct pnp_info { + unsigned int port; + char *id; +} pnp_data[] = { + { 0x278, "LPT3" }, + { 0x2bc, "LPT4" }, + { 0x2e8, "COM4" }, + { 0x2f8, "COM2" }, + { 0x378, "LPT2" }, + { 0x3bc, "LPT1" }, + { 0x3e8, "COM3" }, + { 0x3f8, "COM1" }, + { 0x000, "Tooch did this." } +}; + + +CONFIGURATION_NODE *RootNode; +STATIC CONFIGURATION_NODE *DisplayNode = 0; + +STATIC int convert_node(CONFIGURATION_NODE *); +STATIC CONFIGURATION_NODE *convert_controller(CONFIGURATION_NODE *); +STATIC CONFIGURATION_NODE *add_new_child( + CONFIGURATION_NODE *, char *, CONFIGURATION_CLASS, CONFIGURATION_TYPE); +STATIC int convert_name(CONFIGURATION_NODE *); +STATIC VOID convert_config(CONFIGURATION_NODE *); +STATIC VOID convert_cache(PCONFIGURATION_NODE); +STATIC int convert_PCI_device(PCONFIGURATION_NODE); +STATIC CONFIGURATION_NODE *convert_SCSI_device(PCONFIGURATION_NODE); +STATIC CONFIGURATION_NODE *convert_IDE_device(PCONFIGURATION_NODE); +STATIC VOID convert_system_node(PCONFIGURATION_NODE); +STATIC VOID update_display_node(PCONFIGURATION_NODE); +STATIC VOID configure_pci_node(reg *, PCONFIGURATION_NODE ); + +STATIC int default_interrupt_level = 0; +STATIC int level_equals_vector = FALSE; +STATIC int default_interrupt_affinity = -1; +STATIC int default_affinity = -1; +STATIC int init_key_array[64]; +STATIC int *key_array = init_key_array; + +/* + * Traverse the OF tree. For each node, figure out what it corresponds + * to in an ARC tree and construct the Component and resource + * description data structures. Call this initially with node = 0 + * so peer() finds the root node. See 6.3.2.2. + * + * At each node, build a CONFIGURATION_NODE and attempt to convert the + * node to an ARC component. If this conversion fails, free the + * CONFIGURATION_NODE and move on, continuing to pass "here." Otherwise + * move on, and pass "here" = "newlink." This way unconverted nodes + * are pruned out of the tree. + */ + +void +walk_obp( + phandle ph, + CONFIGURATION_NODE *here, + CONFIGURATION_NODE *parent, + CONFIGURATION_NODE *peer) +{ + phandle newph; + CONFIGURATION_NODE *newlink; + int *saved_key_array; + extern int level; // for debug output + + //VRASSERT((parent) || ((parent == 0) && (here == 0) && (peer == 0))); + debug(VRDBG_TREE, "\n"); + debug(VRDBG_TREE, "walk_obp: phandle 0x%x (%d)\n", ph, level); + debug(VRDBG_TREE, "walk_obp:\there 0x%x parent 0x%x peer 0x%x\n", + here, parent, peer); + + if (newph = OFChild(ph)) { + // + // Here we descend to a new level of the tree. Increment "level" + // so that debugging printouts reflect the level of the tree, + // and allocate a new "key_array" since counts reset at each + // level of the tree. See convert_node() for the use of + // key_array. + // + // + level++; + saved_key_array = key_array; + key_array = (int *) zalloc(64 * sizeof(int)); //"Enough" slots. + newlink = new(CONFIGURATION_NODE); + newlink->OfPhandle = newph; + debug(VRDBG_TREE, "walk_obp:\tNew Child node: 0x%x\n", newlink); + + // + // If there's already an ARC Node "HERE", then set the newlink's + // parent to point to the node "HERE". + // + if (here) { + newlink->Parent = here; + } else { + newlink->Parent = parent; + } + if (convert_node(newlink)) { + if (here) { + if (here->Child == 0) { + here->Child = newlink; + walk_obp(newph, newlink, here, 0); + } else { + CONFIGURATION_NODE *tmplink; + debug(VRDBG_TREE, "walk_obp: newlink = here->Child(0x%x)\n", + here->Child); + tmplink = here->Child; + while (tmplink->Peer) { + tmplink = tmplink->Peer; + } + + tmplink->Peer = newlink; + VRDBG(VRDBG_TREE, vr_dump_config_node(tmplink)); + walk_obp(newph, newlink, here, 0); + } + } else if (peer) { + newlink->Peer = peer->Peer; + peer->Peer = newlink; + walk_obp(newph, newlink, parent, newlink); + while (peer->Peer) { + peer = peer->Peer; + } + } else if (parent) { + newlink->Peer = parent->Child; + parent->Child = newlink; + walk_obp(newph, newlink, here, 0); + peer = newlink; + while (peer->Peer) { + peer = peer->Peer; + } + } + } else { + debug(VRDBG_TREE, "walk_obp: FREE CHILD NODE 0x%x\n", newlink); + free((char *)newlink); + if (here) { + walk_obp(newph, 0, here, 0); + } else { + walk_obp(newph, 0, parent, peer); + } + } + // + // Ascend: restore level and key_array. + // + level--; + key_array = saved_key_array; + } + + if (newph = OFPeer(ph)) { + newlink = new(CONFIGURATION_NODE); + debug(VRDBG_TREE, "walk_obp:\tnew Peer node: 0x%x\n", newlink); + if (ph == 0) { + RootNode = newlink; + } + newlink->OfPhandle = newph; + newlink->Parent = parent; + if (convert_node(newlink)) { + if (here) { + if (here->Peer == 0) { + here->Peer = newlink; + } else { + CONFIGURATION_NODE *tmplink; + debug(VRDBG_TREE, "walk_obp: newlink = here->Peer(0x%x)\n", + here->Peer); + tmplink = here->Peer; + while (tmplink->Peer) { + tmplink = tmplink->Peer; + } + tmplink->Peer = newlink; + VRDBG(VRDBG_TREE, vr_dump_config_node(tmplink)); + } + } else { + if (peer) { + newlink->Peer = peer->Peer; + peer->Peer = newlink; + } else { + if (parent) { + newlink->Peer = parent->Child; + parent->Child = newlink; + } + } + } + walk_obp(newph, newlink, parent, newlink); + } else { + debug(VRDBG_TREE, "walk_obp: FREE PEER NODE 0x%x\n", newlink); + free((char *)newlink); + if (here) { + walk_obp(newph, 0, parent, here); + } else { + walk_obp(newph, 0, parent, peer); + } + } + } + debug(VRDBG_TREE, "walk_obp =====================> exit(%d)\n",level); +} + +STATIC int +convert_node(CONFIGURATION_NODE *node) +{ + phandle ph = node->OfPhandle; + PCONFIGURATION_COMPONENT Component = &node->Component; + PCHAR arcid; + LONG key=-1; + + debug(VRDBG_TREE, "convert_node: node(0x%x) Begin ....\n", node); + node->ComponentName = get_str_prop(ph, "name", ALLOC); + if (node->ComponentName == 0) { + debug(VRDBG_TREE, "convert_node: NULL ComponentName. return FALSE\n"); + return FALSE; + } + if (convert_name(node) == 0) { + debug(VRDBG_TREE, "convert_node: convert_name returned 0...\n", node); + return FALSE; + } + Component->Revision = ARC_REVISION; + Component->Version = ARC_VERSION; + Component->AffinityMask = default_affinity; + + switch(Component->Class) { + case ProcessorClass: + break; + case CacheClass: + convert_cache(node); + break; + + case ControllerClass: + Component->Key = key_array[Component->Type]++; + if((node = convert_controller(node)) == 0 ) { + debug(VRDBG_TEST|VRDBG_TREE, + "Convert_node: failed convert_controller, return FALSE\n"); + return(FALSE); + } + convert_config(node); + break; + + default: + Component->Key = key_array[Component->Type]++; + convert_config(node); + break; + } + + if (arcid = get_str_prop(ph, "arc-identifier", ALLOC)) { + node->Component.Identifier = arcid; + node->Component.IdentifierLength = strlen(arcid) + 1; + } + + if ((key = get_int_prop(ph, "arc-key")) != -1) { + node->Component.Key = key; + } + debug(VRDBG_TREE|VRDBG_ENTRY, + "convert_node: ... returning true\n"); + return(TRUE); +} + +STATIC int +convert_name(CONFIGURATION_NODE *node) +{ + char *name = node->ComponentName; + char *type = get_str_prop(node->OfPhandle, "device_type", NOALLOC); + char **id = &node->Component.Identifier; + char *cp, *String=0; + int result = 1; + static int ncpus = 0; + + // + // The conversion is based upon device_type, or if that fails, + // name. As a first approximation the ARC node's Identifier, if + // converted, is set to the OFW node's name property. + // This is OK, as later in the process the "arc-identifier" + // property can override the Identifier set here. See above. + // + + debug(VRDBG_TREE, "convert_name: node(0x%x) is type %s \n", + node, TypeNames[node->Component.Type]); + *id = name; + if (cp = index(name, ',')) { + *cp = '-'; + } + + // + // If Parent == 0, we can assume this is the root node. + // + if (node->Parent == 0) { + node->Component.Class = SystemClass; + node->Component.Type = ArcSystem; + + // + // OFW, name is Company, Model + // + String = get_str_prop(node->OfPhandle, "name", ALLOC); + node->Component.Identifier = index(String, ','); + if (node->Component.Identifier == NULL) { + node->Component.Identifier = String; + } else { + node->Component.Identifier++; + } + + debug(VRDBG_TEST, "convert_name: node %x (%s)", node, name); + debug(VRDBG_TEST, "convert_name: OFW String (%s)\n", String); + debug(VRDBG_TEST, "convert_name: Identifier (%s)\n", + node->Component.Identifier); + goto found; + } + + if (type == 0) { + goto just_name; + } + + // + // First try to match on device-type. + // This is enough in many cases. + // + if (strcmp(type, "cpu") == 0) { + node->Component.Class = ProcessorClass; + node->Component.Type = CentralProcessor; + node->Component.Key = get_int_prop(node->OfPhandle, "reg"); + if (node->Component.Key == -1) { + node->Component.Key = ncpus++; + } + cp = index(name, '-') + 1; + *id = (char *) zalloc(13); + strcpy(*id, "PowerPC("); + strcat(*id, cp); + strcat(*id, ")"); + if (get_int_prop(node->OfPhandle, "i-cache-size")) { + convert_cache(add_new_child(node, + "cache", CacheClass, PrimaryIcache)); + } + + // + // The following block is to support old FirePower ROMs. + // If version 510 ROMs are ever desupported, this block + // can be deleted. + // + + if (strcmp( + get_str_prop(OFParent(node->OfPhandle), "name", NOALLOC), + "cpus") != 0) { + + // + // This is a 510 rom: it builds a single processor + // node even if it's an MP machine. We need to + // probe and report all CPUs ourselves. + // Since we know 501-rom-equipped machines have + // 1 or 2 processors, the job isn't that bad: + // we look at mailbox[1] and see if the contents + // are equal to "processor ready" (1). If so, + // we are dual-proc. + // + + PULONG mbox = (PULONG) 0x2f88; + CONFIGURATION_NODE *peer; + + if (*mbox == 1) { + peer = new(CONFIGURATION_NODE); + bcopy((PCHAR) node, (PCHAR) peer, sizeof(CONFIGURATION_NODE)); + node->Peer = peer; + peer->Component.Revision = ARC_REVISION; + peer->Component.Version = ARC_VERSION; + peer->Component.Key = ncpus++; + peer->Component.AffinityMask = 1 << peer->Component.Key; + peer->Child = 0; + peer->Component.IdentifierLength = + strlen(peer->Component.Identifier) + 1; + convert_cache(add_new_child(peer, + "cache", CacheClass, PrimaryIcache)); + } + } + + goto found; + + } else if (strcmp(type, "cache") == 0) { + // + // What does the cache architecture of the system + // look like? OF reports processor caches in the cpu node, + // so that case is handled above. This must be a discrete + // off-chip cache of some kind. Is it bound to a particular + // processor, or is it a system-wide cache, or what? + // + // PReP machines call for a "transparent" Level-2 cache. + // Currently, these should be reported to NT as children + // of the root node--thus this code. IT IS CRUCIAL that + // this routine return FALSE, because we want to explicitly + // build a child of the root node, and we do NOT want to + // allow a node to be built in our present location. + // + // XXX - This may need to be re-examined in a future release + // as system architectures develop. + // + + PCONFIGURATION_NODE newnode; + + newnode = add_new_child(RootNode, "cache", CacheClass, SecondaryCache); + newnode->OfPhandle = node->OfPhandle; + convert_cache(newnode); + debug(VRDBG_TREE,"convert_node: node %s (0x%x) has new parent: ROOT.\n", + newnode->ComponentName, newnode); + return (0); + + } else if (strcmp(type, "pci") == 0) { + node->Component.Class = AdapterClass; + node->Component.Type = MultiFunctionAdapter; + node->ComponentName = "multi"; + *id = "PCI"; + goto found; + + } else if (strcmp(type, "isa") == 0) { + node->Component.Class = AdapterClass; + node->Component.Type = MultiFunctionAdapter; + node->ComponentName = "multi"; + *id = "ISA"; + goto found; + + } else if (strncmp(type, "scsi", 4) == 0) { + node->Component.Class = AdapterClass; + node->Component.Type = ScsiAdapter; + node->ComponentName = "scsi"; + String = get_str_prop(node->OfPhandle, "model", NOALLOC); + debug(VRDBG_TEST, "String(name)is ...%s:", String); + *id = (char *) zalloc(16); + if(strcmp(String, "NCR,53C810") == 0) { + *id = "NCRC810"; + debug(VRDBG_TEST|VRDBG_SCSI, + "nodeID =......%s:\n", node->Component.Identifier); + goto found; + } + if(strcmp(String, "AMD 53C794") == 0) { + *id = "AMD53C974"; + debug(VRDBG_TEST|VRDBG_SCSI, + "nodeID =......%s:\n", node->Component.Identifier); + goto found; + } + if (strncmp(String, "ADPT,AIC-78",11) == 0) { + *id = "AIC78XX"; + debug(VRDBG_TEST|VRDBG_SCSI, + "nodeID =......%s:\n", node->Component.Identifier); + goto found; + } + + *id = "UNKNOWN SCSI"; + goto found; + + } else if (strcmp(type, "ide") == 0) { + + node->Component.Class = AdapterClass; + node->Component.Type = ScsiAdapter; + node->ComponentName = "scsi"; + node->Component.Flags.Input = 1; + node->Component.Flags.Output = 1; + *id = "IDE"; + goto found; + + // + // Don't change the names on controllers yet. They all + // get treated again in convert_controller() to build + // their child peripheral nodes, etc. Leave the current + // names intact so we can distinguish between e.g. + // hard disk and floppy. + // + } else + if (strcmp(type, "block") == 0) { + node->Component.Class = ControllerClass; + if (strcmp(name, "disk") == 0) { + node->Component.Type = DiskController; + } else + if (strcmp(name, "floppy") == 0) { + node->Component.Type = DiskController; + } else + if (strcmp(name, "cdrom") == 0) { + node->Component.Type = CdromController; + } else + if (strcmp(name, "worm") == 0) { + node->Component.Type = WormController; + } else { + node->Component.Type = OtherController; + } + goto found; + + } else if (strcmp(type, "byte") == 0) { + node->Component.Class = ControllerClass; + node->Component.Type = TapeController; + goto found; + + } else if (strcmp(type, "display") == 0) { + node->Component.Class = ControllerClass; + node->Component.Type = DisplayController; + String = get_str_prop(node->OfPhandle, "model", ALLOC); + if (String == NULL) { + String = get_str_prop(node->OfPhandle, "name", ALLOC); + } + if (strcmp(String,"FirePower,Powerized_Display" ) == 0) { + node->Component.Identifier = "Powerized Graphics"; + } else { + node->Component.Identifier = capitalize(String); + } + if (String == NULL) { + node->Component.Identifier = "VGA"; + } + + update_display_node(node); + + goto found; + + } else if (strcmp(type, "network") == 0) { + node->Component.Class = ControllerClass; + node->Component.Type = NetworkController; + + // + // The stuff that follows is legacy support. + // See the comments for "I8042PRT" below. + // + String = get_str_prop(node->OfPhandle, "name", NOALLOC); + debug(VRDBG_TEST, "NetWork String(name)is ...%s:", String); + *id = (char *) zalloc(16); + if(strcmp(String, "pci1011,2") == 0) { + *id = "DC21x4"; + goto found; + } + if(strcmp(String, "AMD,79c970") == 0) { + *id = "AMD79C970"; + goto found; + } + *id = "UNKNOWN NETWORK"; + goto found; + + } else if (strcmp(type, "serial") == 0) { + node->Component.Class = ControllerClass; + node->Component.Type = SerialController; + goto found; + + } else if (strcmp(type, "parallel") == 0) { + node->Component.Class = ControllerClass; + node->Component.Type = ParallelController; + goto found; + + // + // For both keyboard and mouse below, the Identifier really + // should come from an "arc-identifier" property. Alas, + // there are machines in the field with ROM versions that + // don't have the arc-identifier property, so this legacy + // code will have to stay here forever. + // + + } else if (strcmp(type, "keyboard") == 0) { + node->Component.Class = ControllerClass; + node->Component.Type = KeyboardController; + *id = get_str_prop(OFParent(node->OfPhandle), "name", ALLOC); + if (strcmp(*id, "8042") == 0) { + free(*id); + *id = "I8042PRT"; + } + goto found; + + } else if (strcmp(type, "mouse") == 0) { + node->Component.Class = ControllerClass; + node->Component.Type = PointerController; + *id = get_str_prop(OFParent(node->OfPhandle), "name", ALLOC); + if (strcmp(*id, "8042") == 0) { + free(*id); + *id = "I8042PRT"; + } + goto found; + } + +just_name: + + // + // Device-type wasn't enough. We'll try matching + // on name now. + // + if (strcmp(name, "audio") == 0) { + node->Component.Class = ControllerClass; + node->Component.Type = AudioController; + goto found; + + } else if (strcmp(name, "memory") == 0) { + node->Component.Class = MemoryClass; + node->Component.Type = SystemMemory; + // + // "memory" nodes have two properties of interest: + // a "reg" prop which describes actual installed memory, + // and an "available" prop which describes the memory + // that hasn't been allocated. We'll pick up the + // reg prop later, in convert_config(). + // + goto found; + + } else if (strcmp(node->Parent->Component.Identifier, "PCI") == 0) { + // + // This is presumably a PCI expansion card, but without + // an FCode expansion ROM. + // + if (convert_PCI_device(node) == 0) { + result = 0; + } + goto found; + + } else { + // + // Else what? + // + debug(VRDBG_TREE, "convert_name: node '%s' (0x%x) is unmatched!\n", + name, node); + return (0); + } +found: + // + // NOTE: the IdentifierLength *includes* the null terminator. + // + + if (*id) { + if (*id == name) { + char *newid = zalloc(strlen(*id) + 1); + strcpy(newid, *id); + *id = newid; + } + node->Component.IdentifierLength = + strlen(*id) + 1; + } + debug(VRDBG_TREE, + "convert_name: node %s (%x) type '%s' is Class %s Type %s ID: %s\n", + name, node, type ? type : "", + ClassNames[node->Component.Class], TypeNames[node->Component.Type], + node->Component.IdentifierLength ? node->Component.Identifier : ""); + return (result); +} + +STATIC CONFIGURATION_NODE * +convert_controller(CONFIGURATION_NODE *node) +{ + phandle ph = node->OfPhandle; + PCONFIGURATION_COMPONENT Component = &node->Component; + char *name = node->ComponentName; + + debug(VRDBG_TREE, "convert_controller: node(0x%x) is type %s \n", + node, TypeNames[node->Component.Type]); + if (OFChild(ph)) { + debug(VRDBG_TREE, "Controller node %x '%s' already has a child (%s)!\n", + Component, name,get_str_prop(OFChild(ph), "name", NOALLOC)); + VRDBG(VRDBG_TREE, vr_dump_config_node(node)); + return(0); + } + + switch (Component->Type) { + + case DiskController: + if (strcmp(name, "disk") == 0) { + (void) add_new_child(node, "rdisk", + PeripheralClass, DiskPeripheral); + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.Output = 1; + } else if (strcmp(name, "floppy") == 0) { + (void) add_new_child(node, "fdisk", + PeripheralClass, FloppyDiskPeripheral); + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.Output = 1; + node->Child->Component.Flags.Removable = 1; + } else + warn("What is this disk controller '%s'?\n", name); + Component->Flags.Input = 1; + Component->Flags.Output = 1; + break; + + case TapeController: + node->ComponentName = "tape"; + (void) add_new_child(node, "tape", + PeripheralClass, TapePeripheral); + Component->Flags.Input = 1; + Component->Flags.Output = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.Output = 1; + node->Child->Component.Flags.Removable = 1; + break; + + case CdromController: + node->ComponentName = "cdrom"; + (void) add_new_child(node, "fdisk", + PeripheralClass, FloppyDiskPeripheral); + Component->Flags.Input = 1; + Component->Flags.ReadOnly = 1; + Component->Flags.Removable = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.ReadOnly = 1; + node->Child->Component.Flags.Removable = 1; + break; + + case WormController: + node->ComponentName = "worm"; + (void) add_new_child(node, "rdisk", + PeripheralClass, DiskPeripheral); + Component->Flags.Input = 1; + Component->Flags.Output = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.Output = 1; + node->Child->Component.Flags.Removable = 1; + break; + + case SerialController: + node->ComponentName = "serial"; + (void) add_new_child(node, "line", + PeripheralClass, LinePeripheral); + Component->Flags.Input = 1; + Component->Flags.Output = 1; + Component->Flags.ConsoleIn = 1; + Component->Flags.ConsoleOut = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.Output = 1; + node->Child->Component.Flags.ConsoleIn = 1; + node->Child->Component.Flags.ConsoleOut = 1; + break; + + case NetworkController: + node->ComponentName = "net"; + (void) add_new_child(node, "network", + PeripheralClass, NetworkPeripheral); + Component->Flags.Input = 1; + Component->Flags.Output = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.Output = 1; + break; + + case DisplayController: + node->ComponentName = "video"; + (void) add_new_child(node, "monitor", + PeripheralClass, MonitorPeripheral); + Component->Flags.Output = 1; + Component->Flags.ConsoleOut = 1; + node->Child->Component.Identifier = "1024x768"; + node->Child->Component.IdentifierLength = 9; + node->Child->Component.Flags.Output = 1; + node->Child->Component.Flags.ConsoleOut = 1; + break; + + case ParallelController: + node->ComponentName = "par"; + (void) add_new_child(node, "print", + PeripheralClass, PrinterPeripheral); + Component->Flags.Input = 1; + Component->Flags.Output = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.Output = 1; + break; + + case PointerController: + node->ComponentName = "point"; + (void) add_new_child(node, "pointer", + PeripheralClass, PointerPeripheral); + Component->Flags.Input = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Identifier = MOUSE_IDENTIFIER; + node->Child->Component.IdentifierLength = + strlen(MOUSE_IDENTIFIER) + 1; + break; + + case KeyboardController: + node->ComponentName = "key"; + (void) add_new_child(node, "keyboard", + PeripheralClass, KeyboardPeripheral); + Component->Flags.Input = 1; + Component->Flags.ConsoleIn = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.ConsoleIn = 1; + node->Child->Component.Identifier = KBD_IDENTIFIER; + node->Child->Component.IdentifierLength = + strlen(KBD_IDENTIFIER) + 1; + break; + + case AudioController: + node->ComponentName = "other"; + (void) add_new_child(node, "other", + PeripheralClass, OtherPeripheral); + Component->Flags.Input = 1; + Component->Flags.Output = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.Output = 1; + break; + + case OtherController: + node->ComponentName = "other"; + (void) add_new_child(node, "other", + PeripheralClass, OtherPeripheral); + Component->Flags.Input = 1; + Component->Flags.Output = 1; + node->Child->Component.Flags.Input = 1; + node->Child->Component.Flags.Output = 1; + break; + + default: + warn("Unknown controller class %d type %d\n", + Component->Class, Component->Type); + break; + } + // + // NOTE: the IdentifierLength *includes* the null terminator. + // + if (node->Component.Identifier) { + node->Component.IdentifierLength = + strlen(node->Component.Identifier) + 1; + } + + debug(VRDBG_TREE, "convert_controller: node %x has parent %x of Type %s\n", + node, node->Parent, TypeNames[node->Parent->Component.Type]); + + // + // Finally, check to see if this is a child of a ScsiAdapter. + // If it is, we may have to probe the bus. + // + + if (node->Parent->Component.Type == ScsiAdapter) { + if (strcmp(node->Parent->Component.Identifier, "IDE") == 0) { + return (convert_IDE_device(node)); + } else { + return (convert_SCSI_device(node)); + } + } + + return (node); +} + +/* + * We found a leaf node. In classical OF this would be sufficient; i.e. + * this node would contain the methods to drive the device and the properties + * that describe the device. But in the ARC world, this node corresponds + * to a ControllerClass Component, which is expected to have a PeripheralClass + * Component that describes the actual device. + * In this function we take an existing "Controller" node and add a + * "Peripheral" node as a child. + */ +STATIC CONFIGURATION_NODE * +add_new_child( + CONFIGURATION_NODE *parent, + char *name, + CONFIGURATION_CLASS class, + CONFIGURATION_TYPE type + ) +{ + PCONFIGURATION_NODE child; + PCONFIGURATION_COMPONENT Component; + + debug(VRDBG_TREE, + "add_new_child: parent %s(0x%x) will get child %s Type %s\n", + parent->ComponentName, parent, name, TypeNames[type]); + child = new(CONFIGURATION_NODE); + child->Parent = parent; + debug(VRDBG_TREE, "add_new_child: add child (0x%x) to node 0x%x\n", + child, child->Parent); + if (parent->Child != NULL) { + PCONFIGURATION_NODE node = parent->Child; + while (node->Peer) { + node = node->Peer; + } + node->Peer = child; + } else { + parent->Child = child; + } + child->ComponentName = name; + child->OfPhandle = parent->OfPhandle; + Component = &child->Component; + Component->Class = class; + Component->Type = type; + Component->Revision = ARC_REVISION; + Component->Version = ARC_VERSION; + Component->AffinityMask = default_affinity; + Component->Key = key_array[Component->Type]++; + VRDBG(VRDBG_TREE, vr_dump_config_node(child)); + + return (child); +} + +/* + * A PCI device without an FCode ROM may yet have enough useful + * properties encoded in configuration space to make a reasonable + * guess about its device type, etc. + */ +STATIC int +convert_PCI_device(PCONFIGURATION_NODE node) +{ + phandle ph = node->OfPhandle; + int class_code, base_class, sub_class, prog_class; + + debug(VRDBG_TREE, "Converting PCI device '%s'\n", node->ComponentName); + class_code = get_int_prop(ph, "class-code"); + debug(VRDBG_TREE, "PCI node class = %x\n", class_code); + if (class_code == -1) { + /* Hopeless */ + return (0); + } + base_class = (class_code >> 16) & 0xff; + sub_class = (class_code >> 8) & 0xff; + prog_class = class_code & 0xff; + + switch (base_class) { + case 0: + node->Component.Class = ControllerClass; + if (sub_class == 1 && prog_class == 0) { + node->Component.Type = DisplayController; + update_display_node(node); + } else { + node->Component.Type = OtherController; + } + goto ok; + + case 1: + node->Component.Class = ControllerClass; + node->Component.Type = DiskController; + switch (sub_class) { + case 0: node->Component.Class = AdapterClass; + node->Component.Type = ScsiAdapter; + node->ComponentName = "scsi"; + (void) add_new_child(node, "disk", + ControllerClass, DiskController); + (void) add_new_child(node, "tape", + ControllerClass, TapeController); + break; + case 1: node->ComponentName = "multi"; // IDE, actually + break; + case 2: node->ComponentName = "floppy"; + break; + case 3: node->ComponentName = "ipi"; + break; + default: node->ComponentName = "other"; + break; + } + goto ok; + + case 2: + node->Component.Class = ControllerClass; + node->Component.Type = NetworkController; + goto ok; + + case 3: + node->Component.Class = ControllerClass; + +#ifdef rev1_30 + node->Component.Type = DisplayController; +#else + if (sub_class == 0 && prog_class == 0) { + node->Component.Type = DisplayController; + update_display_node(node); + } else { + node->Component.Type = OtherController; + } + +#endif + goto ok; + + case 4: + node->Component.Class = ControllerClass; + switch (sub_class) { + case 0: node->Component.Type = DisplayController; + goto ok; + case 1: node->Component.Type = AudioController; + goto ok; + } + break; + + case 5: + // + // What are we to do about memory cards? + // + break; + + case 6: + node->Component.Class = AdapterClass; + if (sub_class == 2) { + node->Component.Type = EisaAdapter; + node->ComponentName = "eisa"; + } else { + node->Component.Type = MultiFunctionAdapter; + node->ComponentName = "multi"; + } + goto ok; + + } + + // + // What is this thing? + // + node->Component.Class = ControllerClass; + node->Component.Type = OtherController; + node->ComponentName = "other"; +ok: + if( VrDebug & VRDBG_TREE ) { + DisplayConfig(&node->Component); + } + return (1); +} + +/* + * ScsiAdapter nodes have some special rules. The child controllers' Key + * values are the SCSI target ID, not the instance, and the child + * controllers' Identifiers are specified to be the concatenation of + * the vendor and product name fields as returned from INQUIRY. + * + * Worse news: SCSI devices may be wildcarded, so we've got to probe + * the whole bus here if we find a wildcard node. + * + * As an optimization, record the fact that we've probed the bus + * so we need probe only once. This eliminates duplicate probes as + * the firmware customarily reports both a disk and tape wildcard. + * The list of probed nodes is an array of "sufficient" size. + * Yes, I know. + */ + +STATIC CONFIGURATION_NODE * +convert_SCSI_device(PCONFIGURATION_NODE node) +{ + PCONFIGURATION_NODE newnode, parent=node->Parent; + CONFIGURATION_TYPE type = node->Component.Type, newtype; + phandle ph = node->OfPhandle; + phandle parentph = parent->OfPhandle; + static PCONFIGURATION_NODE done_list[32] = { 0 }; + reg *regp; + char *path; + int i; + ihandle ih; + UCHAR inq[] = { 0x12, 0, 0, 0, 0xff, 0 }; + ULONG res[2]; + UCHAR *inq_data; + static int lock = 0; + int max_scsi_target = 8, scsi_host_id = 7; + int tmp_scsi_host_id = -1; + + + + if (lock++) { + --lock; + return(0); + } + + debug(VRDBG_ENTRY|VRDBG_TREE|VRDBG_SCSI, + "convert_SCSI_device: node 0x%x Begin.....\n", node); + + if (OFGetproplen(ph, "reg") > 0) { + regp = get_reg_prop(ph, "reg", 0); + node->Component.Key = regp->hi; + node->Child->Component.Key = 0; + --lock; + return (node); + } + + debug(VRDBG_SCSI|VRDBG_TREE, + "convert_SCSI_device: wildcard node (0x%x) parent (0x%x)\n", + node, parent); + VRDBG(VRDBG_SCSI, vr_dump_config_node(node)); + + // + // Discard the existing node: it's a wildcard and does + // us no good. + // + debug(VRDBG_SCSI, "convert_SCSI_device: parent child is(0x%x)\n", + parent->Child); + if (parent->Child == node) { + parent->Child = node->Peer; + debug(VRDBG_SCSI, "convert_SCSI_device: reset parent->Child \n"); + VRDBG(VRDBG_SCSI, vr_dump_config_node(parent->Child)); + } + for (newnode = parent->Child; newnode; newnode = newnode->Peer) { + debug(VRDBG_SCSI, "convert_SCSI_device: new node (0x%x)\n",newnode); + if (newnode->Peer == node) { + newnode->Peer = node->Peer; + node->Peer = 0; + } + } + if (node->Child) { + free((char *) node->Child); + } + + // + // and finally, free the node... + // + free((char *) node); + + + // + // Have we already done this SCSI bus? + // + for (i = 0; i < 32; ++i) { + if (done_list[i] == 0) { + break; + } + if (done_list[i] == parent) { + debug(VRDBG_SCSI|VRDBG_TREE, + "already did node (0x%x)\n", parent); + --lock; + return (0); + } + } + if (i >= 32) { + fatal("Too many (>32) SCSI adapters!\n"); + } + done_list[i] = parent; + + if (get_bool_prop(parentph, "wide")) { + debug(VRDBG_TREE|VRDBG_SCSI, "SCSI controller is wide \n"); + + max_scsi_target = 16; + + tmp_scsi_host_id = get_int_prop(parentph, "scsi-initiator-id"); + + debug(VRDBG_SCSI, "SCSI_Initiator_Id = %x\n", tmp_scsi_host_id); + if ( (tmp_scsi_host_id >= 0) && (tmp_scsi_host_id < 16) ) { + scsi_host_id = tmp_scsi_host_id; + } + } + + // + // Build the parent adapter's path. + // + path = NodeToPath(parent); + ih = OFOpen(path); + + // + // Loop through possible targets, and record each one + // which responds. + // + for (i = 0; i < max_scsi_target; ++i) { + if (i == scsi_host_id) { + continue; // don't want to probe the scsi host! + } + + // + // This algorithm uses methods that are standard + // in the scsi node, but are not explicitly exported + // through the client interface--thus the "call-method." + // + OFCallMethod(0, 4, 0, "set-address", ih, i, 0); + OFCallMethod(2, 5, res, "short-data-command", ih, 6, inq, 0xff); + if (res[0] != 0) { + continue; + } + + // + // The command succeeded. + // + inq_data = (UCHAR *) res[1]; + if (inq_data[0] == 0x7f) { + continue; + } + + // + // What kind of device are we looking for? + // + debug(VRDBG_TREE|VRDBG_SCSI, + "convert_SCSI_device: Device Found @ id %d\n",i); + newtype = ScsiNodeType[inq_data[0]]; + debug(VRDBG_TREE|VRDBG_SCSI, + "convert_SCSI_device:\t\t '%s' of Type '%s'\n", + ScsiNodeName[inq_data[0]], TypeNames[newtype]); + // + // This target is for real. Add a new node to represent + // this device. Touch up the node as necessary + // for proper key, identifier, etc. + // + newnode = add_new_child(parent, ScsiNodeName[inq_data[0]], + ControllerClass, newtype); + + newnode->OfPhandle = ph; + newnode->Component.Key = i; + newnode->Component.Identifier = (char *)zalloc(29); + bcopy(&inq_data[8], newnode->Component.Identifier, 28); + newnode->Component.IdentifierLength = 29; + newnode->Wildcard = 1; + newnode->WildcardAddrPath = (char *) zalloc(6); + strcpy(newnode->WildcardAddrPath, "@X,0"); + + // + // Convert scsi id to hex string value... + // + if (i < 10) { + newnode->WildcardAddrPath[1] = '0' + i; + } else { + newnode->WildcardAddrPath[1] = 'a' + (i-10); + } + + if (!convert_controller(newnode)) { + debug(VRDBG_TEST|VRDBG_SCSI|VRDBG_TREE, + "Convert_SCSI_device: failed convert_controller\n"); + } + newnode->Child->Component.Key = 0; + newnode->Child->Wildcard = 1; + + } // end of for loop probing scsi bus + OFClose(ih); + free(path); + --lock; + return (0); // Zero because this was a wildcard node; don't convert. +} + +/* + * Like SCSI, devices may be wildcarded, so we've got to probe + * the whole bus here if we find a wildcard node. + */ +STATIC CONFIGURATION_NODE * +convert_IDE_device(PCONFIGURATION_NODE node) +{ + PCONFIGURATION_NODE newnode, parent=node->Parent; + CONFIGURATION_TYPE type = node->Component.Type, newtype; + phandle ph = node->OfPhandle; + static PCONFIGURATION_NODE done_list[32] = { 0 }; + reg *regp; + char *path; + int i; + ihandle ih; + ULONG res[3]; + static int lock = 0; + + if (lock++) { + --lock; + return(0); + } + debug(VRDBG_TREE, "convert_IDE_device: node 0x%x\n", node); + + if (OFGetproplen(ph, "reg") > 0) { + regp = get_reg_prop(ph, "reg", 0); + node->Component.Key = regp->hi; + node->Child->Component.Key = 0; + --lock; + return (node); + } + + debug(VRDBG_IDE, "convert_IDE_device: wildcard node (0x%x)\n", node); + VRDBG(VRDBG_IDE, vr_dump_config_node(node)); + + // + // Discard the existing node: it's a wildcard and does + // us no good. + // + + debug(VRDBG_IDE, "convert_IDE_device: parent child is(0x%x)\n", + parent->Child); + if (parent->Child == node) { + // + // remove this node from the parent's lineage... + // + parent->Child = node->Peer; + debug(VRDBG_IDE, "convert_IDE_device: reset parent->Child \n"); + VRDBG(VRDBG_IDE, vr_dump_config_node(parent->Child)); + } + + // + // Run the list of peers and see who points to this wild card node. + // Once the wildcard's sibling is located, remove the wildcard + // from the "peer" list. + // + for (newnode = parent->Child; newnode; newnode = newnode->Peer) { + debug(VRDBG_IDE, "convert_IDE_device: new node (0x%x)\n",newnode); + if (newnode->Peer == node) { + // + // Now, remove this node from its peer(s)'s line + // of siblings.... + // + newnode->Peer = node->Peer; + debug(VRDBG_IDE, "convert_IDE_device: reset newnode->Peer \n"); + VRDBG(VRDBG_IDE, vr_dump_config_node(newnode)); + node->Peer = 0; + } + } + + // + // make sure this node's children are freed up since + // the children of a wild card node are wild themselves. + // + if (node->Child) { + debug(VRDBG_IDE, "convert_IDE_device: free child(0x%x)\n", + node->Child); + free((char *) node->Child); + } + + // + // and finally, zero and free the node... + // + free((char *) node); + + // + // Have we already done this IDE bus? + // + for (i = 0; i < 32; ++i) { + if (done_list[i] == 0) { + break; + } + if (done_list[i] == parent) { + debug(VRDBG_IDE|VRDBG_TREE, + "already did node (0x%x)\n", parent); + --lock; + return (0); + } + } + + if (i >= 32){ + fatal("Too many (>32) IDE adapters!\n"); + } + done_list[i] = parent; + + // + // Build the parent adapter's path. + // + path = NodeToPath(parent); + ih = OFOpen(path); + // + // Loop through possible targets, and record each one + // which responds. + // + + for (i = 0; i < MAX_IDE_DEVICE; ++i) { + // + // This algorithm uses methods that are standard + // in the ide package, but are not explicitly exported + // through the client interface--thus the "call-method." + // + + OFCallMethod(3, 3, res, "ide-drive-inquiry", ih, i); + // + // The command succeeded. + // + + if (res[0] == 0) { + continue; + } + + debug(VRDBG_TREE, "convert_IDE_device: Device Found @ id %d\n",i); + newtype = ScsiNodeType[res[1]]; + debug(VRDBG_TREE, "convert_IDE_device:\t\t '%s' of Type '%s'\n", + ScsiNodeName[res[1]], TypeNames[newtype]); + + // + // What kind of device are we looking for? + // + newnode = add_new_child(parent, ScsiNodeName[res[1]], + ControllerClass, newtype); + newnode->OfPhandle = ph; + newnode->Component.Key = i; + newnode->Component.Identifier = "disk"; + newnode->Component.IdentifierLength = 5; + newnode->Wildcard = 1; + newnode->WildcardAddrPath = (char *) zalloc(6); + strcpy(newnode->WildcardAddrPath, "@X,0"); + newnode->WildcardAddrPath[1] = '0' + i; + + if (!convert_controller(newnode)) { + debug(VRDBG_TEST, + "Convert_IDE_device: failed convert_controller\n"); + } + newnode->Child->Component.Key = 0; + newnode->Child->Wildcard = 1; + + } + OFClose(ih); + free(path); + --lock; + return (0); // Zero because this was a wildcard node; don't convert. +} + +#define prl_t CM_PARTIAL_RESOURCE_LIST +#define prd_t CM_PARTIAL_RESOURCE_DESCRIPTOR + +STATIC prl_t * +grow_prl(PCONFIGURATION_NODE node, int dev_specific) +{ + prl_t *prl; + int datalen; + + if (node->ConfigurationData == (prl_t *) 0) { + node->ConfigurationData = + (PCM_PARTIAL_RESOURCE_LIST) + zalloc(sizeof(CM_PARTIAL_RESOURCE_LIST) + dev_specific); + prl = node->ConfigurationData; + prl->Version = 1; + prl->Revision = 2; + prl->Count = 0; + node->Component.ConfigurationDataLength = + sizeof(CM_PARTIAL_RESOURCE_LIST) + dev_specific; + return (prl); + } + datalen = node->Component.ConfigurationDataLength + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + dev_specific; + node->Component.ConfigurationDataLength = datalen; + prl = (prl_t *) zalloc(datalen); + datalen -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + dev_specific; + bcopy((char *) node->ConfigurationData, (char *) prl, datalen); + free((char *)node->ConfigurationData); + node->ConfigurationData = prl; + return(prl); +} + +/* + * This extremely ad hoc routine is called when converting a floppy + * controller, and builds the appropriate device-specific data struct + * in the floppy peripheral (which is a child of the controller node). + */ +STATIC VOID +convert_config_floppy(CONFIGURATION_NODE *node) +{ + PCM_FLOPPY_DEVICE_DATA fdd; + prl_t *prl; + prd_t *prd; + + debug(VRDBG_TREE, "Convert_config_floppy: node 0x%x\n", *node); + node->ComponentName = "disk"; + node->Component.Identifier = "I82077"; + node->Component.IdentifierLength = 7; + + node = node->Child; + // + // Add space for the floppy configuration data to the end of the + // configuration node: + // + prl = grow_prl(node, sizeof(CM_FLOPPY_DEVICE_DATA)); + + // + // set the partial resource descriptor pointer to the end of the + // configuration node before this new data area was added: + // + prd = &prl->PartialDescriptors[prl->Count]; + + // + // Tell the registry this data is device specific, and the resource + // is device exclusive. Basically, fill out a partial resource + // descriptor for the floppy: + // + prd->Type = CmResourceTypeDeviceSpecific; + prd->ShareDisposition = CmResourceShareDeviceExclusive; + prd->Flags = 0; + prd->u.DeviceSpecificData.DataSize = sizeof(CM_FLOPPY_DEVICE_DATA); + + // + // finally, increment the count to match the increase in the data + // added to the partial resource list + // + prl->Count += 1; + + // + // Device-specific data begins immediately after + // its descriptor. + // + fdd = (PCM_FLOPPY_DEVICE_DATA) + ((char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + // + // These need to be version 1.2, else all the extended fields + // like "HeadSettleTime" are assumed to be valid and must be + // filled in, presumably by a scientist. + // + fdd->Version = 1; + fdd->Revision = 2; + strcpy(fdd->Size, "3.5"); + fdd->MaxDensity = 1440; + /* All else is zero. */ +} + +/* + * This extremely ad hoc routine is called when converting a serial + * controller, and builds the appropriate device-specific data struct. + */ +STATIC VOID +convert_config_serial(CONFIGURATION_NODE *node) +{ + PCM_SERIAL_DEVICE_DATA serd; + prl_t *prl; + prd_t *prd; + + debug(VRDBG_TREE, "Convert_config_serial: node 0x%x\n", *node); + prl = grow_prl(node, sizeof(CM_SERIAL_DEVICE_DATA)); + prd = &prl->PartialDescriptors[prl->Count]; + prd->Type = CmResourceTypeDeviceSpecific; + prd->ShareDisposition = CmResourceShareDeviceExclusive; + prd->Flags = 0; + prd->u.DeviceSpecificData.DataSize = sizeof(CM_SERIAL_DEVICE_DATA); + prl->Count += 1; + + // + // Device-specific data begins immediately after + // its descriptor. + // + serd = (PCM_SERIAL_DEVICE_DATA) + ((char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + serd->Version = 1; + serd->Revision = 2; + if (VrDebug & SANDALFOOT) { + serd->BaudClock = 0x409980; + } else { + serd->BaudClock = 1843200; + } +} + +/* + * This extremely ad hoc routine is called when converting the system + * node, and builds the appropriate device-specific data struct. + */ +STATIC VOID +convert_system_node(CONFIGURATION_NODE *node) +{ + prl_t *prl; + prd_t *prd; + phandle ph; + PCHAR pData; + PCHAR pFirmwareVersion, pVeneerVersion; + PCHAR pVeneerVersionId = "Veneer"; + PCHAR pFirmwareVersionId = "Firmware"; +#ifdef BUILTBY + PCHAR pBuiltById = "Built By"; + PCHAR pBuiltBy; +#endif + CHAR **srcPairs[] = { + &pFirmwareVersionId, + &pFirmwareVersion, + &pVeneerVersionId, + &pVeneerVersion, +#ifdef BUILTBY + &pBuiltById, + &pBuiltBy, +#endif + NULL + }; + LONG dataSize; + LONG n; + + debug(VRDBG_TREE, "Convert_system_node: node 0x%x\n", *node); + + // + // The configuration data being built here will consist of + // multiple null terminated strings terminated by an empty + // string (ie. '\0'). The strings will consist of pairs + // of strings with the first string being the description + // of the second (paired) string. + // + // Example: + // + // "VeneerVersion" "FirmWorks,ENG,00.23,1995-04-27,14:42:21,GENERAL" + // + + // + // grab the firmware and veneer versions + // + + pVeneerVersion = VeneerVersion(); + ph = OFFinddevice("/openprom"); + pFirmwareVersion = get_str_prop(ph, "model", NOALLOC); + level_equals_vector = (OFGetproplen(ph,"arc-interrupt-level=vector") >= 0); + if (OFGetproplen(ph,"arc-interrupt-level") > 0) { + default_interrupt_level = get_int_prop(ph, "arc-interrupt-level"); + } + if (OFGetproplen(ph,"arc-interrupt-affinity") > 0) { + default_interrupt_affinity = get_int_prop(ph, "arc-interrupt-affinity"); + } + +#ifdef BUILTBY + // + // add the built by if defined + // + pBuiltBy = IQUOTE(BUILTBY); +#endif + + // + // the length of all strings + null terminaters + empty string + // + + dataSize = 0; + for (n = 0; srcPairs[n]; n++) { + dataSize += strlen(*srcPairs[n]) + 1; + } + dataSize += 2*sizeof(CHAR); // an empty string (2* just for good measure) + + prl = grow_prl(node, dataSize); + prd = &prl->PartialDescriptors[prl->Count]; + prd->Type = CmResourceTypeDeviceSpecific; + prd->ShareDisposition = CmResourceShareDeviceExclusive; + prd->Flags = 0; + prd->u.DeviceSpecificData.DataSize = dataSize; + prl->Count += 1; + debug(VRDBG_TEST, "Count is now...%x\n", prl->Count); + + // + // Device-specific data begins immediately after + // its descriptor. + // + + pData = (char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); + + { + // + // Now stuff the strings into the data buffer. + // + + PCHAR dst = pData; + PCHAR src; + + for (n = 0; srcPairs[n]; n++) { + src = *srcPairs[n]; + strcpy(dst, src); + dst += strlen(src)+1; + } + + *dst = '\0'; + } + + return; + +} + +// +// 8042 subtrees compliant with the HRP binding define a new address +// space for their children. Reg[0] in the child specifies the keyboard (0) +// or aux (1) port of the 8042. All 8042 child nodes--keyboard and +// mouse--are translated to ARC nodes--kbd and point--that have the same +// PORT information in the registry. The reg information in the device +// tree is suppressed, and the NT driver (i8042prt) sorts out who gets +// what port on the 8042. +// Although we shouldn't, we'll just "know" that an 8042 has two reg +// +STATIC VOID +convert_config_i8042(CONFIGURATION_NODE *node) +{ + phandle parent; + prl_t *prl; + prd_t *prd; + int i; + reg *regp; + + debug(VRDBG_TREE, "Convert_config_i8042: node 0x%x\n", *node); + parent = OFParent(node->OfPhandle); + for (i = 0; i < 2; ++i) { + regp = get_reg_prop(parent, "reg", i); + prl = grow_prl(node, 0); + prd = &prl->PartialDescriptors[prl->Count]; + prd->Type = CmResourceTypePort; + prd->Flags = CM_RESOURCE_PORT_IO; + prd->u.Port.Start.LowPart = regp->lo; + prd->u.Port.Start.HighPart = 0; + prd->u.Port.Length = regp->size; + prd->ShareDisposition = CmResourceShareDeviceExclusive; + prl->Count += 1; + } +} + +STATIC VOID +replace_isa_name(CONFIGURATION_NODE *node, int port) +{ + struct pnp_info *pnp; + + for (pnp = pnp_data; pnp->port != 0; ++pnp) { + if (pnp->port == (unsigned int) port) { + node->Component.Identifier = pnp->id; + node->Component.IdentifierLength = strlen(pnp->id) + 1; + break; + } + } +} + +STATIC VOID +convert_config(CONFIGURATION_NODE *node) +{ + phandle ph = node->OfPhandle; + prl_t *prl; + prd_t *prd=0; + reg *regp; + int prop; + + debug(VRDBG_TREE, "convert_config: node 0x%x, name %s identifier %s\n", + node, node->ComponentName, node->Component.Identifier); + // + // The "arc-config-data" property totally overrides the conversion + // process, providing a complete verbatim ARC configuration data + // structure. + // + if ((prop = OFGetproplen(ph, "arc-config-data")) >= 0) { + char *buf; + debug(VRDBG_ARCDATA, "convert_config: arc data override: 0x%x\n", node); + buf = zalloc(prop); + (VOID) OFGetprop(ph, "arc-config-data", buf, prop); + node->ConfigurationData = (PCM_PARTIAL_RESOURCE_LIST) buf; + node->Component.ConfigurationDataLength = prop; + + if (((prop = OFGetproplen(ph, "reg")) > 0) + && (strcmp(node->Parent->Component.Identifier, "ISA") == 0)) { + regp = get_reg_prop(ph, "reg", 0); + replace_isa_name(node, regp->lo); + } + return; + } + + if ((prop = OFGetproplen(ph, "reg")) > 0) { + if (strcmp(node->ComponentName, "memory") == 0) { + regp = get_reg_prop(ph, "reg", 0); + ADD_MEM_RESOURCE(regp, node); + } else { + if (strcmp(node->Parent->Component.Identifier, "PCI") == 0) { + regp = get_reg_prop(ph, "reg", 1); + configure_pci_node(regp, node); + } else { + if (strcmp(node->Component.Identifier, "I8042PRT") == 0) { + convert_config_i8042(node); + } else { + regp = get_reg_prop(ph, "reg", 0); + ADD_IO_RESOURCE(regp, node); + replace_isa_name(node, prd->u.Port.Start.LowPart); + } + } + } + } + + if ((prop = OFGetproplen(ph, "interrupts")) > 0) { + int level; + level = get_int_prop(ph, "interrupts"); + ADD_INT_RESOURCE(level, node); + // + // Now check for deviations from the "NORM" in the form of + // arc-... properties that this particular system uses to + // override standard tree values. + // + if ((prop = OFGetproplen(ph, "arc-interrupt-flags")) > 0) { + prop = get_int_prop(ph, "arc-interrupt-flags"); + prd->Flags = prop; + } + if ((prop = OFGetproplen(ph, "arc-interrupt-level")) > 0) { + prop = get_int_prop(ph, "arc-interrupt-level"); + prd->u.Interrupt.Level = prop; + } + + if ((prop = OFGetproplen(ph, "arc-interrupt-vector")) > 0) { + prop = get_int_prop(ph, "arc-interrupt-vector"); + prd->u.Interrupt.Vector = prop; + } + + if ((prop = OFGetproplen(ph, "arc-interrupt-affinity")) > 0) { + (int)(prd->u.Interrupt.Affinity) = + get_int_prop(ph, "arc-interrupt-affinity"); + } + + } + + if ((prop = OFGetproplen(ph, "dma")) > 0) { + prop = get_int_prop(ph, "dma"); + ADD_DMA_RESOURCE(prop, node); + if (prop != sizeof(int)) { + // + // Multiple cells are used to encode PNP data for + // AIX--just pick off the first cell. + // + char buf[sizeof(int)]; + OFGetprop(ph, "dma", buf, sizeof(int)); + prop = decode_int(buf); + prd->u.Dma.Channel = prop; + } + } + + if ((prop = OFGetproplen(ph, "arc-device-specific")) > 0) { + ADD_DEVICE_SPECIFIC_RESOURCE(prop, node); + } + + // + // Now check for special-case conversions. + // + + debug(VRDBG_TREE, "\tCheck special case, Name '%s'\n", + node->ComponentName); + + if (strcmp(node->ComponentName, "floppy") == 0) { + convert_config_floppy(node); + } + + if (strcmp(node->ComponentName, "serial") == 0) { + convert_config_serial(node); + } + +#ifdef SANDALFOOT_YET_LIVES + // + // Empirically, Sandalfoot systems have this stuff (register + // init constants?) in their ARC trees. Ergo, we put it + // in our ARC trees too. Note that this stuff doesn't look + // like a normal node. + // + if (strcmp(node->ComponentName, "video") == 0) { + PULONG up; + + node = node->Child; + prl = grow_prl(node, 0x1a); + prl->Version = 1; + prl->Revision = 0; + + up = (PULONG) &prl->Count; + *up++ = 0x3e800400; + *up++ = 0x03e807d0; + *up++ = 0x030005dc; + *up++ = 0x00010027; + *up++ = 0x01570001; + *up++ = 0x00000112; + + } +#endif + + if (node->Component.Type == ArcSystem) { + convert_system_node(node); + } +} + +STATIC VOID +convert_cache(CONFIGURATION_NODE *node) +{ + phandle ph = node->OfPhandle; + CONFIGURATION_NODE *newnode; + int block_size, cache_size; + + debug(VRDBG_TREE, "Convert_cache: node 0x%x\n", node); + if (get_bool_prop(ph, "cache-unified")) { + cache_size = get_int_prop(ph, "i-cache-size"); + if (cache_size == -1) { + fatal("Couldn't find 'i-cache-size': %s\n", node->ComponentName); + } + block_size = get_int_prop(ph, "i-cache-block-size"); + if (block_size == -1) { + block_size = 8; + } + + node->Component.Key = 0x01000000; + node->Component.Key |= log2(block_size) << 16; + node->Component.Key |= log2(cache_size >> PAGE_SHIFT); + + return; + } + + // + // Are we an I-cache? + // + if (get_int_prop(ph, "i-cache-size") != -1) { + cache_size = get_int_prop(ph, "i-cache-size"); + block_size = get_int_prop(ph, "i-cache-block-size"); + if (block_size == -1) { + fatal("Couldn't find 'i-cache-block-size': %s\n", + node->ComponentName); + } + + node->Component.Key = 0x01000000; + node->Component.Key |= log2(block_size) << 16; + node->Component.Key |= log2(cache_size >> PAGE_SHIFT); + + if (node->Parent->Component.Type == CentralProcessor) { + node->Component.Type = PrimaryIcache; + } else { + node->Component.Type = SecondaryIcache; + } + + if (get_int_prop(ph, "d-cache-size") == -1) { + return; + } + + // + // Uh-oh, there's a split cache here. + // + newnode = new(CONFIGURATION_NODE); + bcopy((char *) node, (char *) newnode, sizeof(CONFIGURATION_NODE)); + newnode->Child = 0; + node->Peer = newnode; + node = newnode; + } + + // + // Are we a D-cache? + // + if (get_int_prop(ph, "d-cache-size") != -1) { + cache_size = get_int_prop(ph, "d-cache-size"); + block_size = get_int_prop(ph, "d-cache-block-size"); + if (block_size == -1) { + fatal("Couldn't find 'd-cache-block-size': %s\n", + node->ComponentName); + } + + node->Component.Key = 0x01000000; + node->Component.Key |= log2(block_size) << 16; + node->Component.Key |= log2(cache_size >> PAGE_SHIFT); + + if (node->Parent->Component.Type == CentralProcessor) { + node->Component.Type = PrimaryDcache; + } else { + node->Component.Type = SecondaryDcache; + } + } +} + +STATIC VOID +update_display_node(PCONFIGURATION_NODE node) +{ + PCONFIGURATION_NODE n; + + if (DisplayNode == 0) { + DisplayNode = node; + return; + } + + if (DisplayNode->Child) { + free((char *) DisplayNode->Child); + } + + n = DisplayNode->Parent; + if (n->Child == DisplayNode) { + n->Child = DisplayNode->Peer; + } else { + for (n = n->Child; n && n->Peer != DisplayNode; n = n->Peer) { + ; + } + if (n) { + n->Peer = DisplayNode->Peer; + } + } + + free((char *) DisplayNode); + DisplayNode = node; +} + +STATIC VOID +configure_pci_node(reg *regp, PCONFIGURATION_NODE node) +{ + prl_t *prl; + prd_t *prd; + debug(VRDBG_TREE, "Convert_pci_node: node 0x%x\n", node); + if (regp != NULL) { + prl = grow_prl(node, 0); + prd = &prl->PartialDescriptors[prl->Count]; + prd->ShareDisposition = CmResourceShareDeviceExclusive; + + switch (regp->hi & 0x0f000000) { + case 0x01000000: + prd->Type = CmResourceTypePort; + prd->Flags = CM_RESOURCE_PORT_IO; + prd->u.Port.Start.LowPart = regp->lo; + prd->u.Port.Start.HighPart = 0; + break; + case 0x02000000: + case 0x03000000: + // + // XXX this is really quite bogus - we should probably + // look in the assigned-addresses property to find + // the actual assigned base address. However, we + // don't really know yet exactly what this property is + // supposed to contain for PCI devices. + // + + prd->Type = CmResourceTypeMemory; + prd->Flags = 0; + prd->u.Memory.Start.LowPart = regp->lo; + prd->u.Memory.Start.HighPart = 0; + // XXX do something for 64-bit memory space + break; + } + prd->u.Port.Length = regp->size; + prl->Count += 1; + } + +} + +/* + * Routine: vr_dump_config_node(PCONFIGURATION_NODE) + * + * Description: + * To dump the open firmware info for the given node. + */ + +VOID +vr_dump_config_node(PCONFIGURATION_NODE node) +{ + CONFIGURATION_CLASS class; + CONFIGURATION_TYPE type; + PCHAR name="XXX"; + + if (!node) { + warn("vr_dump_config_node: NODE is invalid: 0x%x\n",node); + return; + } + class = node->Component.Class; + type = node->Component.Type; + + if (class > MaximumClass ) { + warn("vr_dump_config: class value maxed out: previously 0x%x\n",class); + class = MaximumClass; + } + + if (type > MaximumType) { + warn("vr_dump_config: type value maxed out: previously 0x%x\n",type); + type = MaximumType; + } + + // + // Dump information to identify this node. + // + warn("\ndump_node:\tName\t%s\n", node->ComponentName); + warn("\t\tClass\t%s\t\t\tParent 0x%x\n", + ClassNames[class], node->Parent); + warn("\t\tType\t%s\t\t\t /\n", TypeNames[type]); + warn("\t\tKey\t%d\t\t\t Current 0x%x ----> Peer 0x%x\n", + node->Component.Key, node, node->Peer); + warn("\t\t\t\t\t\t/\n"); + warn("\t\t\t\t\tChild 0x%x\n\n",node->Child); + +} diff --git a/private/ntos/boot/veneer/vrtree.h b/private/ntos/boot/veneer/vrtree.h new file mode 100644 index 000000000..42015fa9d --- /dev/null +++ b/private/ntos/boot/veneer/vrtree.h @@ -0,0 +1,153 @@ + +/* + * + * Copyright (c) 1995,1996 FirePower Systems, Inc. + * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved. + * + * $RCSfile: vrtree.h $ + * $Revision: 1.3 $ + * $Date: 1996/06/15 23:21:16 $ + * $Locker: $ + * + */ + +#ifndef VRTREE_H +#define VRTREE_H + +#define ADD_MEM_RESOURCE(regp, node) { \ + prl = grow_prl(node, 0); \ + prd = &prl->PartialDescriptors[prl->Count]; \ + prd->Type = CmResourceTypeMemory; \ + prd->u.Memory.Start.LowPart = regp->lo; \ + prd->u.Memory.Start.HighPart = 0; \ + prd->u.Port.Length = regp->size; \ + prd->Flags = 0; \ + prd->ShareDisposition = CmResourceShareDeviceExclusive;\ + prl->Count += 1; \ + } + +#define ADD_IO_RESOURCE(regp, node) { \ + prl = grow_prl(node, 0); \ + prd = &prl->PartialDescriptors[prl->Count];\ + prd->ShareDisposition = CmResourceShareDeviceExclusive; \ + \ + prd->Type = CmResourceTypePort; \ + prd->Flags = CM_RESOURCE_PORT_IO; \ + prd->u.Port.Start.LowPart = regp->lo; \ + prd->u.Port.Start.HighPart = 0; \ + prd->u.Port.Length = regp->size; \ + prl->Count += 1; \ + } + + +#define ADD_INT_RESOURCE(level, node) { \ + prl = grow_prl(node, 0); \ + prd = &prl->PartialDescriptors[prl->Count]; \ + prd->u.Interrupt.Level = level; \ + prd->Type = CmResourceTypeInterrupt; \ + prd->ShareDisposition = CmResourceShareDeviceExclusive;\ + prd->Flags = CM_RESOURCE_INTERRUPT_LATCHED; \ + prd->u.Interrupt.Vector = \ + level_equals_vector ? \ + level : default_interrupt_level; \ + (int)(prd->u.Interrupt.Affinity) = default_interrupt_affinity;\ + prl->Count += 1; \ + } + +#define ADD_DMA_RESOURCE(prop, node) { \ + prl = grow_prl(node, 0); \ + prd = &prl->PartialDescriptors[prl->Count]; \ + prd->Type = CmResourceTypeDma; \ + prd->ShareDisposition = CmResourceShareDeviceExclusive; \ + prd->u.Dma.Channel = prop; \ + prl->Count += 1; \ + } + +#define ADD_DEVICE_SPECIFIC_RESOURCE(prop, node) { \ + char *buf;\ + prl = grow_prl(node, prop);\ + prd = &prl->PartialDescriptors[prl->Count];\ + prd->Type = CmResourceTypeDeviceSpecific;\ + prd->ShareDisposition = CmResourceShareDeviceExclusive;\ + prd->Flags = 0;\ + prd->u.DeviceSpecificData.DataSize = prop;\ + prl->Count += 1;\ + buf = ((char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));\ + (VOID) OFGetprop(ph, "arc-device-specific", buf, prop);\ + } + + +PCHAR TypeNames[]={ + "ArcSystem", + "CentralProcessor", + "FloatingPointProcessor", + "PrimaryIcache", + "PrimaryDcache", + "SecondaryIcache", + "SecondaryDcache", + "SecondaryCache", + "EisaAdapter", + "TcAdapter", + "ScsiAdapter", + "DtiAdapter", + "MultiFunctionAdapter", + "DiskController", + "TapeController", + "CdromController", + "WormController", + "SerialController", + "NetworkController", + "DisplayController", + "ParallelController", + "PointerController", + "KeyboardController", + "AudioController", + "OtherController", + "DiskPeripheral", + "FloppyDiskPeripheral", + "TapePeripheral", + "ModemPeripheral", + "MonitorPeripheral", + "PrinterPeripheral", + "PointerPeripheral", + "KeyboardPeripheral", + "TerminalPeripheral", + "OtherPeripheral", + "LinePeripheral", + "NetworkPeripheral", + "SystemMemory", + "MaximumType" +}; + +PCHAR ClassNames[]={ + "SystemClass", + "ProcessorClass", + "CacheClass", + "AdapterClass", + "ControllerClass", + "PeripheralClass", + "MemoryClass", + "MaximumClass", + "XX 8 XX", + "XX 9 XX" +}; + +PCHAR ScsiNodeName[] ={ + "disk", + "tape", + "nada", + "nada", + "worm", + "cdrom" +}; + + +CONFIGURATION_TYPE ScsiNodeType[] ={ + DiskController, + TapeController, + MaximumType, + MaximumType, + WormController, + CdromController +}; +#endif // VRTREE_H |